All Projects → alexanderwallin → React Player Controls

alexanderwallin / React Player Controls

Licence: isc
⏯ Dumb and (re)useful React components for media players.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to React Player Controls

Dlgplayer
A media player for iOS based on FFmpeg 4.0
Stars: ✭ 148 (-15.91%)
Mutual labels:  media-player
React Rough
🐇 React Components for Rough.js
Stars: ✭ 164 (-6.82%)
Mutual labels:  react-components
Cassette
📼 A flexible media player component library for React that requires no up-front config
Stars: ✭ 171 (-2.84%)
Mutual labels:  media-player
React Formik Ui
A simple component library, composed out of pure HTML form elements to make your live easier composing forms with Formik and React
Stars: ✭ 154 (-12.5%)
Mutual labels:  react-components
Materials
官方精品物料仓库
Stars: ✭ 159 (-9.66%)
Mutual labels:  react-components
Glow
mpv Config File Generator for Windows
Stars: ✭ 167 (-5.11%)
Mutual labels:  media-player
React Border Wrapper
A wrapper for placing elements along div borders.
Stars: ✭ 147 (-16.48%)
Mutual labels:  react-components
Video React
A web video player built for the HTML5 world using React library.
Stars: ✭ 2,227 (+1165.34%)
Mutual labels:  react-components
Primereact
The Most Complete React UI Component Library
Stars: ✭ 2,393 (+1259.66%)
Mutual labels:  react-components
Xbmc
Kodi is an award-winning free and open source home theater/media center software and entertainment hub for digital media. With its beautiful interface and powerful skinning engine, it's available for Android, BSD, Linux, macOS, iOS and Windows.
Stars: ✭ 13,175 (+7385.8%)
Mutual labels:  media-player
Styled Bootstrap
💅🏻 A styled-component implementation of Bootstrap
Stars: ✭ 154 (-12.5%)
Mutual labels:  react-components
React Spinners Kit
A collection of loading spinners with React.js
Stars: ✭ 158 (-10.23%)
Mutual labels:  react-components
Terra Core
Terra offers a set of configurable React components designed to help build scalable and modular application UIs. This UI library was created to solve real-world issues in projects we work on day to day.
Stars: ✭ 167 (-5.11%)
Mutual labels:  react-components
React Stylesheet
Component based styling for your React applications
Stars: ✭ 150 (-14.77%)
Mutual labels:  react-components
React Reveal
Easily add reveal on scroll animations to your React app
Stars: ✭ 2,282 (+1196.59%)
Mutual labels:  react-components
Fundamental React
React implementation of the reusable component library designed in Fundamental Library Styles
Stars: ✭ 148 (-15.91%)
Mutual labels:  react-components
Ej2 React Ui Components
Syncfusion React UI components library offer more than 50+ cross-browser, responsive, and lightweight react UI controls for building modern web applications.
Stars: ✭ 166 (-5.68%)
Mutual labels:  react-components
React Awesome Slider
React content transition slider. Awesome Slider is a 60fps, light weight, performant component that renders an animated set of production ready UI general purpose sliders with fullpage transition support for NextJS and GatsbyJS. 🖥️ 📱
Stars: ✭ 2,343 (+1231.25%)
Mutual labels:  react-components
React Native Performance Monitor
React Native Performance Monitor - Realtime graphing of React Native render performance
Stars: ✭ 174 (-1.14%)
Mutual labels:  react-components
Semantic Ui React
The official Semantic-UI-React integration
Stars: ✭ 12,561 (+7036.93%)
Mutual labels:  react-components


react-player-controls
 

npm version Build Status Dependencies Dev dependency status

This is a minimal set of modular and hopefully useful React components for composing media player interfaces. It is designed for you to compose media player controls yourself using a small and easy-to-learn API.

Instead of shipping default but customisable styles, there are implementation recipies to help you get going quickly. Also check out the demo site to try the components out.

⚠️ NOTE: This library does not deal with actual media in any way, only the UI. ⚠️

Table of contents

Installation

npm i react-player-controls

