@u-wave/react-youtube
Advanced tools
Comparing version 1.0.0-alpha.3 to 1.0.0-alpha.4
@@ -7,2 +7,7 @@ # @u-wave/react-youtube change log | ||
## 1.0.0-alpha.4 - 2022-05-03 | ||
* Add docs for the `useYouTube` hook. | ||
* Add props for `origin` / `host` settings. | ||
* Pass-through `muted` to the player initially, so `<YouTube autoplay muted />` works as expected. | ||
## 1.0.0-alpha.3 - 2022-05-01 | ||
@@ -9,0 +14,0 @@ * Fix unmount order. |
@@ -13,3 +13,3 @@ 'use strict'; | ||
/* global window, document */ | ||
/* global YT, document */ | ||
function loadSdk() { | ||
@@ -24,3 +24,3 @@ return new Promise((resolve, reject) => { | ||
script.onload = null; | ||
window.YT.ready(resolve); | ||
YT.ready(resolve); | ||
}; | ||
@@ -39,6 +39,8 @@ | ||
let sdk = null; | ||
/** @param {(sdk: typeof YT) => void} callback */ | ||
function getSdk(callback) { | ||
if (typeof window.YT === 'object' && typeof window.YT.ready === 'function') { | ||
if (typeof YT === 'object' && typeof YT.ready === 'function') { | ||
// A YouTube SDK is already loaded, so reuse that | ||
window.YT.ready(callback); | ||
YT.ready(callback); | ||
return; | ||
@@ -58,2 +60,9 @@ } | ||
} = React__default["default"]; | ||
const useLayoutEffect = typeof document !== 'undefined' ? React__default["default"].useLayoutEffect : useEffect; // Player state numbers are documented to be constants, so we can inline them. | ||
const ENDED = 0; | ||
const PLAYING = 1; | ||
const PAUSED = 2; | ||
const BUFFERING = 3; | ||
const CUED = 5; | ||
/** | ||
@@ -70,9 +79,11 @@ * Attach an event listener to a YouTube player. | ||
useEffect(() => { | ||
if (handler) { | ||
player === null || player === void 0 ? void 0 : player.addEventListener(event, handler); | ||
if (handler && player) { | ||
player.addEventListener(event, handler); | ||
} | ||
return () => { | ||
if (handler) { | ||
player === null || player === void 0 ? void 0 : player.removeEventListener(event, handler); | ||
// If the iframe was already deleted, removing event | ||
// listeners is unnecessary, and can actually cause a crash. | ||
if (handler && player && player.getIframe()) { | ||
player.removeEventListener(event, handler); | ||
} | ||
@@ -83,19 +94,13 @@ }; | ||
/** | ||
* @param {React.RefObject<HTMLElement>} container | ||
* @param {import('../index').YouTubeOptions} options | ||
* @return {YT.PlayerVars} | ||
*/ | ||
function useYouTube(container, _ref) { | ||
function getPlayerVars(_ref) { | ||
let { | ||
video, | ||
startSeconds, | ||
endSeconds, | ||
width, | ||
height, | ||
lang, | ||
paused, | ||
muted, | ||
volume, | ||
playbackRate, | ||
muted = false, | ||
autoplay = false, | ||
@@ -110,2 +115,39 @@ showCaptions = false, | ||
showRelatedVideos = true, | ||
origin = typeof window.location === 'object' ? window.location.origin : undefined | ||
} = _ref; | ||
return { | ||
autoplay: autoplay ? 1 : 0, | ||
cc_load_policy: showCaptions ? 1 : 0, | ||
controls: controls ? 1 : 0, | ||
disablekb: disableKeyboard ? 1 : 0, | ||
fs: allowFullscreen ? 1 : 0, | ||
hl: lang, | ||
iv_load_policy: annotations ? 1 : 3, | ||
start: startSeconds, | ||
end: endSeconds, | ||
modestbranding: modestBranding ? 1 : 0, | ||
playsinline: playsInline ? 1 : 0, | ||
rel: showRelatedVideos ? 1 : 0, | ||
mute: muted ? 1 : 0, | ||
origin | ||
}; | ||
} | ||
/** | ||
* @param {React.RefObject<HTMLElement>} container | ||
* @param {import('../index').YouTubeOptions} options | ||
*/ | ||
function useYouTube(container, options) { | ||
const { | ||
video, | ||
startSeconds, | ||
endSeconds, | ||
width, | ||
height, | ||
paused, | ||
muted, | ||
volume, | ||
playbackRate, | ||
autoplay = false, | ||
onReady, | ||
@@ -121,5 +163,5 @@ onError, | ||
onEnd = () => {} | ||
} = _ref; | ||
// Storing the player in the very first hook makes it easier to | ||
} = options; // Storing the player in the very first hook makes it easier to | ||
// find in React DevTools :) | ||
const [player, setPlayer] = useState( | ||
@@ -135,18 +177,2 @@ /** @type {YT.Player | null} */ | ||
if (!player) { | ||
/** @type {YT.PlayerVars} */ | ||
const playerVars = { | ||
autoplay: autoplay ? 1 : 0, | ||
cc_load_policy: showCaptions ? 1 : 0, | ||
controls: controls ? 1 : 0, | ||
disablekb: disableKeyboard ? 1 : 0, | ||
fs: allowFullscreen ? 1 : 0, | ||
hl: lang, | ||
iv_load_policy: annotations ? 1 : 3, | ||
start: startSeconds, | ||
end: endSeconds, | ||
modestbranding: modestBranding ? 1 : 0, | ||
playsinline: playsInline ? 1 : 0, | ||
rel: showRelatedVideos ? 1 : 0 | ||
}; | ||
createPlayer.current = () => new YT.Player(container.current, { | ||
@@ -156,3 +182,4 @@ videoId: video, | ||
height, | ||
playerVars, | ||
host: options.host, | ||
playerVars: getPlayerVars(options), | ||
events: { | ||
@@ -166,23 +193,44 @@ onReady: event => { | ||
useLayoutEffect(() => { | ||
/** @type {YT.Player|null} */ | ||
let instance = null; | ||
let cancelled = false; | ||
getSdk(() => { | ||
if (!cancelled) { | ||
instance = createPlayer.current(); | ||
} | ||
}); | ||
return () => { | ||
var _instance; | ||
cancelled = true; // Destroying the player here means that some other hooks cannot access its methods anymore, | ||
// so they do need to be careful in their unsubscribe effects. | ||
// There isn't really a way around this aside from manually implementing parts of the | ||
// `destroy()` method. | ||
// It's tempting to just remove the iframe here just in time for React to move in, | ||
// but we must use `.destroy()` to avoid memory leaks, since the YouTube SDK holds on | ||
// to references to player objects globally. | ||
(_instance = instance) === null || _instance === void 0 ? void 0 : _instance.destroy(); | ||
}; | ||
}, []); | ||
const handlePlayerStateChange = useCallback(event => { | ||
const State = YT.PlayerState; | ||
switch (event.data) { | ||
case State.CUED: | ||
case CUED: | ||
onCued(event); | ||
break; | ||
case State.BUFFERING: | ||
case BUFFERING: | ||
onBuffering(event); | ||
break; | ||
case State.PAUSED: | ||
case PAUSED: | ||
onPause(event); | ||
break; | ||
case State.PLAYING: | ||
case PLAYING: | ||
onPlaying(event); | ||
break; | ||
case State.ENDED: | ||
case ENDED: | ||
onEnd(event); | ||
@@ -259,23 +307,3 @@ break; | ||
} | ||
}, [player, video]); // The effect that manages the player's lifetime. | ||
// This must be done at the end to ensure that `.destroy()` runs last. | ||
// Else, other hooks will attempt to do things like `.removeEventListener()` | ||
// after the player is destroyed. | ||
useEffect(() => { | ||
/** @type {YT.Player|null} */ | ||
let instance = null; | ||
let cancelled = false; | ||
getSdk(() => { | ||
if (!cancelled) { | ||
instance = createPlayer.current(); | ||
} | ||
}); | ||
return () => { | ||
var _instance; | ||
cancelled = true; | ||
(_instance = instance) === null || _instance === void 0 ? void 0 : _instance.destroy(); | ||
}; | ||
}, []); | ||
}, [player, video]); | ||
return player; | ||
@@ -308,3 +336,3 @@ } | ||
/** | ||
* An 11-character string representing a YouTube video ID.. | ||
* An 11-character string representing a YouTube video ID. | ||
*/ | ||
@@ -324,3 +352,3 @@ video: PropTypes__default["default"].string, | ||
/** | ||
* Inline style for container element. | ||
* Inline style for the player element. | ||
*/ | ||
@@ -344,3 +372,4 @@ style: PropTypes__default["default"].object, | ||
paused: PropTypes__default["default"].bool, | ||
// eslint-disable-line react/no-unused-prop-types | ||
host: PropTypes__default["default"].string, | ||
origin: PropTypes__default["default"].string, | ||
// Player parameters | ||
@@ -347,0 +376,0 @@ |
@@ -19,2 +19,14 @@ /// <reference types="youtube" /> | ||
/** | ||
* YouTube host to use: 'https://www.youtube.com' or 'https://www.youtube-nocookie.com'. | ||
* | ||
* @default 'https://www.youtube.com' | ||
*/ | ||
host?: string; | ||
/** | ||
* The YouTube API will usually default this value correctly. It is exposed for completeness. | ||
*/ | ||
origin?: string; | ||
/** | ||
* Pause the video. | ||
@@ -30,2 +42,4 @@ */ | ||
* https://developers.google.com/youtube/player_parameters#autoplay | ||
* | ||
* @default false | ||
*/ | ||
@@ -37,2 +51,4 @@ autoplay?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#cc_load_policy | ||
* | ||
* @default false | ||
*/ | ||
@@ -44,2 +60,4 @@ showCaptions?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#controls | ||
* | ||
* @default true | ||
*/ | ||
@@ -51,2 +69,4 @@ controls?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#disablekb | ||
* | ||
* @default false | ||
*/ | ||
@@ -58,2 +78,4 @@ disableKeyboard?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#fs | ||
* | ||
* @default true | ||
*/ | ||
@@ -72,2 +94,4 @@ allowFullscreen?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#iv_load_policy | ||
* | ||
* @default true | ||
*/ | ||
@@ -91,2 +115,4 @@ annotations?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#modestbranding | ||
* | ||
* @default false | ||
*/ | ||
@@ -98,2 +124,4 @@ modestBranding?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#playsinline | ||
* | ||
* @default false | ||
*/ | ||
@@ -105,2 +133,4 @@ playsInline?: boolean; | ||
* https://developers.google.com/youtube/player_parameters#rel | ||
* | ||
* @default true | ||
*/ | ||
@@ -171,3 +201,3 @@ showRelatedVideos?: boolean; | ||
/** | ||
* Inline style for container element. | ||
* Inline style for player element. | ||
*/ | ||
@@ -178,2 +208,4 @@ style?: React.CSSProperties; | ||
export function useYouTube(container: React.Ref<HTMLElement>, options: YouTubeOptions): YT.Player | null; | ||
export default function YouTube(props: YouTubeProps): JSX.Element; | ||
declare const YouTube: React.FunctionComponent<YouTubeProps>; | ||
export default YouTube; |
{ | ||
"name": "@u-wave/react-youtube", | ||
"description": "YouTube player component for React.", | ||
"version": "1.0.0-alpha.3", | ||
"version": "1.0.0-alpha.4", | ||
"author": "Renée Kooi <renee@kooi.me>", | ||
@@ -31,3 +31,3 @@ "bugs": { | ||
"min-react-env": "^1.0.1", | ||
"mocha": "^9.0.0", | ||
"mocha": "^10.0.0", | ||
"prop-types-table": "^1.0.0", | ||
@@ -34,0 +34,0 @@ "proxyquire": "^2.1.3", |
# @u-wave/react-youtube | ||
YouTube player component for React. | ||
[Install][] - [Usage][] - [Demo][] - [Props][] | ||
[Install][] - [Usage][] - [Demo][] - [Component API][] - [Hook API][] | ||
@@ -23,11 +23,19 @@ ## Install | ||
## Props | ||
<a id="component"></a> | ||
## `<YouTube />` | ||
The `<YouTube />` component renders an iframe and attaches the YouTube player to it. It supports all the | ||
same options as the `useYouTube` hook, plus a few to configure the iframe. If you need to do more with | ||
the iframe than this component provides, consider using the `useYouTube` hook directly. | ||
### Props | ||
| Name | Type | Default | Description | | ||
|:-----|:-----|:-----|:-----| | ||
| video | string | | An 11-character string representing a YouTube video ID.. | | ||
| id | string | | DOM ID for the player element. | | ||
| className | string | | CSS className for the player element. | | ||
| style | object | | Inline style for container element. | | ||
| video | string | | An 11-character string representing a YouTube video ID.. | | ||
| width | number, string | | Width of the player element. | | ||
| height | number, string | | Height of the player element. | | ||
| host | string | https://www.youtube.com | YouTube host to use: 'https://www.youtube.com' or 'https://www.youtube-nocookie.com'. | | ||
| origin | string | | The YouTube API will usually default this value correctly. It is exposed for completeness.<br>https://developers.google.com/youtube/player_parameters#origin | | ||
| paused | bool | | Pause the video. | | ||
@@ -51,7 +59,7 @@ | autoplay | bool | false | Whether the video should start playing automatically.<br>https://developers.google.com/youtube/player_parameters#autoplay | | ||
| onError | function | | Sent when the player triggers an error. | | ||
| onCued | function | () => {} | Sent when the video is cued and ready to play. | | ||
| onBuffering | function | () => {} | Sent when the video is buffering. | | ||
| onPlaying | function | () => {} | Sent when playback has been started or resumed. | | ||
| onPause | function | () => {} | Sent when playback has been paused. | | ||
| onEnd | function | () => {} | Sent when playback has stopped. | | ||
| onCued | function | | Sent when the video is cued and ready to play. | | ||
| onBuffering | function | | Sent when the video is buffering. | | ||
| onPlaying | function | | Sent when playback has been started or resumed. | | ||
| onPause | function | | Sent when playback has been paused. | | ||
| onEnd | function | | Sent when playback has stopped. | | ||
| onStateChange | function | | | | ||
@@ -61,2 +69,57 @@ | onPlaybackRateChange | function | | | | ||
<a id="hook"></a> | ||
## `useYouTube(container, options)` | ||
Create a YouTube player at `container`. `container` must be a ref object. | ||
Returns the `YT.Player` object, or `null` until the player is ready. | ||
```js | ||
import { useYouTube } from '@u-wave/react-youtube'; | ||
function Player() { | ||
const container = useRef(null); | ||
const player = useYouTube(container, { | ||
video: 'x2to0hs', | ||
autoplay: true, | ||
}); | ||
console.log(player?.getVideoUrl()); | ||
return <div ref={container} />; | ||
} | ||
``` | ||
### Options | ||
| Name | Type | Default | Description | | ||
|:-----|:-----|:-----|:-----| | ||
| video | string | | An 11-character string representing a YouTube video ID.. | | ||
| width | number, string | | Width of the player element. | | ||
| height | number, string | | Height of the player element. | | ||
| host | string | https://www.youtube.com | YouTube host to use: 'https://www.youtube.com' or 'https://www.youtube-nocookie.com'. | | ||
| origin | string | | The YouTube API will usually default this value correctly. It is exposed for completeness.<br>https://developers.google.com/youtube/player_parameters#origin | | ||
| paused | bool | | Pause the video. | | ||
| autoplay | bool | false | Whether the video should start playing automatically.<br>https://developers.google.com/youtube/player_parameters#autoplay | | ||
| showCaptions | bool | false | Whether to show captions below the video.<br>https://developers.google.com/youtube/player_parameters#cc_load_policy | | ||
| controls | bool | true | Whether to show video controls.<br>https://developers.google.com/youtube/player_parameters#controls | | ||
| disableKeyboard | bool | false | Ignore keyboard controls.<br>https://developers.google.com/youtube/player_parameters#disablekb | | ||
| allowFullscreen | bool | true | Whether to display the fullscreen button.<br>https://developers.google.com/youtube/player_parameters#fs | | ||
| lang | string | | The player's interface language. The parameter value is an ISO 639-1 two-letter language code or a fully specified locale.<br>https://developers.google.com/youtube/player_parameters#hl | | ||
| annotations | bool | true | Whether to show annotations on top of the video.<br>https://developers.google.com/youtube/player_parameters#iv_load_policy | | ||
| startSeconds | number | | Time in seconds at which to start playing the video.<br>https://developers.google.com/youtube/player_parameters#start | | ||
| endSeconds | number | | Time in seconds at which to stop playing the video.<br>https://developers.google.com/youtube/player_parameters#end | | ||
| modestBranding | bool | false | Remove most YouTube logos from the player.<br>https://developers.google.com/youtube/player_parameters#modestbranding | | ||
| playsInline | bool | false | Whether to play the video inline on iOS, instead of fullscreen.<br>https://developers.google.com/youtube/player_parameters#playsinline | | ||
| showRelatedVideos | bool | true | Whether to show related videos after the video is over.<br>https://developers.google.com/youtube/player_parameters#rel | | ||
| volume | number | | The playback volume, **as a number between 0 and 1**. | | ||
| muted | bool | | Whether the video's sound should be muted. | | ||
| playbackRate | number | | Playback speed.<br>https://developers.google.com/youtube/iframe_api_reference#setPlaybackRate | | ||
| onReady | function | | Sent when the YouTube player API has loaded. | | ||
| onError | function | | Sent when the player triggers an error. | | ||
| onCued | function | | Sent when the video is cued and ready to play. | | ||
| onBuffering | function | | Sent when the video is buffering. | | ||
| onPlaying | function | | Sent when playback has been started or resumed. | | ||
| onPause | function | | Sent when playback has been paused. | | ||
| onEnd | function | | Sent when playback has stopped. | | ||
| onStateChange | function | | | | ||
| onPlaybackRateChange | function | | | | ||
| onPlaybackQualityChange | function | | | | ||
## Related | ||
@@ -72,3 +135,4 @@ - [react-dailymotion][] - A Dailymotion component with a similar declarative API. | ||
[Usage]: #usage | ||
[Props]: #props | ||
[Component API]: #component | ||
[Hook API]: #hook | ||
[Demo]: https://u-wave.net/react-youtube | ||
@@ -75,0 +139,0 @@ [Demo source code]: ./example |
173
src/index.js
// @ts-check | ||
/* global YT */ | ||
/* global YT, window */ | ||
import React from 'react'; | ||
@@ -13,3 +13,11 @@ import PropTypes from 'prop-types'; | ||
} = React; | ||
const useLayoutEffect = typeof document !== 'undefined' ? React.useLayoutEffect : useEffect; | ||
// Player state numbers are documented to be constants, so we can inline them. | ||
const ENDED = 0; | ||
const PLAYING = 1; | ||
const PAUSED = 2; | ||
const BUFFERING = 3; | ||
const CUED = 5; | ||
/** | ||
@@ -25,8 +33,10 @@ * Attach an event listener to a YouTube player. | ||
useEffect(() => { | ||
if (handler) { | ||
player?.addEventListener(event, handler); | ||
if (handler && player) { | ||
player.addEventListener(event, handler); | ||
} | ||
return () => { | ||
if (handler) { | ||
player?.removeEventListener(event, handler); | ||
// If the iframe was already deleted, removing event | ||
// listeners is unnecessary, and can actually cause a crash. | ||
if (handler && player && player.getIframe()) { | ||
player.removeEventListener(event, handler); | ||
} | ||
@@ -38,16 +48,10 @@ }; | ||
/** | ||
* @param {React.RefObject<HTMLElement>} container | ||
* @param {import('../index').YouTubeOptions} options | ||
* @return {YT.PlayerVars} | ||
*/ | ||
function useYouTube(container, { | ||
video, | ||
function getPlayerVars({ | ||
startSeconds, | ||
endSeconds, | ||
width, | ||
height, | ||
lang, | ||
paused, | ||
muted, | ||
volume, | ||
playbackRate, | ||
muted = false, | ||
autoplay = false, | ||
@@ -62,13 +66,50 @@ showCaptions = false, | ||
showRelatedVideos = true, | ||
onReady, | ||
onError, | ||
onStateChange, | ||
onPlaybackQualityChange, | ||
onPlaybackRateChange, | ||
onCued = () => {}, | ||
onBuffering = () => {}, | ||
onPlaying = () => {}, | ||
onPause = () => {}, | ||
onEnd = () => {}, | ||
origin = typeof window.location === 'object' ? window.location.origin : undefined, | ||
}) { | ||
return { | ||
autoplay: autoplay ? 1 : 0, | ||
cc_load_policy: showCaptions ? 1 : 0, | ||
controls: controls ? 1 : 0, | ||
disablekb: disableKeyboard ? 1 : 0, | ||
fs: allowFullscreen ? 1 : 0, | ||
hl: lang, | ||
iv_load_policy: annotations ? 1 : 3, | ||
start: startSeconds, | ||
end: endSeconds, | ||
modestbranding: modestBranding ? 1 : 0, | ||
playsinline: playsInline ? 1 : 0, | ||
rel: showRelatedVideos ? 1 : 0, | ||
mute: muted ? 1 : 0, | ||
origin, | ||
}; | ||
} | ||
/** | ||
* @param {React.RefObject<HTMLElement>} container | ||
* @param {import('../index').YouTubeOptions} options | ||
*/ | ||
function useYouTube(container, options) { | ||
const { | ||
video, | ||
startSeconds, | ||
endSeconds, | ||
width, | ||
height, | ||
paused, | ||
muted, | ||
volume, | ||
playbackRate, | ||
autoplay = false, | ||
onReady, | ||
onError, | ||
onStateChange, | ||
onPlaybackQualityChange, | ||
onPlaybackRateChange, | ||
onCued = () => {}, | ||
onBuffering = () => {}, | ||
onPlaying = () => {}, | ||
onPause = () => {}, | ||
onEnd = () => {}, | ||
} = options; | ||
// Storing the player in the very first hook makes it easier to | ||
@@ -84,18 +125,2 @@ // find in React DevTools :) | ||
if (!player) { | ||
/** @type {YT.PlayerVars} */ | ||
const playerVars = { | ||
autoplay: autoplay ? 1 : 0, | ||
cc_load_policy: showCaptions ? 1 : 0, | ||
controls: controls ? 1 : 0, | ||
disablekb: disableKeyboard ? 1 : 0, | ||
fs: allowFullscreen ? 1 : 0, | ||
hl: lang, | ||
iv_load_policy: annotations ? 1 : 3, | ||
start: startSeconds, | ||
end: endSeconds, | ||
modestbranding: modestBranding ? 1 : 0, | ||
playsinline: playsInline ? 1 : 0, | ||
rel: showRelatedVideos ? 1 : 0, | ||
}; | ||
createPlayer.current = () => new YT.Player(container.current, { | ||
@@ -105,3 +130,4 @@ videoId: video, | ||
height, | ||
playerVars, | ||
host: options.host, | ||
playerVars: getPlayerVars(options), | ||
events: { | ||
@@ -115,18 +141,41 @@ onReady: (event) => { | ||
useLayoutEffect(() => { | ||
/** @type {YT.Player|null} */ | ||
let instance = null; | ||
let cancelled = false; | ||
loadSdk(() => { | ||
if (!cancelled) { | ||
instance = createPlayer.current(); | ||
} | ||
}); | ||
return () => { | ||
cancelled = true; | ||
// Destroying the player here means that some other hooks cannot access its methods anymore, | ||
// so they do need to be careful in their unsubscribe effects. | ||
// There isn't really a way around this aside from manually implementing parts of the | ||
// `destroy()` method. | ||
// It's tempting to just remove the iframe here just in time for React to move in, | ||
// but we must use `.destroy()` to avoid memory leaks, since the YouTube SDK holds on | ||
// to references to player objects globally. | ||
instance?.destroy(); | ||
}; | ||
}, []); | ||
const handlePlayerStateChange = useCallback((event) => { | ||
const State = YT.PlayerState; | ||
switch (event.data) { | ||
case State.CUED: | ||
case CUED: | ||
onCued(event); | ||
break; | ||
case State.BUFFERING: | ||
case BUFFERING: | ||
onBuffering(event); | ||
break; | ||
case State.PAUSED: | ||
case PAUSED: | ||
onPause(event); | ||
break; | ||
case State.PLAYING: | ||
case PLAYING: | ||
onPlaying(event); | ||
break; | ||
case State.ENDED: | ||
case ENDED: | ||
onEnd(event); | ||
@@ -207,23 +256,2 @@ break; | ||
// The effect that manages the player's lifetime. | ||
// This must be done at the end to ensure that `.destroy()` runs last. | ||
// Else, other hooks will attempt to do things like `.removeEventListener()` | ||
// after the player is destroyed. | ||
useEffect(() => { | ||
/** @type {YT.Player|null} */ | ||
let instance = null; | ||
let cancelled = false; | ||
loadSdk(() => { | ||
if (!cancelled) { | ||
instance = createPlayer.current(); | ||
} | ||
}); | ||
return () => { | ||
cancelled = true; | ||
instance?.destroy(); | ||
}; | ||
}, []); | ||
return player; | ||
@@ -256,3 +284,3 @@ } | ||
/** | ||
* An 11-character string representing a YouTube video ID.. | ||
* An 11-character string representing a YouTube video ID. | ||
*/ | ||
@@ -269,3 +297,3 @@ video: PropTypes.string, | ||
/** | ||
* Inline style for container element. | ||
* Inline style for the player element. | ||
*/ | ||
@@ -291,4 +319,7 @@ style: PropTypes.object, // eslint-disable-line react/forbid-prop-types | ||
*/ | ||
paused: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types | ||
paused: PropTypes.bool, | ||
host: PropTypes.string, | ||
origin: PropTypes.string, | ||
// Player parameters | ||
@@ -295,0 +326,0 @@ |
@@ -1,2 +0,2 @@ | ||
/* global window, document */ | ||
/* global YT, document */ | ||
@@ -11,3 +11,3 @@ function loadSdk() { | ||
script.onload = null; | ||
window.YT.ready(resolve); | ||
YT.ready(resolve); | ||
}; | ||
@@ -25,6 +25,7 @@ script.onerror = () => { | ||
let sdk = null; | ||
/** @param {(sdk: typeof YT) => void} callback */ | ||
export default function getSdk(callback) { | ||
if (typeof window.YT === 'object' && typeof window.YT.ready === 'function') { | ||
if (typeof YT === 'object' && typeof YT.ready === 'function') { | ||
// A YouTube SDK is already loaded, so reuse that | ||
window.YT.ready(callback); | ||
YT.ready(callback); | ||
return; | ||
@@ -31,0 +32,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
118377
1856
140
25