feat(packages): add chromecast support via remote playback API (#1348)

This commit is contained in:
Wesley Luyten
2026-04-17 14:51:16 -07:00
committed by GitHub
parent 8530316987
commit 31a005eeef
54 changed files with 1928 additions and 89 deletions
+1
View File
@@ -33,6 +33,7 @@ export {
export { AlertDialog, type AlertDialogContextValue, useAlertDialogContext } from './ui/alert-dialog';
export { BufferingIndicator, type BufferingIndicatorProps } from './ui/buffering-indicator/buffering-indicator';
export { CaptionsButton, type CaptionsButtonProps } from './ui/captions-button/captions-button';
export { CastButton, type CastButtonProps } from './ui/cast-button/cast-button';
export { Controls } from './ui/controls';
export type { ControlsGroupProps } from './ui/controls/controls-group';
export type { ControlsRootProps } from './ui/controls/controls-root';
@@ -1,6 +1,8 @@
import {
CaptionsOffIcon,
CaptionsOnIcon,
CastEnterIcon,
CastExitIcon,
FullscreenEnterIcon,
FullscreenExitIcon,
PauseIcon,
@@ -41,6 +43,7 @@ import { type ComponentProps, forwardRef, type ReactNode } from 'react';
import { Container, usePlayer } from '@/player/context';
import { BufferingIndicator } from '@/ui/buffering-indicator';
import { CaptionsButton } from '@/ui/captions-button';
import { CastButton } from '@/ui/cast-button';
import { Controls } from '@/ui/controls';
import { ErrorDialog } from '@/ui/error-dialog';
import { FullscreenButton } from '@/ui/fullscreen-button';
@@ -268,6 +271,18 @@ export function MinimalVideoSkinTailwind(props: MinimalVideoSkinProps): ReactNod
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
<CastButton className={iconState.cast.button} render={<Button />}>
<CastEnterIcon className={cn(icon, iconState.cast.enter)} />
<CastExitIcon className={cn(icon, iconState.cast.exit)} />
</CastButton>
}
/>
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
@@ -1,6 +1,8 @@
import {
CaptionsOffIcon,
CaptionsOnIcon,
CastEnterIcon,
CastExitIcon,
FullscreenEnterIcon,
FullscreenExitIcon,
PauseIcon,
@@ -20,6 +22,7 @@ import { type ComponentProps, forwardRef, type ReactNode } from 'react';
import { Container, usePlayer } from '@/player/context';
import { BufferingIndicator } from '@/ui/buffering-indicator';
import { CaptionsButton } from '@/ui/captions-button';
import { CastButton } from '@/ui/cast-button';
import { Controls } from '@/ui/controls';
import { ErrorDialog } from '@/ui/error-dialog';
import { FullscreenButton } from '@/ui/fullscreen-button';
@@ -205,6 +208,18 @@ export function MinimalVideoSkin(props: MinimalVideoSkinProps): ReactNode {
<Tooltip.Popup className="media-tooltip" />
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
<CastButton className="media-button--cast" render={<Button />}>
<CastEnterIcon className="media-icon media-icon--cast-enter" />
<CastExitIcon className="media-icon media-icon--cast-exit" />
</CastButton>
}
/>
<Tooltip.Popup className="media-tooltip" />
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
@@ -1,6 +1,8 @@
import {
CaptionsOffIcon,
CaptionsOnIcon,
CastEnterIcon,
CastExitIcon,
FullscreenEnterIcon,
FullscreenExitIcon,
PauseIcon,
@@ -41,6 +43,7 @@ import { type ComponentProps, forwardRef, type ReactNode } from 'react';
import { Container, usePlayer } from '@/player/context';
import { BufferingIndicator } from '@/ui/buffering-indicator';
import { CaptionsButton } from '@/ui/captions-button';
import { CastButton } from '@/ui/cast-button';
import { Controls } from '@/ui/controls';
import { ErrorDialog } from '@/ui/error-dialog';
import { FullscreenButton } from '@/ui/fullscreen-button';
@@ -264,6 +267,18 @@ export function VideoSkinTailwind(props: VideoSkinProps): ReactNode {
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
<CastButton className={iconState.cast.button} render={<Button />}>
<CastEnterIcon className={cn(icon, iconState.cast.enter)} />
<CastExitIcon className={cn(icon, iconState.cast.exit)} />
</CastButton>
}
/>
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
+15
View File
@@ -1,6 +1,8 @@
import {
CaptionsOffIcon,
CaptionsOnIcon,
CastEnterIcon,
CastExitIcon,
FullscreenEnterIcon,
FullscreenExitIcon,
PauseIcon,
@@ -20,6 +22,7 @@ import { type ComponentProps, forwardRef, type ReactNode } from 'react';
import { Container, usePlayer } from '@/player/context';
import { BufferingIndicator } from '@/ui/buffering-indicator';
import { CaptionsButton } from '@/ui/captions-button';
import { CastButton } from '@/ui/cast-button';
import { Controls } from '@/ui/controls';
import { ErrorDialog } from '@/ui/error-dialog';
import { FullscreenButton } from '@/ui/fullscreen-button';
@@ -203,6 +206,18 @@ export function VideoSkin(props: VideoSkinProps): ReactNode {
<Tooltip.Popup className="media-surface media-tooltip" />
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
<CastButton className="media-button--cast" render={<Button />}>
<CastEnterIcon className="media-icon media-icon--cast-enter" />
<CastExitIcon className="media-icon media-icon--cast-exit" />
</CastButton>
}
/>
<Tooltip.Popup className="media-surface media-tooltip" />
</Tooltip.Root>
<Tooltip.Root side="top">
<Tooltip.Trigger
render={
@@ -0,0 +1,23 @@
'use client';
import { CastButtonCore, CastButtonDataAttrs } from '@videojs/core';
import { selectCast } from '@videojs/core/dom';
import type { UIComponentProps } from '../../utils/types';
import { createMediaButton } from '../create-media-button';
export interface CastButtonProps extends UIComponentProps<'button', CastButtonCore.State>, CastButtonCore.Props {}
/** A button that toggles casting to a remote device. */
export const CastButton = createMediaButton<CastButtonCore, CastButtonProps>({
displayName: 'CastButton',
core: CastButtonCore,
stateAttrMap: CastButtonDataAttrs,
selector: selectCast,
action: (core, state) => core.toggle(state),
});
export namespace CastButton {
export type Props = CastButtonProps;
export type State = CastButtonCore.State;
}
@@ -0,0 +1 @@
export * from './cast-button';