Usage

// ES2015+ import
import { Slider, Direction } from 'react-player-controls'

// Using CommonJS
const { Slider, Direction } = require('react-player-controls')

API

Direction

An enum describing a slider's active axis.

Key Value
HORIZONTAL "HORIZONTAL"
VERTICAL "VERTICAL"

<FormattedTime />

<FormattedTime /> translates a number of seconds into the player-friendly format of m:ss, or h:mm:ss if the total time is one hour or higher.

// This will render -1:01:02
<FormattedTime numSeconds={-3662} />
Prop name Default value Description
numSeconds 0 A number of seconds, positive or negative
className null A string to set as the HTML class attribute
style {} Styles to set on the wrapping span element.

<PlayerIcon />

<PlayerIcon /> is not really a component in itself, but a container of a number of icon components.

<PlayerIcon.Play />
<PlayerIcon.Pause />
<PlayerIcon.Previous />
<PlayerIcon.Next />
<PlayerIcon.SoundOn />
<PlayerIcon.SoundOff />

Any props passed to a <PlayerIcon.* /> component will be passed onto the underlying svg element.

<Slider />

The <Slider /> helps you build things like volume controls and progress bars. It does not take a value prop, but expects you to keep track of this yourself and render whatever you want inside it.

What this component actually does is that it renders an element inside itself, on top of its children, which listens to mouse events and invokes change and intent callbacks with relative, normalised values based on those events.

<Slider
  direction={Direction.HORIZONTAL}
  onIntent={intent => console.log(`hovered at ${intent}`)}
  onIntentStart={intent => console.log(`entered with mouse at ${intent}`)}
  onIntentEnd={() => console.log('left with mouse')}
  onChange={newValue => console.log(`clicked at ${newValue}`)}
  onChangeStart={startValue => console.log(`started dragging at ${startValue}`)}
  onChangeEnd={endValue => console.log(`stopped dragging at ${endValue}`)}
>
  {/* Here we render whatever we want. Nothings is rendered by default. */}
</Slider>
Prop name Default value Description
direction Direction.HORIZONTAL The slider's direction
onIntent (intent) => {} A function that is invoked with the relative, normalised value at which the user is hovering (when not dragging).
onIntentStart (intent) => {} A function this is invoked with the relative, normalised value at which the user started hovering the slider (when not dragging).
onIntentEnd () => {} A function this is invoked when the mouse left the slider area (when not dragging).
onChange (value) => {} A function that is invoked with the latest relative, normalised value that the user has set by either clicking or dragging.
onChangeStart (value) => {} A function that is invoked with the relative, normalised value at which the user started changing the slider's value.
onChangeEnd (value) => {} A function that is invoked with the relative, normalised value at which the user stopped changing the slider's value. When the component unmounts, this function will be invoked with a value of null.
children null Child elements.
className null A string to set as the HTML class attribute.
style {} Styles to set on the wrapping div element.
overlayZIndex 10 The z-index of the invisible overlay that captures mouse events

Recipies

Styled buttons with icons
import { PlayerIcon } from 'react-player-controls'

// A base component that has base styles applied to it
const PlayerButton = ({ style, children, ...props }) => (
  <button
    style={{
      appearance: 'none',
      outline: 'none',
      border: 'none',
      borderRadius: 3,
      background: 'white',
      color: 'blue',
      '&:hover': {
        'color': 'lightblue',
      },
      ...style,
    }}
    {...props}
  >
    {children}
  </button>
)

// Compose buttons with matching icons. Use whatever icon library
// you want. If you don't have any particular logic for each of the
// buttons, you might not need this abstraction.
const PlayButton = props => <button {...props}><PlayerIcon.Play /></button>
const PauseButton = props => <button {...props}><PlayerIcon.Pause /></button>
const PreviousButton = props => <button {...props}><PlayerIcon.Previous /></button>
const NextButton = props => <button {...props}><PlayerIcon.Next /></button>
Styled slider
import { Direction, Slider } from 'react-player-controls'

