@hubspot/video-player-core 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +15 -0
- package/README.md +5 -0
- package/dist/api/utils.d.ts +3 -0
- package/dist/api/utils.d.ts.map +1 -0
- package/dist/api/utils.js +8 -0
- package/dist/api/video.d.ts +9 -0
- package/dist/api/video.d.ts.map +1 -0
- package/dist/api/video.js +22 -0
- package/dist/components/CaptionTracks.d.ts +7 -0
- package/dist/components/CaptionTracks.d.ts.map +1 -0
- package/dist/components/CaptionTracks.js +11 -0
- package/dist/components/HSPlayerIcons.d.ts +12 -0
- package/dist/components/HSPlayerIcons.d.ts.map +1 -0
- package/dist/components/HSPlayerIcons.js +14 -0
- package/dist/components/HSThemeTemplate.d.ts +23 -0
- package/dist/components/HSThemeTemplate.d.ts.map +1 -0
- package/dist/components/HSThemeTemplate.js +94 -0
- package/dist/components/TranslationsProvider.d.ts +13 -0
- package/dist/components/TranslationsProvider.d.ts.map +1 -0
- package/dist/components/TranslationsProvider.js +28 -0
- package/dist/components/VideoFetchProvider.d.ts +22 -0
- package/dist/components/VideoFetchProvider.d.ts.map +1 -0
- package/dist/components/VideoFetchProvider.js +12 -0
- package/dist/components/VideoPlayer.d.ts +13 -0
- package/dist/components/VideoPlayer.d.ts.map +1 -0
- package/dist/components/VideoPlayer.js +51 -0
- package/dist/components/VideoPlayerProvider.d.ts +40 -0
- package/dist/components/VideoPlayerProvider.d.ts.map +1 -0
- package/dist/components/VideoPlayerProvider.js +162 -0
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +8 -0
- package/dist/hooks/useAsyncEffect.d.ts +9 -0
- package/dist/hooks/useAsyncEffect.d.ts.map +1 -0
- package/dist/hooks/useAsyncEffect.js +54 -0
- package/dist/hooks/useSubtitles.d.ts +6 -0
- package/dist/hooks/useSubtitles.d.ts.map +1 -0
- package/dist/hooks/useSubtitles.js +17 -0
- package/dist/hooks/useVideo.d.ts +7 -0
- package/dist/hooks/useVideo.d.ts.map +1 -0
- package/dist/hooks/useVideo.js +17 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/styles/mux-player.css +23 -0
- package/dist/styles/player-theme.css +446 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/utils/i18n.d.ts +43 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +79 -0
- package/package.json +49 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Warranty disclaimer
|
|
2
|
+
|
|
3
|
+
THIS SOFTWARE IS PROVIDED “AS IS” AND “AS AVAILABLE”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
|
4
|
+
|
|
5
|
+
Limitation of liability
|
|
6
|
+
|
|
7
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
8
|
+
|
|
9
|
+
No support / no SLA
|
|
10
|
+
|
|
11
|
+
This package is provided as open source software. It is not part of any commercial product or service offering and is not subject to any service level agreement or support obligation.
|
|
12
|
+
|
|
13
|
+
No endorsement / no product integration
|
|
14
|
+
|
|
15
|
+
Use of this software does not imply endorsement, certification, or sponsorship by the author or the author’s employer.
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/api/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAOzC,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,MAAM,SAAQ,UAG/D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
function getApiDomain(env) {
|
|
2
|
+
const computedEnv = env || process.env.HS_ENV || 'prod';
|
|
3
|
+
return computedEnv === 'qa' ? 'hubspotqa.com' : 'hubspot.com';
|
|
4
|
+
}
|
|
5
|
+
export function getApiOrigin(env, hublet = 'na1') {
|
|
6
|
+
const apiSubdomainWithHublet = hublet === 'na1' ? 'api' : `api-${hublet}`;
|
|
7
|
+
return `https://${apiSubdomainWithHublet}.${getApiDomain(env)}`;
|
|
8
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { HsEnvironment, SubtitlesByLanguage, VideoResponse } from '../types';
|
|
2
|
+
export type FetchError = Error & {
|
|
3
|
+
status: number;
|
|
4
|
+
};
|
|
5
|
+
export declare function fetchVideo(videoId: number, portalId: number, env?: HsEnvironment, hublet?: string, skip?: boolean): Promise<VideoResponse | {
|
|
6
|
+
video: undefined;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function fetchSubtitles(videoId: number, portalId: number, env?: HsEnvironment, hublet?: string): Promise<SubtitlesByLanguage>;
|
|
9
|
+
//# sourceMappingURL=video.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/api/video.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG7E,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,aAAa,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,OAAO;;GAkBf;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,aAAa,EACnB,MAAM,CAAC,EAAE,MAAM,gCAahB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getApiOrigin } from './utils';
|
|
2
|
+
export async function fetchVideo(videoId, portalId, env, hublet, skip) {
|
|
3
|
+
if (skip) {
|
|
4
|
+
return { video: undefined };
|
|
5
|
+
}
|
|
6
|
+
const response = await fetch(`${getApiOrigin(env, hublet)}/video/v1/public/${videoId}/player?portalId=${portalId}`);
|
|
7
|
+
if (!response.ok) {
|
|
8
|
+
const err = Object.assign(new Error('Failed to fetch video'), {
|
|
9
|
+
status: response.status,
|
|
10
|
+
});
|
|
11
|
+
throw err;
|
|
12
|
+
}
|
|
13
|
+
return (await response.json());
|
|
14
|
+
}
|
|
15
|
+
export async function fetchSubtitles(videoId, portalId, env, hublet) {
|
|
16
|
+
const response = await fetch(`${getApiOrigin(env, hublet)}/video/v1/public/${videoId}/subtitles?portalId=${portalId}`);
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
const err = Object.assign(new Error('Failed to fetch subtitles'), response);
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
return (await response.json());
|
|
22
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HsEnvironment } from '../types';
|
|
2
|
+
export declare const CaptionTracks: ({ videoId, portalId, hsEnv, }: {
|
|
3
|
+
videoId: number;
|
|
4
|
+
portalId: number;
|
|
5
|
+
hsEnv: HsEnvironment;
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=CaptionTracks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CaptionTracks.d.ts","sourceRoot":"","sources":["../../src/components/CaptionTracks.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAKzC,eAAO,MAAM,aAAa,kCAIvB;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,aAAa,CAAC;CACtB,4CAoBA,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useSubtitles } from '../hooks/useSubtitles';
|
|
3
|
+
const languageNames = new Intl.DisplayNames(['en'], { type: 'language' });
|
|
4
|
+
// todo first captions track is automatically enabled
|
|
5
|
+
export const CaptionTracks = ({ videoId, portalId, hsEnv, }) => {
|
|
6
|
+
const { subtitles } = useSubtitles(videoId, portalId, hsEnv);
|
|
7
|
+
return (_jsx(_Fragment, { children: subtitles &&
|
|
8
|
+
Object.entries(subtitles).map(([language, url]) => (_jsx("track", { src: url, kind: "captions", srcLang: language, label: languageNames.of(language), style: {
|
|
9
|
+
display: 'none',
|
|
10
|
+
} }, language))) }));
|
|
11
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const BigPlayIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare const PlayPauseIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export declare const VolumeHighIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare const VolumeLowIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare const VolumeMuteIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare const CaptionsMenuIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const SettingsMenuIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare const PipIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare const EnterFullscreenIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare const ExitFullscreenIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const CloseIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=HSPlayerIcons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HSPlayerIcons.d.ts","sourceRoot":"","sources":["../../src/components/HSPlayerIcons.tsx"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,+CASvB,CAAC;AAEF,eAAO,MAAM,aAAa,+CAazB,CAAC;AAEF,eAAO,MAAM,cAAc,+CAU1B,CAAC;AAEF,eAAO,MAAM,aAAa,+CASzB,CAAC;AAEF,eAAO,MAAM,cAAc,+CAS1B,CAAC;AAEF,eAAO,MAAM,gBAAgB,+CAS5B,CAAC;AAEF,eAAO,MAAM,gBAAgB,+CAQ5B,CAAC;AAEF,eAAO,MAAM,OAAO,+CASnB,CAAC;AAEF,eAAO,MAAM,mBAAmB,+CAmB/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,+CAU9B,CAAC;AAEF,eAAO,MAAM,SAAS,+CAarB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export const BigPlayIcon = () => (
|
|
3
|
+
// @ts-expect-error slot needed for media-chrome but not supported in react types
|
|
4
|
+
_jsx("svg", { slot: "play", "aria-hidden": "true", viewBox: "-1 0 23 24", children: _jsx("path", { fillRule: "evenodd", d: "M5.5 6c0-.8.8-1.3 1.5-.9l10 6c.7.4.7 1.4 0 1.8l-10 6c-.7.4-1.5-.1-1.5-.9V6Z", clipRule: "evenodd" }) }));
|
|
5
|
+
export const PlayPauseIcon = () => (_jsx("svg", { viewBox: "0 0 36 36", children: _jsxs("g", { id: "icon-play", children: [_jsxs("g", { id: "play-icon", children: [_jsx("path", { id: "play-p1", d: "M18.5 14L12 10V26L18.5 22V14Z" }), _jsx("path", { id: "play-p2", d: "M18 13.6953L25 18L18 22.3086V13.6953Z" })] }), _jsxs("g", { id: "pause-icon", children: [_jsx("path", { id: "pause-p1", d: "M16 10H12V26H16V10Z" }), _jsx("path", { id: "pause-p2", d: "M21 10H25V26H21V10Z" })] })] }) }));
|
|
6
|
+
export const VolumeHighIcon = () => (_jsxs("svg", { viewBox: "0 0 36 36", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#icon-volume" }), _jsxs("g", { id: "icon-volume", children: [_jsx("path", { d: "M19.29,29.28c-.2,0-.39-.05-.57-.15l-11.61-6.71H1c-.3,0-.59-.12-.81-.33-.21-.21-.33-.51-.33-.81v-11.43c0-.63.51-1.14,1.14-1.14l6.04-.03,11.68-6.68c.35-.2.79-.2,1.14,0,.35.2.57.58.57.99v25.14c0,.41-.22.79-.57.99-.18.1-.37.15-.57.15ZM7.41,20.14c.2,0,.4.05.57.15l10.17,5.87V4.97l-10.24,5.85c-.17.1-.36.15-.56.15l-5.2.03v9.15h5.26Z" }), _jsx("path", { d: "M6.71,17.86c-.63,0-1.14-.51-1.14-1.14v-2.29c0-.63.51-1.14,1.14-1.14s1.14.51,1.14,1.14v2.29c0,.63-.51,1.14-1.14,1.14Z" }), _jsx("path", { d: "M23.86,24.8c-.55,0-1.03-.4-1.13-.95-.11-.62.31-1.21.94-1.32,3.42-.58,5.9-3.51,5.9-6.96s-2.48-6.39-5.9-6.96c-.62-.1-1.04-.69-.94-1.32.1-.62.69-1.04,1.32-.94,4.52.76,7.81,4.64,7.81,9.22s-3.28,8.45-7.81,9.22c-.06.01-.13.02-.19.02Z" }), _jsx("path", { d: "M23.86,19.04c-.39,0-.77-.2-.98-.56-.32-.54-.14-1.24.4-1.57.51-.3.81-.8.81-1.34s-.3-1.03-.81-1.34c-.54-.32-.72-1.02-.4-1.57.32-.54,1.02-.72,1.57-.4,1.21.72,1.93,1.95,1.93,3.31s-.72,2.59-1.93,3.3c-.18.11-.38.16-.58.16Z" })] })] }));
|
|
7
|
+
export const VolumeLowIcon = () => (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 36 36", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#icon-volume" }), _jsxs("g", { id: "icon-volume", children: [_jsx("path", { d: "M21.29,29.29c-.2,0-.39-.05-.57-.15l-11.61-6.7H3c-.3,0-.59-.12-.81-.33-.21-.21-.33-.5-.33-.81v-11.43c0-.63.51-1.14,1.14-1.14l6.04-.03,11.68-6.68c.35-.2.79-.2,1.14,0,.35.2.57.58.57.99v25.14c0,.41-.22.79-.57.99-.18.1-.37.15-.57.15ZM9.41,20.14c.2,0,.4.05.57.15l10.17,5.87V4.97l-10.24,5.85c-.17.1-.36.15-.56.15l-5.2.03v9.15h5.26Z" }), _jsx("path", { d: "M8.71,17.86c-.63,0-1.14-.51-1.14-1.14v-2.29c0-.63.51-1.14,1.14-1.14s1.14.51,1.14,1.14v2.29c0,.63-.51,1.14-1.14,1.14Z" }), _jsx("path", { d: "M25.86,20.76c-.55,0-1.03-.39-1.13-.95-.11-.62.31-1.21.94-1.32,1.43-.24,2.48-1.47,2.48-2.92s-1.04-2.68-2.48-2.92c-.62-.1-1.04-.69-.94-1.32.1-.62.69-1.04,1.32-.94,2.54.43,4.38,2.6,4.38,5.17s-1.84,4.74-4.38,5.17c-.06.01-.13.02-.19.02Z" })] })] }));
|
|
8
|
+
export const VolumeMuteIcon = () => (_jsxs("svg", { viewBox: "0 0 36 36", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#icon-muted" }), _jsxs("g", { id: "icon-muted", children: [_jsx("path", { d: "M28.07,29.29c-.29,0-.58-.11-.81-.33L2.19,3.88c-.45-.45-.45-1.17,0-1.62.45-.45,1.17-.45,1.62,0l25.07,25.07c.45.45.45,1.17,0,1.62-.22.22-.52.33-.81.33Z" }), _jsx("path", { d: "M23.5,19c-.63,0-1.14-.51-1.14-1.14V4.97l-6.72,3.84c-.55.31-1.25.12-1.56-.43-.31-.55-.12-1.25.42-1.56l8.43-4.81c.35-.2.79-.2,1.14,0,.35.2.57.58.57.99v14.86c0,.63-.51,1.14-1.14,1.14Z" }), _jsx("path", { d: "M19.29,26.85c-.19,0-.39-.05-.57-.15l-7.4-4.27h-6.1c-.3,0-.59-.12-.81-.33-.21-.21-.33-.5-.33-.81v-9.14c0-.63.51-1.14,1.14-1.14s1.14.51,1.14,1.14v8h5.26c.2,0,.4.05.57.15l7.67,4.43c.55.32.73,1.01.42,1.56-.21.37-.6.57-.99.57Z" })] })] }));
|
|
9
|
+
export const CaptionsMenuIcon = () => (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 32 32", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#captions-menu-icon" }), _jsxs("g", { id: "captions-menu-icon", children: [_jsx("path", { d: "M28.43,27.71H3.29c-1.89,0-3.43-1.54-3.43-3.43v-16c0-1.89,1.54-3.43,3.43-3.43h25.14c1.89,0,3.43,1.54,3.43,3.43v16c0,1.89-1.54,3.43-3.43,3.43ZM3.29,7.14c-.63,0-1.14.51-1.14,1.14v16c0,.63.51,1.14,1.14,1.14h25.14c.63,0,1.14-.51,1.14-1.14v-16c0-.63-.51-1.14-1.14-1.14H3.29Z" }), _jsx("path", { d: "M5.38,16.28c0-3.58,2.67-6.2,6.31-6.2,1.12,0,2.41.33,3.29.95v2.45c-.81-.72-1.98-1.17-3.2-1.17-2.24,0-3.94,1.59-3.94,3.98s1.7,3.98,3.94,3.98c1.16,0,2.4-.45,3.2-1.17v2.45c-.88.62-2.17.95-3.29.95-3.64,0-6.31-2.62-6.31-6.2h0Z" }), _jsx("path", { d: "M16.38,16.28c0-3.58,2.67-6.2,6.31-6.2,1.12,0,2.41.33,3.29.95v2.45c-.81-.72-1.98-1.17-3.2-1.17-2.24,0-3.94,1.59-3.94,3.98s1.7,3.98,3.94,3.98c1.16,0,2.4-.45,3.2-1.17v2.45c-.88.62-2.17.95-3.29.95-3.64,0-6.31-2.62-6.31-6.2h0Z" })] })] }));
|
|
10
|
+
export const SettingsMenuIcon = () => (_jsxs("svg", { viewBox: "0 0 32 32", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#settings-icon" }), _jsxs("g", { id: "settings-icon", children: [_jsx("path", { d: "M16.26,21.57c-3.15,0-5.71-2.56-5.71-5.71,0-1.01.27-2,.77-2.86.32-.55,1.02-.73,1.56-.42.55.32.73,1.02.42,1.56-.3.52-.46,1.11-.46,1.72,0,1.89,1.54,3.43,3.43,3.43s3.43-1.54,3.43-3.43-1.54-3.43-3.43-3.43c-.63,0-1.14-.51-1.14-1.14s.51-1.14,1.14-1.14c3.15,0,5.71,2.56,5.71,5.71s-2.56,5.71-5.71,5.71Z" }), _jsx("path", { d: "M16.89,31.86h-1.27c-1.48,0-2.79-.94-3.25-2.35l-.44-1.34c-.09-.27-.27-.49-.51-.63l-2.9-1.68c-.22-.13-.49-.18-.74-.14l-1.34.2c-1.31.19-2.62-.39-3.36-1.49l-.64-.96c-.77-1.15-.77-2.65,0-3.8l1.06-1.58c.12-.19.19-.41.19-.63v-3.19c0-.23-.07-.44-.19-.63l-1.06-1.58c-.77-1.16-.77-2.65,0-3.8l.64-.95c.73-1.1,2.05-1.68,3.36-1.49l1.34.2c.25.04.52-.01.74-.14l2.94-1.71c.23-.13.4-.34.5-.59l.56-1.48c.5-1.33,1.79-2.22,3.21-2.22h1.08c1.42,0,2.71.89,3.21,2.22l.55,1.48c.09.25.27.46.5.59l2.94,1.71c.22.13.49.18.74.14l1.34-.2c1.31-.19,2.63.39,3.36,1.49l.6.9c.79,1.19.76,2.76-.08,3.91l-.99,1.36c-.12.19-.18.41-.18.63l.02,3.36c0,.22.07.44.19.63l1.06,1.59c.77,1.16.77,2.65,0,3.8l-.64.95c-.73,1.1-2.05,1.68-3.36,1.49l-1.34-.2c-.25-.04-.52.01-.74.14l-2.9,1.68c-.24.14-.42.36-.51.63l-.44,1.33c-.47,1.41-1.77,2.35-3.25,2.35ZM7.93,23.42c.6,0,1.2.16,1.73.46l2.9,1.68c.73.42,1.27,1.09,1.53,1.89l.44,1.34c.16.47.59.78,1.08.78h1.27c.49,0,.93-.32,1.08-.78l.44-1.34c.27-.8.81-1.47,1.53-1.89l2.9-1.68c.67-.39,1.46-.54,2.23-.43l1.34.2c.44.07.87-.13,1.12-.5l.64-.95c.26-.38.26-.88,0-1.27l-1.06-1.59c-.37-.56-.57-1.21-.58-1.88l-.02-3.36c0-.72.23-1.45.65-2.03l.95-1.31c.28-.38.29-.91.03-1.3l-.6-.9c-.24-.37-.68-.57-1.12-.5l-1.34.2c-.76.11-1.55-.04-2.23-.43l-2.95-1.71c-.68-.39-1.21-1.02-1.49-1.76l-.56-1.48c-.17-.44-.6-.74-1.07-.74h-1.08c-.47,0-.9.3-1.07.74l-.56,1.48c-.28.74-.81,1.37-1.49,1.76l-2.94,1.71c-.67.39-1.46.54-2.23.43l-1.34-.2c-.44-.07-.88.13-1.12.5l-.64.95c-.26.38-.26.88,0,1.27l1.06,1.58c.38.57.58,1.23.58,1.9v3.19c0,.68-.2,1.33-.58,1.9l-1.06,1.59c-.26.39-.26.88,0,1.27l.64.95c.24.37.69.57,1.12.5l1.34-.2c.17-.02.33-.04.5-.04Z" })] })] }));
|
|
11
|
+
export const PipIcon = () => (_jsxs("svg", { viewBox: "0 0 36 36", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#pip-icon" }), _jsx("path", { d: "M25 17H17V23H25V17Z" }), _jsx("path", { id: "pip-icon", d: "M7 11C7 9.89543 7.89545 9 9 9H27.0161C28.1207 9 29.0161 9.89543 29.0161 11V24.8837C29.0161 25.9883 28.1207 26.8837 27.0162 26.8837H9C7.89545 26.8837 7 25.9883 7 24.8837V11ZM9 11H27V25H9V11Z" })] }));
|
|
12
|
+
export const EnterFullscreenIcon = () => (_jsxs("svg", { viewBox: "0 0 36 36", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#fs-enter-paths" }), _jsxs("g", { id: "fs-enter-paths", children: [_jsx("path", { className: "ulbounce", d: "M11 15H9V9H15V11H11V15Z" }), _jsx("path", { className: "urbounce", d: "M21 11L21 9L27 9L27 15L25 15L25 11L21 11Z" }), _jsx("path", { className: "dlbounce", d: "M15 25L15 27L9 27L9 21L11 21L11 25L15 25Z" }), _jsx("path", { className: "drbounce", d: "M25 21L27 21L27 27L21 27L21 25L25 25L25 21Z" })] })] }));
|
|
13
|
+
export const ExitFullscreenIcon = () => (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 32 32", children: [_jsx("use", { className: "svg-shadow", xlinkHref: "#fs-exit-paths" }), _jsxs("g", { id: "fs-exit-paths", children: [_jsx("path", { d: "M19,13.28c-.29,0-.58-.11-.81-.33-.45-.45-.45-1.17,0-1.62L27.33,2.19c.45-.45,1.17-.45,1.62,0,.45.45.45,1.17,0,1.62l-9.14,9.14c-.22.22-.52.33-.81.33Z" }), _jsx("path", { d: "M3,29.28c-.29,0-.58-.11-.81-.33-.45-.45-.45-1.17,0-1.62l9.14-9.14c.45-.45,1.17-.45,1.62,0,.45.45.45,1.17,0,1.62L3.81,28.95c-.22.22-.52.33-.81.33Z" }), _jsx("path", { d: "M28.14,13.28h-9.14c-.63,0-1.14-.51-1.14-1.14V3c0-.63.51-1.14,1.14-1.14s1.14.51,1.14,1.14v8h8c.63,0,1.14.51,1.14,1.14s-.51,1.14-1.14,1.14Z" }), _jsx("path", { d: "M12.14,29.28c-.63,0-1.14-.51-1.14-1.14v-8H3c-.63,0-1.14-.51-1.14-1.14s.51-1.14,1.14-1.14h9.14c.63,0,1.14.51,1.14,1.14v9.14c0,.63-.51,1.14-1.14,1.14Z" })] })] }));
|
|
14
|
+
export const CloseIcon = () => (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M18 6 6 18" }), _jsx("path", { d: "m6 6 12 12" })] }));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HubSpotVideoParams } from '../types';
|
|
2
|
+
import { Translations } from '../utils/i18n';
|
|
3
|
+
import { PlayerActions } from './VideoPlayerProvider';
|
|
4
|
+
type HSPlayerTheme = {
|
|
5
|
+
themeName: string;
|
|
6
|
+
primaryColor: string;
|
|
7
|
+
secondaryColor: string;
|
|
8
|
+
accentColor: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const HSPlayerThemes: Record<string, HSPlayerTheme>;
|
|
11
|
+
type HubspotPlayerProps = {
|
|
12
|
+
videoPlayer: React.ReactNode;
|
|
13
|
+
themeProps: HSPlayerTheme;
|
|
14
|
+
translations: Translations;
|
|
15
|
+
hubspotVideoParams: HubSpotVideoParams;
|
|
16
|
+
fullscreenElement?: HTMLElement;
|
|
17
|
+
actions: PlayerActions;
|
|
18
|
+
language: string;
|
|
19
|
+
isPipMode: boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare const HSThemeWrapper: ({ videoPlayer, themeProps, hubspotVideoParams, }: Pick<HubspotPlayerProps, "videoPlayer" | "themeProps" | "hubspotVideoParams">) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=HSThemeTemplate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HSThemeTemplate.d.ts","sourceRoot":"","sources":["../../src/components/HSThemeTemplate.tsx"],"names":[],"mappings":"AA+BA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAc7C,OAAO,EAAE,aAAa,EAAkB,MAAM,uBAAuB,CAAC;AAEtE,KAAK,aAAa,GAAG;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAaxD,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,UAAU,EAAE,aAAa,CAAC;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,cAAc,qDAIxB,IAAI,CACL,kBAAkB,EAClB,aAAa,GAAG,YAAY,GAAG,oBAAoB,CACpD,4CA4DA,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MediaControlBar, MediaController, MediaErrorDialog, MediaFullscreenButton, MediaLoadingIndicator, MediaMuteButton, MediaPipButton, MediaPlayButton, MediaPreviewChapterDisplay, MediaPreviewThumbnail, MediaPreviewTimeDisplay, MediaTimeDisplay, MediaTimeRange, MediaVolumeRange, } from 'media-chrome/react';
|
|
3
|
+
import { MediaCaptionsMenu, MediaCaptionsMenuButton, MediaPlaybackRateMenu, MediaRenditionMenu, MediaSettingsMenu, MediaSettingsMenuButton, MediaSettingsMenuItem,
|
|
4
|
+
// @ts-expect-error cannot resolve - types are incomplete
|
|
5
|
+
} from 'media-chrome/react/menu';
|
|
6
|
+
import { useEffect, useRef } from 'react';
|
|
7
|
+
import { createRoot } from 'react-dom/client';
|
|
8
|
+
import { DEFAULT_PLAY_BUTTON_COLOR } from '../constants';
|
|
9
|
+
import playerThemeStyles from '../styles/player-theme.css';
|
|
10
|
+
import { BigPlayIcon, CaptionsMenuIcon, EnterFullscreenIcon, ExitFullscreenIcon, PipIcon, PlayPauseIcon, SettingsMenuIcon, VolumeHighIcon, VolumeLowIcon, VolumeMuteIcon, } from './HSPlayerIcons';
|
|
11
|
+
import { useLanguage, useTranslations } from './TranslationsProvider';
|
|
12
|
+
import { useVideoPlayer } from './VideoPlayerProvider';
|
|
13
|
+
export const HSPlayerThemes = {
|
|
14
|
+
DARK: {
|
|
15
|
+
themeName: 'dark',
|
|
16
|
+
primaryColor: '#ffffff',
|
|
17
|
+
secondaryColor: '#4b4b4b',
|
|
18
|
+
accentColor: DEFAULT_PLAY_BUTTON_COLOR,
|
|
19
|
+
},
|
|
20
|
+
LIGHT: {
|
|
21
|
+
themeName: 'light',
|
|
22
|
+
primaryColor: '#333333',
|
|
23
|
+
secondaryColor: '#ffffff',
|
|
24
|
+
accentColor: '#460629',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
export const HSThemeWrapper = ({ videoPlayer, themeProps, hubspotVideoParams, }) => {
|
|
28
|
+
const wrapperRef = useRef(null);
|
|
29
|
+
const containerRef = useRef(null);
|
|
30
|
+
const rootRef = useRef(null);
|
|
31
|
+
const translations = useTranslations();
|
|
32
|
+
const language = useLanguage();
|
|
33
|
+
const { actions, state } = useVideoPlayer();
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
// Initialize Shadow DOM to encapsulate player styles
|
|
36
|
+
if (!wrapperRef.current?.shadowRoot) {
|
|
37
|
+
const shadowRoot = wrapperRef.current?.attachShadow({ mode: 'open' });
|
|
38
|
+
const style = document.createElement('style');
|
|
39
|
+
style.textContent = playerThemeStyles;
|
|
40
|
+
shadowRoot?.appendChild(style);
|
|
41
|
+
}
|
|
42
|
+
// Initialize React root container
|
|
43
|
+
if (!containerRef.current) {
|
|
44
|
+
containerRef.current = document.createElement('div');
|
|
45
|
+
wrapperRef.current?.shadowRoot?.appendChild(containerRef.current);
|
|
46
|
+
rootRef.current = createRoot(containerRef.current);
|
|
47
|
+
}
|
|
48
|
+
return () => {
|
|
49
|
+
if (rootRef.current) {
|
|
50
|
+
rootRef.current.unmount();
|
|
51
|
+
rootRef.current = null;
|
|
52
|
+
}
|
|
53
|
+
if (containerRef.current && wrapperRef.current?.shadowRoot) {
|
|
54
|
+
wrapperRef.current.shadowRoot.removeChild(containerRef.current);
|
|
55
|
+
containerRef.current = null;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
rootRef.current?.render(_jsx(HSPlayer, { videoPlayer: videoPlayer, themeProps: themeProps, translations: translations, hubspotVideoParams: hubspotVideoParams, fullscreenElement: wrapperRef.current ?? undefined, actions: actions, language: language, isPipMode: state.isPipMode }));
|
|
61
|
+
}, [
|
|
62
|
+
videoPlayer,
|
|
63
|
+
themeProps,
|
|
64
|
+
translations,
|
|
65
|
+
hubspotVideoParams,
|
|
66
|
+
language,
|
|
67
|
+
actions,
|
|
68
|
+
state.isPipMode,
|
|
69
|
+
]);
|
|
70
|
+
return _jsx("section", { ref: wrapperRef });
|
|
71
|
+
};
|
|
72
|
+
const getIsExpanded = (element) => {
|
|
73
|
+
return element.getAttribute('aria-expanded') === 'true';
|
|
74
|
+
};
|
|
75
|
+
const HSPlayer = ({ videoPlayer, themeProps, translations, hubspotVideoParams, fullscreenElement, language, actions, isPipMode, }) => {
|
|
76
|
+
const { hide_controls } = hubspotVideoParams;
|
|
77
|
+
const captionsMenuRef = useRef(null);
|
|
78
|
+
const settingsMenuRef = useRef(null);
|
|
79
|
+
return (_jsxs(MediaController, { lang: language, breakpoints: "md:480", hotkeys: "true", defaultStreamType: "on-demand", defaultSubtitles: false, fullscreenElement: fullscreenElement, style: {
|
|
80
|
+
'--media-primary-color': themeProps.primaryColor,
|
|
81
|
+
'--media-text-color': themeProps.primaryColor,
|
|
82
|
+
'--hs-secondary-color': themeProps.secondaryColor,
|
|
83
|
+
'--hs-secondary-color-translucent': themeProps.secondaryColor + 'cc',
|
|
84
|
+
'--media-accent-color': themeProps.accentColor,
|
|
85
|
+
}, children: [videoPlayer, _jsx("slot", { name: "media", slot: "media" }), _jsx("slot", { name: "poster", slot: "poster" }), _jsx("slot", { name: "overlay", slot: "centered-chrome" }), _jsx(MediaLoadingIndicator, { noAutohide: true, slot: "centered-chrome" }), _jsx(MediaPlayButton, { slot: "centered-chrome", className: "centered-play-button", children: _jsx(BigPlayIcon, {}) }), _jsx(MediaErrorDialog, { slot: "dialog" }), _jsxs("div", { className: "hs-control-bar-background", style: { display: hide_controls ? 'none' : 'flex' }, children: [_jsxs(MediaTimeRange, { children: [_jsx(MediaPreviewThumbnail, { slot: "preview" }), _jsx(MediaPreviewChapterDisplay, { slot: "preview" }), _jsx(MediaPreviewTimeDisplay, { slot: "preview" })] }), _jsx("div", { className: "hs-bottom-gradient", "data-theme-variant": themeProps.themeName }), _jsxs(MediaControlBar, { children: [_jsx(MediaPlayButton, { className: "hs-button", mediaPaused: true, children: _jsx("span", { slot: "icon", children: _jsx(PlayPauseIcon, {}) }) }), _jsx(MediaTimeDisplay, { showDuration: true }), _jsx("span", { className: "control-spacer" }), _jsxs("div", { className: "media-volume-wrapper", children: [_jsxs(MediaMuteButton, { className: "hs-button", tooltipPlacement: "bottom", children: [_jsx("span", { slot: "high", children: _jsx(VolumeHighIcon, {}) }), _jsx("span", { slot: "medium", children: _jsx(VolumeHighIcon, {}) }), _jsx("span", { slot: "low", children: _jsx(VolumeLowIcon, {}) }), _jsx("span", { slot: "off", children: _jsx(VolumeMuteIcon, {}) })] }), _jsx("div", { className: "media-volume-range-wrapper", children: _jsx("div", { className: "media-volume-range-inner", children: _jsx(MediaVolumeRange, {}) }) })] }), _jsx(MediaCaptionsMenu, { anchor: "auto", hidden: true }), _jsx(MediaCaptionsMenuButton, { ref: captionsMenuRef, className: "hs-button", onClick: () => {
|
|
86
|
+
if (captionsMenuRef.current) {
|
|
87
|
+
actions.toggleMenu('captions', getIsExpanded(captionsMenuRef.current));
|
|
88
|
+
}
|
|
89
|
+
}, children: _jsx("span", { slot: "icon", children: _jsx(CaptionsMenuIcon, {}) }) }), _jsx(MediaSettingsMenuButton, { ref: settingsMenuRef, className: "hs-button", onClick: () => {
|
|
90
|
+
if (settingsMenuRef.current) {
|
|
91
|
+
actions.toggleMenu('settings', getIsExpanded(settingsMenuRef.current));
|
|
92
|
+
}
|
|
93
|
+
}, children: _jsx("span", { slot: "icon", children: _jsx(SettingsMenuIcon, {}) }) }), _jsxs(MediaSettingsMenu, { role: "menu", anchor: "auto", hidden: true, children: [_jsxs(MediaSettingsMenuItem, { children: [translations.playbackSpeed, _jsx(MediaPlaybackRateMenu, { slot: "submenu", hidden: true, children: _jsx("div", { slot: "title", children: translations.playbackSpeed }) })] }), _jsxs(MediaSettingsMenuItem, { children: [translations.quality, _jsx(MediaRenditionMenu, { slot: "submenu", hidden: true, children: _jsx("div", { slot: "title", children: translations.quality }) })] })] }), _jsx(MediaPipButton, { className: "hs-button", mediaIsPip: isPipMode, children: _jsx("span", { slot: "icon", children: _jsx(PipIcon, {}) }) }), _jsxs(MediaFullscreenButton, { className: "hs-button", children: [_jsx("span", { slot: "enter", children: _jsx(EnterFullscreenIcon, {}) }), _jsx("span", { slot: "exit", children: _jsx(ExitFullscreenIcon, {}) })] })] })] })] }));
|
|
94
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { Translations } from '../utils/i18n';
|
|
3
|
+
export declare const TranslationsContext: import("react").Context<{
|
|
4
|
+
translations: Translations;
|
|
5
|
+
language: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare const TranslationsProvider: ({ children, translations, language, }: PropsWithChildren<{
|
|
8
|
+
translations: Partial<Translations>;
|
|
9
|
+
language?: string;
|
|
10
|
+
}>) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const useTranslations: () => Translations;
|
|
12
|
+
export declare const useLanguage: () => string;
|
|
13
|
+
//# sourceMappingURL=TranslationsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TranslationsProvider.d.ts","sourceRoot":"","sources":["../../src/components/TranslationsProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,iBAAiB,EAIlB,MAAM,OAAO,CAAC;AAIf,OAAO,EAIL,YAAY,EACb,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,mBAAmB;kBAChB,YAAY;cAChB,MAAM;EACoD,CAAC;AAEvE,eAAO,MAAM,oBAAoB,0CAI9B,iBAAiB,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,4CAsBD,CAAC;AAEF,eAAO,MAAM,eAAe,oBAG3B,CAAC;AAEF,eAAO,MAAM,WAAW,cAGvB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useMemo, } from 'react';
|
|
3
|
+
// @ts-expect-error cannot resolve
|
|
4
|
+
import { addTranslation } from 'media-chrome/utils/i18n';
|
|
5
|
+
import { createTranslationsMap, DEFAULT_LANGUAGE, DEFAULT_TRANSLATIONS, } from '../utils/i18n';
|
|
6
|
+
export const TranslationsContext = createContext({ translations: DEFAULT_TRANSLATIONS, language: DEFAULT_LANGUAGE });
|
|
7
|
+
export const TranslationsProvider = ({ children, translations, language = DEFAULT_LANGUAGE, }) => {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (language !== DEFAULT_LANGUAGE) {
|
|
10
|
+
// Add custom language to media-chrome's translations dictionary
|
|
11
|
+
addTranslation(language, createTranslationsMap(translations));
|
|
12
|
+
}
|
|
13
|
+
}, [language, translations]);
|
|
14
|
+
const contextValue = useMemo(() => ({
|
|
15
|
+
// provide default EN translation fallbacks for any missing keys
|
|
16
|
+
translations: { ...DEFAULT_TRANSLATIONS, ...translations },
|
|
17
|
+
language,
|
|
18
|
+
}), [translations, language]);
|
|
19
|
+
return (_jsx(TranslationsContext.Provider, { value: contextValue, children: children }));
|
|
20
|
+
};
|
|
21
|
+
export const useTranslations = () => {
|
|
22
|
+
const { translations } = useContext(TranslationsContext);
|
|
23
|
+
return translations;
|
|
24
|
+
};
|
|
25
|
+
export const useLanguage = () => {
|
|
26
|
+
const { language } = useContext(TranslationsContext);
|
|
27
|
+
return language;
|
|
28
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { FetchError } from '../api/video';
|
|
3
|
+
import { HsEnvironment, HubSpotVideoParams, VideoCrmObject } from '../types';
|
|
4
|
+
type VideoFetchProviderProps = PropsWithChildren<{
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
env: HsEnvironment;
|
|
7
|
+
hublet: string;
|
|
8
|
+
videoId: number;
|
|
9
|
+
video?: VideoCrmObject;
|
|
10
|
+
videoFetchError?: FetchError;
|
|
11
|
+
hubspotVideoParams: HubSpotVideoParams;
|
|
12
|
+
}>;
|
|
13
|
+
export declare const VideoFetchContext: import("react").Context<{
|
|
14
|
+
video?: VideoCrmObject;
|
|
15
|
+
videoFetchError?: FetchError;
|
|
16
|
+
hubspotVideoParams?: HubSpotVideoParams;
|
|
17
|
+
hublet: string;
|
|
18
|
+
env: HsEnvironment;
|
|
19
|
+
}>;
|
|
20
|
+
export declare const VideoFetchProvider: ({ children, ...props }: VideoFetchProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=VideoFetchProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoFetchProvider.d.ts","sourceRoot":"","sources":["../../src/components/VideoFetchProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE7E,KAAK,uBAAuB,GAAG,iBAAiB,CAAC;IAC/C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,kBAAkB,EAAE,kBAAkB,CAAC;CACxC,CAAC,CAAC;AAEH,eAAO,MAAM,iBAAiB;YACpB,cAAc;sBACJ,UAAU;yBACP,kBAAkB;YAC/B,MAAM;SACT,aAAa;EAOlB,CAAC;AAEH,eAAO,MAAM,kBAAkB,2BAG5B,uBAAuB,4CAMzB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext } from 'react';
|
|
3
|
+
export const VideoFetchContext = createContext({
|
|
4
|
+
video: undefined,
|
|
5
|
+
videoFetchError: undefined,
|
|
6
|
+
hubspotVideoParams: undefined,
|
|
7
|
+
hublet: 'na1',
|
|
8
|
+
env: 'prod',
|
|
9
|
+
});
|
|
10
|
+
export const VideoFetchProvider = ({ children, ...props }) => {
|
|
11
|
+
return (_jsx(VideoFetchContext.Provider, { value: props, children: children }));
|
|
12
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import '../styles/mux-player.css';
|
|
2
|
+
import { HSPlayerThemes } from './HSThemeTemplate';
|
|
3
|
+
type VideoPlayerProps = {
|
|
4
|
+
portalId: number;
|
|
5
|
+
playButtonColor?: {
|
|
6
|
+
color: string;
|
|
7
|
+
};
|
|
8
|
+
theme: keyof typeof HSPlayerThemes;
|
|
9
|
+
overlay?: React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
export declare const VideoPlayer: ({ portalId, playButtonColor, theme, overlay, }: VideoPlayerProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=VideoPlayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../../src/components/VideoPlayer.tsx"],"names":[],"mappings":"AAMA,OAAO,0BAA0B,CAAC;AAIlC,OAAO,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAGnE,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,EAAE,MAAM,OAAO,cAAc,CAAC;IACnC,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,WAAW,mDAKrB,gBAAgB,mDAsFlB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useContext } from 'react';
|
|
3
|
+
import MuxVideo from '@mux/mux-video/react';
|
|
4
|
+
// @ts-expect-error cannot resolve - types are incomplete
|
|
5
|
+
import { useMediaRef } from 'media-chrome/react/media-store';
|
|
6
|
+
import '../styles/mux-player.css';
|
|
7
|
+
import { useVideoPlayer } from './VideoPlayerProvider';
|
|
8
|
+
import { CaptionTracks } from './CaptionTracks';
|
|
9
|
+
import { DEFAULT_HLS_OPTIONS } from '../constants';
|
|
10
|
+
import { HSPlayerThemes, HSThemeWrapper } from './HSThemeTemplate';
|
|
11
|
+
import { VideoFetchContext } from './VideoFetchProvider';
|
|
12
|
+
export const VideoPlayer = ({ portalId, playButtonColor, theme, overlay, }) => {
|
|
13
|
+
const { video, hubspotVideoParams, env } = useContext(VideoFetchContext);
|
|
14
|
+
const mediaRef = useMediaRef();
|
|
15
|
+
const themeProps = HSPlayerThemes[theme] || HSPlayerThemes.DARK;
|
|
16
|
+
const { actions, eventCallbacks } = useVideoPlayer();
|
|
17
|
+
const setMediaRef = useCallback((el) => {
|
|
18
|
+
mediaRef(el);
|
|
19
|
+
actions.setElement(el);
|
|
20
|
+
}, [mediaRef, actions.setElement]);
|
|
21
|
+
const setupChapters = async (event) => {
|
|
22
|
+
const element = event.target;
|
|
23
|
+
if (element && video?.chapters) {
|
|
24
|
+
const chapters = video.chapters.items.map((chapter, i) => ({
|
|
25
|
+
startTime: chapter.startTime,
|
|
26
|
+
endTime: video.chapters.items[i + 1]?.startTime || video.duration / 1000,
|
|
27
|
+
value: chapter.title,
|
|
28
|
+
}));
|
|
29
|
+
try {
|
|
30
|
+
await element.addChapters(chapters);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.error('addChapters failed with error:', error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
if (!video) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return (_jsxs("div", { style: {
|
|
41
|
+
position: 'relative',
|
|
42
|
+
maxWidth: video.width,
|
|
43
|
+
aspectRatio: `${video.width} / ${video.height}`,
|
|
44
|
+
lineHeight: 0,
|
|
45
|
+
}, children: [_jsx(HSThemeWrapper, { videoPlayer: _jsxs(MuxVideo, { ref: setMediaRef, slot: "media", crossOrigin: "anonymous", playbackId: video.primaryPlaybackId || undefined, poster: video.posterUrl, src: video.primaryPlaybackId ? undefined : video.fileUrl, playsInline: true, _hlsConfig: DEFAULT_HLS_OPTIONS, style: {
|
|
46
|
+
aspectRatio: `${video.width} / ${video.height}`,
|
|
47
|
+
}, autoplay: hubspotVideoParams?.autoplay, loop: hubspotVideoParams?.loop_video, muted: hubspotVideoParams?.mute_by_default || false, onLoadedMetadata: setupChapters, ...eventCallbacks, children: [_jsx("track", { label: "thumbnails", kind: "metadata", src: `https://image.mux.com/${video.primaryPlaybackId}/storyboard.vtt?format=webp`, default: true }), _jsx(CaptionTracks, { videoId: video.videoId, portalId: portalId, hsEnv: env })] }), hubspotVideoParams: hubspotVideoParams, themeProps: {
|
|
48
|
+
...themeProps,
|
|
49
|
+
accentColor: playButtonColor?.color || themeProps?.accentColor,
|
|
50
|
+
} }), overlay] }));
|
|
51
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import MuxVideoElement from '@mux/mux-video';
|
|
2
|
+
import { PropsWithChildren } from 'react';
|
|
3
|
+
import { VideoCrmObject } from '../types';
|
|
4
|
+
export type PlayerState = {
|
|
5
|
+
hasStarted: boolean;
|
|
6
|
+
isPaused: boolean;
|
|
7
|
+
currentTime: number;
|
|
8
|
+
hasEnded: boolean;
|
|
9
|
+
playbackStartedAt?: number;
|
|
10
|
+
element: MuxVideoElement | null;
|
|
11
|
+
loadedDuration: number;
|
|
12
|
+
selectedCaptionTrack: string | null;
|
|
13
|
+
playbackRate: number;
|
|
14
|
+
isPipMode: boolean;
|
|
15
|
+
selectedRendition?: string;
|
|
16
|
+
};
|
|
17
|
+
export type MenuType = 'captions' | 'settings';
|
|
18
|
+
export type PlayerActions = {
|
|
19
|
+
play: () => void;
|
|
20
|
+
pause: (reason?: string) => void;
|
|
21
|
+
setElement: (el: MuxVideoElement | null) => void;
|
|
22
|
+
toggleMenu: (menuType: MenuType, isOpen: boolean) => void;
|
|
23
|
+
};
|
|
24
|
+
export type PlayerCallbacks = Pick<React.VideoHTMLAttributes<MuxVideoElement>, 'onPlay' | 'onPlaying'> & {
|
|
25
|
+
onPause?: (event: React.SyntheticEvent<MuxVideoElement>, reason?: string) => void;
|
|
26
|
+
onCaptionChange?: (lang: string) => void;
|
|
27
|
+
onToggleMenu?: (menuType: MenuType, isOpen: boolean) => void;
|
|
28
|
+
onPlaybackRateChange?: (playbackRate: number) => void;
|
|
29
|
+
onQualityChange?: (renditionId: string) => void;
|
|
30
|
+
};
|
|
31
|
+
export declare const VideoPlayerProvider: ({ video, children, playerCallbacks, }: PropsWithChildren<{
|
|
32
|
+
video?: VideoCrmObject;
|
|
33
|
+
playerCallbacks?: PlayerCallbacks;
|
|
34
|
+
}>) => import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export declare const useVideoPlayer: () => {
|
|
36
|
+
state: PlayerState;
|
|
37
|
+
actions: PlayerActions;
|
|
38
|
+
eventCallbacks: Record<string, React.ReactEventHandler<MuxVideoElement>>;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=VideoPlayerProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoPlayerProvider.d.ts","sourceRoot":"","sources":["../../src/components/VideoPlayerProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,gBAAgB,CAAC;AAS7C,OAAO,EAEL,iBAAiB,EAMlB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA4C1C,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IAEnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AAE/C,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,UAAU,EAAE,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,UAAU,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3D,CAAC;AAQF,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,KAAK,CAAC,mBAAmB,CAAC,eAAe,CAAC,EAC1C,QAAQ,GAAG,WAAW,CACvB,GAAG;IACF,OAAO,CAAC,EAAE,CACR,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,EAC5C,MAAM,CAAC,EAAE,MAAM,KACZ,IAAI,CAAC;IACV,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7D,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD,CAAC;AA0LF,eAAO,MAAM,mBAAmB,0CAI7B,iBAAiB,CAAC;IACnB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC,CAAC,4CAQD,CAAC;AAEF,eAAO,MAAM,cAAc;WA5NlB,WAAW;aACT,aAAa;oBACN,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC;CAgOzE,CAAC"}
|