Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use hooks, support React 18, drop React < 16 #196

Open
wants to merge 16 commits into
base: default
Choose a base branch
from
Open
Next Next commit
Rewrite it with hooks
goto-bus-stop committed Jun 30, 2024
commit 119068e7fe9b33e8ee494a323998661ecd7565e3
30 changes: 16 additions & 14 deletions .babelrc.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
const TEST = process.env.BABEL_ENV === 'test';
const CJS = process.env.BABEL_ENV === 'cjs';
'use strict';

module.exports = {
presets: [
['@babel/env', {
modules: TEST || CJS ? 'commonjs' : false,
loose: true,
targets: TEST ? { node: 'current' } : {},
}],
'@babel/react',
],
plugins: TEST ? [
'dynamic-import-node',
] : [],
module.exports = (api) => {
const isTest = api.caller((caller) => caller.name === '@babel/register');

return {
targets: isTest ? { node: 'current' } : {},
presets: [
['@babel/env', {
modules: isTest ? 'commonjs' : false,
}],
'@babel/react',
],
plugins: isTest ? [
'dynamic-import-node',
] : [],
};
};
30 changes: 30 additions & 0 deletions .browserslistrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
and_chr 92
and_chr 91
and_ff 90
and_ff 89
and_qq 10.4
and_uc 12.12
android 92
android 91
baidu 7.12
chrome 92
chrome 91
chrome 90
edge 92
edge 91
firefox 90
firefox 89
firefox 78
ios_saf 14.5-14.7
ios_saf 14.0-14.4
ios_saf 13.4-13.7
kaios 2.5
op_mini all
op_mob 77
op_mob 76
opera 77
opera 76
safari 14.1
safari 14
samsung 14.0
samsung 13.0
5 changes: 5 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -11,6 +11,11 @@ module.exports = {
'react/require-default-props': 'off',
// Our babel config doesn't support class properties
'react/state-in-constructor': 'off',
// I disagree
'react/function-component-definition': ['error', {
namedComponents: 'function-declaration',
unnamedComponents: 'arrow-function',
}],
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
'jsx-a11y/label-has-for': ['error', {
components: [],
6 changes: 3 additions & 3 deletions example/app.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global document */
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOM from 'react-dom/client';
import Vimeo from '@u-wave/react-vimeo'; // eslint-disable-line import/no-unresolved

const videos = [
@@ -113,5 +113,5 @@ class App extends React.Component {
}
}

// eslint-disable-next-line react/no-deprecated
ReactDOM.render(<App />, document.getElementById('example'));
const root = ReactDOM.createRoot(document.querySelector('#example'));
root.render(<App />);
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
"version": "0.0.0-example",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "esbuild --bundle app.js --loader:.js=jsx --sourcemap=inline --minify > bundle.js",
"build": "esbuild --bundle app.js --loader:.js=jsx --sourcemap=inline --minify-whitespace --minify-syntax > bundle.js",
"start": "serve ."
},
"dependencies": {
197 changes: 35 additions & 162 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,158 +1,16 @@
import * as React from 'react'
import Player, { Error } from '@vimeo/player'

export type PlayEvent = {
/**
* The length of the video in seconds.
*/
duration: number
/**
* The amount of the video, in seconds, that has played.
*/
seconds: number
/**
* The amount of the video that has played in comparison to the length of the video;
* multiply by 100 to obtain the percentage.
*/
percent: number
}

export type PlayingEvent = PlayEvent;

export type PauseEvent = {
/**
* The length of the video in seconds.
*/
duration: number
/**
* The amount of the video, in seconds, that has played to the pause position.
*/
seconds: number
/**
* The amount of the video that has played to the pause position in comparison to the length of the video; multiply by 100 to obtain the percentage.
*/
percent: number
}

export type EndEvent = PauseEvent

export type TimeUpdateEvent = {
/**
* The length of the video in seconds.
*/
duration: number
/**
* The amount of the video, in seconds, that has played from the current playback position.
*/
seconds: number
/**
* The amount of the video that has played from the current playback position in comparison to the length of the video; multiply by 100 to obtain the percentage.
*/
percent: number
}

export type ProgressEvent = {
/**
* The length of the video in seconds.
*/
duration: number
/**
* The amount of the video, in seconds, that has buffered.
*/
seconds: number
/**
* The amount of the video that has buffered in comparison to the length of the video;
* multiply by 100 to obtain the percentage.
*/
percent: number
}

export type SeekedEvent = {
/**
* The length of the video in seconds.
*/
duration: number
/**
* The amount of the video, in seconds, that has played from the new seek position.
*/
seconds: number
/**
* The amount of the video that has played from the new seek position in comparison to the length of the video; multiply by 100 to obtain the percentage.
*/
percent: number
}

export type TextTrackEvent = {
kind: 'captions' | 'subtitles'
label: string
language: string
}

export type Cue = {
html: string
text: string
}

export type CueChangeEvent = {
cues: Cue[]
kind: 'captions' | 'subtitles'
label: string
language: string
}
import Player,{
Error,
EventMap,
VimeoVideoQuality,
} from '@vimeo/player'

export type CuePointEvent = {
/**
* The location of the cue point in seconds.
*/
time: number
/**
* The ID of the cue point.
*/
id: string
/**
* The custom data from the `addCuePoint()` call, or an empty object.
*/
data: object
}

export type VolumeEvent = {
/**
* The new volume level.
*/
volume: number
}

export type PlaybackRateEvent = {
/**
* The new playback rate.
*/
playbackRate: number
}

export type LoadEvent = {
/**
* The ID of the new video.
*/
id: number
}

export interface VimeoProps {
export interface VimeoOptions {
/**
* A Vimeo video ID or URL.
*/
video: number | string
/**
* DOM ID for the player element.
*/
id?: string
/**
* CSS className for the player element.
*/
className?: string
/**
* Inline style for container element.
*/
style?: React.CSSProperties
/**
* Width of the player element.
*/
@@ -271,7 +129,7 @@ export interface VimeoProps {
* Vimeo Plus, PRO, and Business members can default
* an embedded video to a specific quality on desktop.
*/
quality?: string
quality?: VimeoVideoQuality

/**
* Turn captions/subtitles on for a specific language by default.
@@ -296,64 +154,79 @@ export interface VimeoProps {
/**
* Triggered when video playback is initiated.
*/
onPlay?: (event: PlayEvent) => void
onPlay?: (event: EventMap['play']) => void
/**
* Triggered when the video starts playing.
*/
onPlaying?: (event: PlayingEvent) => void
onPlaying?: (event: EventMap['playing']) => void
/**
* Triggered when the video pauses.
*/
onPause?: (event: PauseEvent) => void
onPause?: (event: EventMap['pause']) => void
/**
* Triggered any time the video playback reaches the end.
* Note: when `loop` is turned on, the ended event will not fire.
*/
onEnd?: (event: EndEvent) => void
onEnd?: (event: EventMap['ended']) => void
/**
* Triggered as the `currentTime` of the video updates. It generally fires
* every 250ms, but it may vary depending on the browser.
*/
onTimeUpdate?: (event: TimeUpdateEvent) => void
onTimeUpdate?: (event: EventMap['timeupdate']) => void
/**
* Triggered as the video is loaded. Reports back the amount of the video
* that has been buffered.
*/
onProgress?: (event: ProgressEvent) => void
onProgress?: (event: EventMap['progress']) => void
/**
* Triggered when the player seeks to a specific time. An `onTimeUpdate`
* event will also be fired at the same time.
*/
onSeeked?: (event: SeekedEvent) => void
onSeeked?: (event: EventMap['seeked']) => void
/**
* Triggered when the active text track (captions/subtitles) changes. The
* values will be `null` if text tracks are turned off.
*/
onTextTrackChange?: (event: TextTrackEvent) => void
onTextTrackChange?: (event: EventMap['texttrackchange']) => void
/**
* Triggered when the active cue for the current text track changes. It also
* fires when the active text track changes. There may be multiple cues
* active.
*/
onCueChange?: (event: CueChangeEvent) => void
onCueChange?: (event: EventMap['cuechange']) => void
/**
* Triggered when the current time hits a registered cue point.
*/
onCuePoint?: (event: CuePointEvent) => void
onCuePoint?: (event: EventMap['cuepoint']) => void
/**
* Triggered when the volume in the player changes. Some devices do not
* support setting the volume of the video independently from the system
* volume, so this event will never fire on those devices.
*/
onVolumeChange?: (event: VolumeEvent) => void
onVolumeChange?: (event: EventMap['volumechange']) => void
/**
* Triggered when the playback rate in the player changes.
*/
onPlaybackRateChange?: (event: PlaybackRateEvent) => void
onPlaybackRateChange?: (event: EventMap['playbackratechange']) => void
/**
* Triggered when a new video is loaded in the player.
*/
onLoaded?: (event: LoadEvent) => void
onLoaded?: (event: EventMap['loaded']) => void
}

export interface VimeoProps extends VimeoOptions {
/**
* DOM ID for the player element.
*/
id?: string
/**
* CSS className for the player element.
*/
className?: string
/**
* Inline style for container element.
*/
style?: React.CSSProperties
}

/**
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -2,8 +2,14 @@
"name": "@u-wave/react-vimeo",
"version": "0.9.11",
"description": "Vimeo player component for React.",
"main": "dist/react-vimeo.js",
"module": "dist/react-vimeo.es.js",
"main": "./dist/react-vimeo.js",
"module": "./dist/react-vimeo.mjs",
"exports": {
".": {
"require": "./dist/react-vimeo.js",
"import": "./dist/react-vimeo.mjs"
}
},
"types": "index.d.ts",
"scripts": {
"prepare": "npm run build",
16 changes: 0 additions & 16 deletions src/eventNames.js

This file was deleted.

438 changes: 265 additions & 173 deletions src/index.js

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -21,14 +21,13 @@ describe('Vimeo', () => {
expect(sdkMock.calls[0].arguments[1]).toMatch({ url: 'https://vimeo.com/179290396' });
});

it('should all onError when `ready()` fails', async () => {
it('should call onError when `ready()` fails', async () => {
const onError = createSpy();
const { sdkMock } = await render({
video: 404,
shouldFail: true,
onError,
});
await Promise.resolve();
expect(sdkMock).toHaveBeenCalled();
expect(sdkMock.calls[0].arguments[1]).toMatch({ id: 404 });
expect(onError).toHaveBeenCalled();
@@ -137,7 +136,7 @@ describe('Vimeo', () => {
});

expect(playerMock.setWidth).toHaveBeenCalledWith('100%');
expect(playerMock.setHeight).toHaveBeenCalledWith(800);
expect(playerMock.setHeight).toHaveBeenCalledWith('800');
});

it('should set the playback rate using the "playbackRate" props', async () => {
7 changes: 5 additions & 2 deletions test/util/createVimeo.js
Original file line number Diff line number Diff line change
@@ -50,8 +50,11 @@ export default function createVimeo({ shouldFail = false } = {}) {
});

const Vimeo = proxyquire.noCallThru().load('../../src/index.js', {
'@vimeo/player': function Player(...args) {
return sdkMock(...args);
'@vimeo/player': {
__esModule: true,
default: function Player(...args) {
return sdkMock(...args);
},
},
}).default;

27 changes: 16 additions & 11 deletions test/util/render.js
Original file line number Diff line number Diff line change
@@ -22,7 +22,11 @@ async function render(initialProps) {
shouldFail: initialProps.shouldFail,
});

let component;
let resolveReady;
const readyPromise = new Promise((resolve) => {
resolveReady = resolve;
});

// Emulate changes to component.props using a container component's state
class Container extends React.Component {
constructor(ytProps) {
@@ -31,14 +35,16 @@ async function render(initialProps) {
this.state = { props: ytProps };
}

componentDidMount() {
// Wait for the initial `setPlayer()` to be rendered.
setTimeout(() => resolveReady());
}

render() {
const { props } = this.state;

return (
<Vimeo
ref={(vimeo) => { component = vimeo; }}
{...props}
/>
<Vimeo {...props} />
);
}
}
@@ -60,26 +66,25 @@ async function render(initialProps) {
},
};
}

const container = await new Promise((resolve) => {
root.render(<Container {...initialProps} ref={resolve} />);
});
await readyPromise;

function rerender(newProps) {
return (act || noAct)(async () => {
container.setState({ props: newProps });
});
}

function unmount() {
root.unmount();
}

return {
sdkMock,
playerMock,
component,
rerender,
unmount,
unmount() {
root.unmount();
},
};
}