const WHITE_SMOKE = '#eee'
const GRAY = '#878c88'
const GREEN = '#72d687'

// A colored bar that will represent the current value
const SliderBar = ({ direction, value, style }) => (
  <div
    style={Object.assign({}, {
      position: 'absolute',
      background: GRAY,
      borderRadius: 4,
    }, direction === Direction.HORIZONTAL ? {
      top: 0,
      bottom: 0,
      left: 0,
      width: `${value * 100}%`,
    } : {
      right: 0,
      bottom: 0,
      left: 0,
      height: `${value * 100}%`,
    }, style)}
  />
)

// A handle to indicate the current value
const SliderHandle = ({ direction, value, style }) => (
  <div
    style={Object.assign({}, {
      position: 'absolute',
      width: 16,
      height: 16,
      background: GREEN,
      borderRadius: '100%',
      transform: 'scale(1)',
      transition: 'transform 0.2s',
      '&:hover': {
        transform: 'scale(1.3)',
      }
    }, direction === Direction.HORIZONTAL ? {
      top: 0,
      left: `${value * 100}%`,
      marginTop: -4,
      marginLeft: -8,
    } : {
      left: 0,
      bottom: `${value * 100}%`,
      marginBottom: -8,
      marginLeft: -4,
    }, style)}
  />
)

// A composite progress bar component
const ProgressBar = ({ isEnabled, direction, value, ...props }) => (
  <Slider
    direction={direction}
    onChange={/* store value somehow */}
    style={{
      width: direction === Direction.HORIZONTAL ? 200 : 8,
      height: direction === Direction.HORIZONTAL ? 8 : 130,
      borderRadius: 4,
      background: WHITE_SMOKE,
      transition: direction === Direction.HORIZONTAL ? 'width 0.1s' : 'height 0.1s',
      cursor: isEnabled === true ? 'pointer' : 'default',
    }}
    {...props}
  >
    <SliderBar direction={direction} value={value} style={{ background: isEnabled ? GREEN : GRAY }} />
    <SliderHandle direction={direction} value={value} style={{ background: isEnabled ? GREEN : GRAY }} />
  </Slider>
)

// Now use <ProgressBar /> somewhere
<ProgressBar
  isEnabled
  direction={Direction.HORIZONTAL}
  value={currentTime / currentSong.duration}
  onChange={value => seek(value * currentSong.duration)}
/>
Playback controls
import Icon from 'some-icon-library'

const PlaybackControls = ({
  isPlaying,
  onPlaybackChange,
  hasPrevious,
  onPrevious,
  hasNext,
  onNext,
}) => (
  <div>
    <button disabled={!hasPrevious} onClick={onPrevious}>
      <Icon.Previous />
    </button>

    <button onClick={() => onPlaybackChange(!isPlaying)}>
      {isPlaying ? <Icon.Pause /> : <Icon.Play />}
    </button>

    <button disabled={!hasNext} onClick={onNext}>
      <Icon.Next />
    </button>
  </div>
)

// Use PlaybackControls in a player context
<PlaybackControls
  isPlaying={player.isPlaying}
  onPlaybackChange={isPlaying => player.setIsPlaying(isPlaying)}
  hasPrevious={songs.indexOf(currentSong) > 0}
  hasNext={songs.indexOf(currentSong) < songs.length - 1}
  onPrevious={player.setSong(songs[songs.indexOf(currentSong) - 1])}
  onNext={player.setSong(songs[songs.indexOf(currentSong) + 1])}
/>
Progress bar with buffer
import { Direction, Slider } from 'react-player-controls'

const Bar = ({ style, children, ...props }) => (
  <div
    style={{
      height: 6,
      width: '100%',
      ...style,
    }}
  >
    {children}
  </div>
)

const ProgressBarWithBuffer = ({
  amountBuffered,
  ...props,
}) => (
  <Slider
    direction={Direction.HORIZONTAL}
    {...props}
  >
    {/* Background bar */}
    <Bar style={{ background: 'gray', width: '100%' }} />

    {/* Buffer bar */}
    <Bar style={{ background: 'silver', width: `${amountBuffered * 100}%` }} />

    {/* Playtime bar */}
    <Bar style={{ background: 'blue', width: `${100 * currentTime / duration}%` }} />
  </Slider>
)

// Use buffer bar somewhere
<ProgressBarWithBuffer
  amountBuffered={secondsBuffered / duration}
  {/* callback props etc */}
/>
Progress bar that shows the target time on hover
import { Direction, FormattedTime, Slider } from 'react-player-controls'

// Create a basic bar that represents time
const TimeBar = ({ children }) => (
  <div
    style={{
      height: 6,
      width: '100%',
      background: 'gray',
    }}
  >
    {children}
  </div>
)

// Create a tooltip that will show the time
const TimeTooltip = ({ numSeconds, style = {} }) => (
  <div
    style={{
      display: 'inline-block',
      position: 'absolute',
      bottom: '100%',
      transform: 'translateX(-50%)',
      padding: 8,
      borderRadius: 3,
      background: 'darkblue',
      color: 'white',
      fontSize: 12,
      fontWeight: 'bold',
      lineHeight: 16,
      textAlign: 'center',
      ...style,
    }}
  >
    <FormattedTime numSeconds={numSeconds} />
  </div>
)

// Create a component to keep track of user interactions
class BarWithTimeOnHover extends React.Component {
  static propTypes = {
    duration: PropTypes.number.isRequired,
  }

  constructor(props) {
    super(props)

    this.state = {
      // This will be a normalised value between 0 and 1,
      // or null when not hovered
      hoverValue: null,
    }

    this.handleIntent = this.handleIntent.bind(this)
    this.handleIntentEnd = this.handleIntentEnd.bind(this)
  }

  handleIntent(value) {
    this.setState({
      hoverValue: value,
    })
  }

  handleIntentEnd() {
    // Note that this might not be invoked if the user ends
    // a control change with the mouse outside of the slider
    // element, so you might want to do this inside a
    // onChangeEnd callback too.
    this.setState({
      hoverValue: null,
    })
  }

  render() {
    const { duration } = this.props
    const { hoverValue } = this.state

    return (
      <Slider
        direction={Direction.HORIZONTAL}
        style={{
          position: 'relative',
        }}
        onIntent={this.handleIntent}
        onIntentEnd={this.handleIntentEnd}
      >
        <TimeBar />

        {hoverValue !== null && (
          <TimeTooltip
            numSeconds={hoverValue * duration}
            style={{
              left: `${hoverValue * 100}%`,
            }}
          />
        )}
      </Slider>
    )
  }
}

// Let's use it somewhere
<BarWithTimeOnHover duration={video.duration} />
Base CSS styles (as seen on the docs page)
/* Root slider component */
.slider {
  position: relative;
}

.slider.is-horizontal {
  width: 200px;
  height: 8px;
}

.slider.is-vertical {
  width: 8px;
  height: 200px;
}

/* Bars – can be progress. value, buffer or whatever */
.bar {
  position: absolute;
  border-radius: 50%;
}

.bar.is-background {
  background: #878c88;
}

.bar.is-value {
  background: #72d687;
}

.bar.is-horizontal {
  top: 0;
  bottom: 0;
  left: 0;
  /* width: set dynamically in js */;
  height: 100%;
}

.bar.is-vertical {
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  /* height: set dynamically in js */;
}

/* Slider handle */
.handle {
  position: absolute;
  width: 16px;
  height: 16px;
  background: 'green';
  border-radius: 50%;
  transform: scale(1);
  transition: transform 0.2s;
}

.handle:hover {
  transform: scale(1.3);
}

.handle.is-horizontal {
  top: 0;
  /* left: set dynamically in js to x %; */
  margin-top: -4px;
  margin-left: -8px;
}

.handle.is-vertical {
  left: 0;
  /* bottom: set dynamically in js to x %; */
  margin-bottom: -8px;
  margin-left: -4px;
}

Contribute

Contributions are very welcome, no matter your experience! Please submit a PR and we'll take it from there.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].