diff --git a/examples/html-demo/index.html b/examples/html-demo/index.html index 848981cf..d714eb37 100644 --- a/examples/html-demo/index.html +++ b/examples/html-demo/index.html @@ -4,19 +4,6 @@ VJS HTML Demo - - -

Video.js 10 HTML Demos

diff --git a/examples/html-demo/minimal-eject.html b/examples/html-demo/minimal-eject.html index d894a924..3687ad2c 100644 --- a/examples/html-demo/minimal-eject.html +++ b/examples/html-demo/minimal-eject.html @@ -27,7 +27,7 @@

Minimal Skin (ejected)

display: block; width: 100%; height: 100%; - border-radius: 2rem; + border-radius: 0.75rem; max-width: 960px; margin: 2rem auto; aspect-ratio: 16/9; diff --git a/examples/html-demo/src/frosted-eject.css b/examples/html-demo/src/frosted-eject.css index 6de40b6d..afc0372f 100644 --- a/examples/html-demo/src/frosted-eject.css +++ b/examples/html-demo/src/frosted-eject.css @@ -7,10 +7,11 @@ media-container { isolation: isolate; container: root / inline-size; overflow: clip; + border-radius: var(--vjs-border-radius, 2rem); + background: oklab(0 0 0); + font-family: var(--vjs-font-family, InterVariable, Inter, ui-sans-serif, system-ui, sans-serif); font-size: 0.8125rem; line-height: 1.5; - border-radius: inherit; - background: oklab(0 0 0); } media-container::before, media-container::after { @@ -204,8 +205,8 @@ media-mute-button .icon { } media-mute-button:not([data-volume-level]) .volume-low-icon, media-mute-button[data-volume-level='high'] .volume-high-icon, +media-mute-button[data-volume-level='medium'] .volume-high-icon, media-mute-button[data-volume-level='low'] .volume-low-icon, -media-mute-button[data-volume-level='medium'] .volume-low-icon, media-mute-button[data-volume-level='off'] .volume-off-icon { display: inline; } diff --git a/examples/html-demo/src/minimal-eject.css b/examples/html-demo/src/minimal-eject.css index 2bf66d50..8ae1486b 100644 --- a/examples/html-demo/src/minimal-eject.css +++ b/examples/html-demo/src/minimal-eject.css @@ -7,10 +7,11 @@ media-container { isolation: isolate; container: root / inline-size; overflow: clip; + border-radius: var(--vjs-border-radius, 2rem); + background: oklab(0 0 0); + font-family: var(--vjs-font-family, InterVariable, Inter, ui-sans-serif, system-ui, sans-serif); font-size: 0.8125rem; line-height: 1.5; - border-radius: inherit; - background: oklab(0 0 0); } media-container::after { content: ''; @@ -19,11 +20,11 @@ media-container::after { border-radius: inherit; z-index: 10; inset: 0; - box-shadow: inset 0 0 0 1px oklab(0 0 0 / 0.2); + box-shadow: inset 0 0 0 1px oklab(0 0 0 / 0.15); } @media (prefers-color-scheme: dark) { media-container::after { - box-shadow: inset 0 0 0 1px oklab(1 0 0 / 0.2); + box-shadow: inset 0 0 0 1px oklab(1 0 0 / 0.15); } } @@ -183,8 +184,8 @@ media-mute-button .icon { } media-mute-button:not([data-volume-level]) .volume-low-icon, media-mute-button[data-volume-level='high'] .volume-high-icon, +media-mute-button[data-volume-level='medium'] .volume-high-icon, media-mute-button[data-volume-level='low'] .volume-low-icon, -media-mute-button[data-volume-level='medium'] .volume-low-icon, media-mute-button[data-volume-level='off'] .volume-off-icon { display: inline; } diff --git a/examples/react-demo/package.json b/examples/react-demo/package.json index 42a8ad5f..343aca83 100644 --- a/examples/react-demo/package.json +++ b/examples/react-demo/package.json @@ -14,7 +14,6 @@ "clsx": "^2.1.1", "react": "^18.0.0", "react-dom": "^18.0.0", - "screenfull": "^6.0.2", "tailwindcss": "^4.1.13" }, "devDependencies": { diff --git a/examples/react-demo/src/App.tsx b/examples/react-demo/src/App.tsx index 68d8f7d4..148e2eab 100644 --- a/examples/react-demo/src/App.tsx +++ b/examples/react-demo/src/App.tsx @@ -1,10 +1,7 @@ import type { ChangeEventHandler } from 'react'; import { FrostedSkin, HlsVideo, MinimalSkin, VideoProvider } from '@videojs/react'; -import { FullscreenEnterAltIcon, FullscreenExitAltIcon } from '@videojs/react/icons'; -import clsx from 'clsx'; -import { useCallback, useMemo, useRef, useState } from 'react'; -import { useFullscreen } from './hooks/useFullscreen'; +import { useCallback, useMemo, useState } from 'react'; // NOTE: Commented out imports are for testing locally/externally defined skins. // import { VideoProvider, Video } from '@videojs/react'; @@ -45,22 +42,22 @@ type SkinKey = (typeof skins)[number]['key']; const mediaSources = [ { key: '1', - name: 'Mux 1', + name: 'Mux 1 (HLS)', value: 'https://stream.mux.com/fXNzVtmtWuyz00xnSrJg4OJH6PyNo6D02UzmgeKGkP5YQ.m3u8', }, { key: '2', - name: 'Mux 2', + name: 'Mux 2 (HLS)', value: 'https://stream.mux.com/a4nOgmxGWg6gULfcBbAa00gXyfcwPnAFldF8RdsNyk8M.m3u8', }, { key: '3', - name: 'Mux 3', + name: 'Mux 3 (MP4)', value: 'https://stream.mux.com/A3VXy02VoUinw01pwyomEO3bHnG4P32xzV7u1j1FSzjNg/high.mp4', }, { key: '4', - name: 'Mux 4', + name: 'Mux 4 (HLS)', value: 'https://stream.mux.com/lyrKpPcGfqyzeI00jZAfW6MvP6GNPrkML.m3u8', }, ] as const; @@ -85,8 +82,6 @@ const DEFAULT_MEDIA_SOURCE: MediaSourceKey = '1'; export default function App(): JSX.Element { const [skinKey, setSkinKey] = useState(() => getParam('skin', DEFAULT_SKIN)); const [mediaSourceKey, setMediaSourceKey] = useState(() => getParam('source', DEFAULT_MEDIA_SOURCE)); - const containerRef = useRef(null); - const { isFullscreen, toggle: toggleFullscreen } = useFullscreen(containerRef); const mediaSource = useMemo(() => { let match = mediaSources.find(m => m.key === mediaSourceKey); @@ -120,37 +115,12 @@ export default function App(): JSX.Element { // Force a re-render on changes. const key = `${skinKey}-${mediaSourceKey}`; - const skinClassName = useMemo(() => { - switch (skinKey) { - case 'frosted': - case 'frosted-eject': - return 'aspect-video !rounded-4xl shadow shadow-lg shadow-black/15'; - case 'minimal': - case 'minimal-eject': - return 'aspect-video !rounded-2xl shadow shadow-lg shadow-black/15'; - default: - return ''; - } - }, [skinKey]); - const playbackId = mediaSource.match(/stream\.mux\.com\/([^./]+)/)?.[1]; const poster = playbackId ? `https://image.mux.com/${playbackId}/thumbnail.webp` : undefined; return ( -
-
+
+
-
+
- + {/* @ts-expect-error -- types are incorrect */} diff --git a/examples/react-demo/src/hooks/useFullscreen.ts b/examples/react-demo/src/hooks/useFullscreen.ts deleted file mode 100644 index 94768ce5..00000000 --- a/examples/react-demo/src/hooks/useFullscreen.ts +++ /dev/null @@ -1,132 +0,0 @@ -import type { RefObject } from 'react'; -import { useCallback, useEffect, useState } from 'react'; -import screenfull from 'screenfull'; - -export interface UseFullscreenOptions { - /** - * When true, automatically handles fullscreen change events - * to synchronize the state with browser fullscreen status - * @default true - */ - trackChanges?: boolean; - /** - * Callback fired when fullscreen state changes - */ - onFullscreenChange?: (isFullscreen: boolean) => void; - /** - * Callback fired when fullscreen encounters an error - */ - onFullscreenError?: (error: Error) => void; -} - -export interface UseFullscreenResult { - /** - * Whether the element is currently in fullscreen mode - */ - isFullscreen: boolean; - /** - * Whether fullscreen is supported in the current environment - */ - isSupported: boolean; - /** - * Request fullscreen for the target element - * @returns Promise that resolves when fullscreen is entered - */ - enter: () => Promise; - /** - * Exit fullscreen mode - * @returns Promise that resolves when fullscreen is exited - */ - exit: () => Promise; - /** - * Toggle fullscreen mode for the target element - * @returns Promise that resolves when the toggle is complete - */ - toggle: () => Promise; -} - -/** - * Hook that provides fullscreen functionality for a DOM element - * - * @param elementRef - Ref to the element to make fullscreen - * @param options - Configuration options - * @returns Methods and state for managing fullscreen - */ -export function useFullscreen( - elementRef: RefObject, - options: UseFullscreenOptions = {}, -): UseFullscreenResult { - const { - trackChanges = true, - onFullscreenChange, - onFullscreenError, - } = options; - - const [isFullscreen, setIsFullscreen] = useState( - screenfull.isEnabled ? screenfull.isFullscreen : false, - ); - - // Handle fullscreen change events - useEffect(() => { - if (!screenfull.isEnabled || !trackChanges) return; - - const handleChange = () => { - const newIsFullscreen = screenfull.isFullscreen; - setIsFullscreen(newIsFullscreen); - onFullscreenChange?.(newIsFullscreen); - }; - - const handleError = () => { - onFullscreenError?.(new Error('Fullscreen error occurred')); - }; - - screenfull.on('change', handleChange); - screenfull.on('error', handleError); - - return () => { - screenfull.off('change', handleChange); - screenfull.off('error', handleError); - }; - }, [trackChanges, onFullscreenChange, onFullscreenError]); - - // Request fullscreen for the target element - const enter = useCallback(async (): Promise => { - if (!screenfull.isEnabled || !elementRef.current) return; - - try { - await screenfull.request(elementRef.current); - } catch (error) { - onFullscreenError?.(error instanceof Error ? error : new Error(String(error))); - } - }, [elementRef, onFullscreenError]); - - // Exit fullscreen mode - const exit = useCallback(async (): Promise => { - if (!screenfull.isEnabled) return; - - try { - await screenfull.exit(); - } catch (error) { - onFullscreenError?.(error instanceof Error ? error : new Error(String(error))); - } - }, [onFullscreenError]); - - // Toggle fullscreen mode for the target element - const toggle = useCallback(async (): Promise => { - if (!screenfull.isEnabled || !elementRef.current) return; - - try { - await screenfull.toggle(elementRef.current); - } catch (error) { - onFullscreenError?.(error instanceof Error ? error : new Error(String(error))); - } - }, [elementRef, onFullscreenError]); - - return { - isFullscreen, - isSupported: screenfull.isEnabled, - enter, - exit, - toggle, - }; -} diff --git a/examples/react-demo/src/skins/frosted-eject/frosted.css b/examples/react-demo/src/skins/frosted-eject/frosted.css index 6f018520..016b0ecf 100644 --- a/examples/react-demo/src/skins/frosted-eject/frosted.css +++ b/examples/react-demo/src/skins/frosted-eject/frosted.css @@ -7,10 +7,11 @@ isolation: isolate; container: root / inline-size; overflow: clip; + border-radius: var(--vjs-border-radius, 2rem); + background: oklab(0 0 0); + font-family: var(--vjs-font-family, InterVariable, Inter, ui-sans-serif, system-ui, sans-serif); font-size: 0.8125rem; line-height: 1.5; - border-radius: inherit; - background: oklab(0 0 0); } .vjs-frosted-skin::before, .vjs-frosted-skin::after { @@ -201,8 +202,8 @@ } .vjs-frosted-skin .mute-button:not([data-volume-level]) .volume-low-icon, .vjs-frosted-skin .mute-button[data-volume-level='high'] .volume-high-icon, +.vjs-frosted-skin .mute-button[data-volume-level='medium'] .volume-high-icon, .vjs-frosted-skin .mute-button[data-volume-level='low'] .volume-low-icon, -.vjs-frosted-skin .mute-button[data-volume-level='medium'] .volume-low-icon, .vjs-frosted-skin .mute-button[data-volume-level='off'] .volume-off-icon { display: inline; } diff --git a/examples/react-demo/src/skins/minimal-eject/minimal.css b/examples/react-demo/src/skins/minimal-eject/minimal.css index a31687bd..fb8500bb 100644 --- a/examples/react-demo/src/skins/minimal-eject/minimal.css +++ b/examples/react-demo/src/skins/minimal-eject/minimal.css @@ -7,10 +7,11 @@ isolation: isolate; container: root / inline-size; overflow: clip; + border-radius: var(--vjs-border-radius, 2rem); + background: oklab(0 0 0); + font-family: var(--vjs-font-family, InterVariable, Inter, ui-sans-serif, system-ui, sans-serif); font-size: 0.8125rem; line-height: 1.5; - border-radius: inherit; - background: oklab(0 0 0); } .vjs-minimal-skin::after { content: ''; @@ -19,11 +20,11 @@ border-radius: inherit; z-index: 10; inset: 0; - box-shadow: inset 0 0 0 1px oklab(0 0 0 / 0.2); + box-shadow: inset 0 0 0 1px oklab(0 0 0 / 0.15); } @media (prefers-color-scheme: dark) { .vjs-minimal-skin::after { - box-shadow: inset 0 0 0 1px oklab(1 0 0 / 0.2); + box-shadow: inset 0 0 0 1px oklab(1 0 0 / 0.15); } } @@ -180,8 +181,8 @@ } .vjs-minimal-skin .mute-button:not([data-volume-level]) .volume-low-icon, .vjs-minimal-skin .mute-button[data-volume-level='high'] .volume-high-icon, +.vjs-minimal-skin .mute-button[data-volume-level='medium'] .volume-high-icon, .vjs-minimal-skin .mute-button[data-volume-level='low'] .volume-low-icon, -.vjs-minimal-skin .mute-button[data-volume-level='medium'] .volume-low-icon, .vjs-minimal-skin .mute-button[data-volume-level='off'] .volume-off-icon { display: inline; } diff --git a/packages/html/src/skins/frosted/styles.css b/packages/html/src/skins/frosted/styles.css index 3ac262c5..912f57cb 100644 --- a/packages/html/src/skins/frosted/styles.css +++ b/packages/html/src/skins/frosted/styles.css @@ -7,10 +7,11 @@ media-container { isolation: isolate; container: root / inline-size; overflow: clip; + border-radius: var(--vjs-border-radius, 2rem); + background: oklab(0 0 0); + font-family: var(--vjs-font-family, InterVariable, Inter, ui-sans-serif, system-ui, sans-serif); font-size: 0.8125rem; line-height: 1.5; - border-radius: inherit; - background: oklab(0 0 0); } media-container::before, media-container::after { diff --git a/packages/html/src/skins/minimal/styles.css b/packages/html/src/skins/minimal/styles.css index 9668ffd7..d8367457 100644 --- a/packages/html/src/skins/minimal/styles.css +++ b/packages/html/src/skins/minimal/styles.css @@ -7,10 +7,11 @@ media-container { isolation: isolate; container: root / inline-size; overflow: clip; + border-radius: var(--vjs-border-radius, 0.75rem); + background: oklab(0 0 0); + font-family: var(--vjs-font-family, InterVariable, Inter, ui-sans-serif, system-ui, sans-serif); font-size: 0.8125rem; line-height: 1.5; - border-radius: inherit; - background: oklab(0 0 0); } media-container::after { content: ''; @@ -19,11 +20,11 @@ media-container::after { border-radius: inherit; z-index: 10; inset: 0; - box-shadow: inset 0 0 0 1px oklab(0 0 0 / 0.2); + box-shadow: inset 0 0 0 1px oklab(0 0 0 / 0.15); } @media (prefers-color-scheme: dark) { media-container::after { - box-shadow: inset 0 0 0 1px oklab(1 0 0 / 0.2); + box-shadow: inset 0 0 0 1px oklab(1 0 0 / 0.15); } } diff --git a/packages/react/src/skins/frosted/FrostedSkin.tsx b/packages/react/src/skins/frosted/FrostedSkin.tsx index 8a61c3d7..e4ec770a 100644 --- a/packages/react/src/skins/frosted/FrostedSkin.tsx +++ b/packages/react/src/skins/frosted/FrostedSkin.tsx @@ -33,12 +33,12 @@ export default function FrostedSkin({ children, className = '' }: SkinProps): JS
-
+
- - - + + + @@ -82,10 +82,10 @@ export default function FrostedSkin({ children, className = '' }: SkinProps): JS - - - - + + + + @@ -104,9 +104,9 @@ export default function FrostedSkin({ children, className = '' }: SkinProps): JS - - - + + + diff --git a/packages/react/src/skins/frosted/frosted-skin.css b/packages/react/src/skins/frosted/frosted-skin.css index 402243f1..f889ae15 100644 --- a/packages/react/src/skins/frosted/frosted-skin.css +++ b/packages/react/src/skins/frosted/frosted-skin.css @@ -3,6 +3,3 @@ @import 'tailwindcss/utilities.css' layer(utilities) prefix(vjs); /* Custom variants used by the frosted skin */ @custom-variant reduced-transparency @media (prefers-reduced-transparency: reduce); -.vjs { - font-family: inherit; -} diff --git a/packages/react/src/skins/frosted/styles.ts b/packages/react/src/skins/frosted/styles.ts index dedc109c..f506e15e 100644 --- a/packages/react/src/skins/frosted/styles.ts +++ b/packages/react/src/skins/frosted/styles.ts @@ -12,24 +12,25 @@ function cn(...classes: (string | undefined)[]): string { const styles: FrostedSkinStyles = { MediaContainer: cn( 'vjs', // Scope preflight - 'vjs:relative vjs:isolate vjs:@container/root vjs:group/root vjs:overflow-clip vjs:bg-black', + 'vjs:relative vjs:isolate vjs:@container/root vjs:group/root vjs:overflow-clip vjs:bg-black vjs:rounded-(--vjs-border-radius,2rem)', // Base typography - 'vjs:text-[0.8125rem]', // 13px - // Fancy borders. + 'vjs:text-[0.8125rem]', + // Fancy borders 'vjs:after:absolute vjs:after:inset-0 vjs:after:ring-black/10 vjs:after:ring-1 vjs:dark:after:ring-white/10 vjs:after:ring-inset vjs:after:z-10 vjs:after:pointer-events-none vjs:after:rounded-[inherit]', 'vjs:before:absolute vjs:before:inset-px vjs:before:rounded-[inherit] vjs:before:ring-white/15 vjs:before:ring-1 vjs:before:ring-inset vjs:before:z-10 vjs:before:pointer-events-none vjs:dark:before:ring-0', - // Prevent rounded corners in fullscreen. + // Prevent rounded corners in fullscreen 'vjs:[&:fullscreen]:rounded-none', - // Ensure the nested video inherits the radius. + // Ensure the nested video inherits the radius 'vjs:[&_video]:w-full vjs:[&_video]:h-full', ), Overlay: cn( 'vjs:opacity-0 vjs:delay-500 vjs:duration-300 vjs:rounded-[inherit] vjs:absolute vjs:inset-0 vjs:pointer-events-none vjs:bg-gradient-to-t vjs:from-black/50 vjs:via-black/20 vjs:to-transparent vjs:transition-opacity vjs:backdrop-saturate-150 vjs:backdrop-brightness-90', - // Hide when playing (for now). + // ------------------------------------ // FIXME: This is crude temporary logic, we'll improve it later I guess with a [data-show-controls] attribute or something? 'vjs:has-[+.controls_[data-paused]]:opacity-100 vjs:has-[+.controls_[data-paused]]:delay-0 vjs:has-[+.controls_[data-paused]]:duration-100', 'vjs:has-[+.controls_[aria-expanded="true"]]:opacity-100 vjs:has-[+.controls_[aria-expanded="true"]]:delay-0 vjs:has-[+.controls_[aria-expanded="true"]]:duration-100', 'vjs:group-hover/root:opacity-100 vjs:group-hover/root:delay-0 vjs:group-hover/root:duration-100', + // ------------------------------------ ), Surface: cn( 'vjs:bg-white/10 vjs:backdrop-blur-3xl vjs:backdrop-saturate-150 vjs:backdrop-brightness-90', @@ -44,18 +45,22 @@ const styles: FrostedSkinStyles = { 'vjs:contrast-more:bg-black/90 vjs:contrast-more:ring-black vjs:contrast-more:after:ring-white/20', ), Controls: cn( + // ------------------------------------ + // FIXME: Temporary className hook for above logic in the overlay. Can be removed once have a proper way to handle controls visibility. + 'controls', + // ------------------------------------ 'vjs:@container/controls vjs:absolute vjs:inset-x-3 vjs:bottom-3 vjs:rounded-full vjs:flex vjs:items-center vjs:p-1 vjs:gap-0.5 vjs:text-white', // Animation 'vjs:transition vjs:will-change-[transform,scale,filter,opacity] vjs:origin-bottom vjs:ease-out', - // FIXME: Temporary className hook for above logic in the overlay. Can be removed once have a proper way to handle controls visibility. - 'controls', - // FIXME: Temporary hide/show logic + // ------------------------------------ + // FIXME: Temporary hide/show logic, related to above. 'vjs:scale-90 vjs:opacity-0 vjs:blur-sm vjs:delay-500 vjs:duration-300', 'vjs:has-[[data-paused]]:scale-100 vjs:has-[[data-paused]]:opacity-100 vjs:has-[[data-paused]]:blur-none vjs:has-[[data-paused]]:delay-0 vjs:has-[[data-paused]]:duration-100', 'vjs:has-[[aria-expanded="true"]]:scale-100 vjs:has-[[aria-expanded="true"]]:opacity-100 vjs:has-[[aria-expanded="true"]]:blur-none vjs:has-[[aria-expanded="true"]]:delay-0 vjs:has-[[aria-expanded="true"]]:duration-100', 'vjs:group-hover/root:scale-100 vjs:group-hover/root:opacity-100 vjs:group-hover/root:blur-none vjs:group-hover/root:delay-0 vjs:group-hover/root:duration-100', + // ------------------------------------ ), - Icon: cn('icon'), + Icon: cn('icon vjs:[&_path]:transition-transform vjs:[&_path]:ease-out'), Button: cn( 'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition-[color,background,outline-offset] vjs:select-none vjs:p-2 vjs:rounded-full', // Background/foreground @@ -75,48 +80,32 @@ const styles: FrostedSkinStyles = { 'vjs:grid vjs:[&_.icon]:[grid-area:1/1]', 'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition-opacity vjs:[&_.icon]:duration-150 vjs:[&_.icon]:ease-linear vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/25', ), - PlayButton: cn( - 'vjs:[&_.pause-icon]:opacity-100 vjs:[&[data-paused]_.pause-icon]:opacity-0', - 'vjs:[&_.play-icon]:opacity-0 vjs:[&[data-paused]_.play-icon]:opacity-100', - ), - PlayIcon: cn('play-icon'), - PauseIcon: cn('pause-icon'), + PlayIcon: cn('vjs:opacity-0 vjs:group-data-paused/button:opacity-100'), + PauseIcon: cn('vjs:group-data-paused/button:opacity-0'), PlayTooltipPopup: cn( - 'vjs:[&_.pause-tooltip]:inline vjs:[&[data-paused]_.pause-tooltip]:hidden', - 'vjs:[&_.play-tooltip]:hidden vjs:[&[data-paused]_.play-tooltip]:inline', + 'vjs:[&_.pause-tooltip]:inline vjs:[&_.play-tooltip]:hidden', + 'vjs:data-paused:[&_.pause-tooltip]:hidden vjs:data-paused:[&_.play-tooltip]:inline', ), PlayTooltip: cn('play-tooltip'), PauseTooltip: cn('pause-tooltip'), - MuteButton: cn( - 'vjs:[&_.icon]:hidden', - 'vjs:[&[data-volume-level="high"]_.volume-high-icon]:inline', - 'vjs:[&[data-volume-level="medium"]_.volume-low-icon]:inline', - 'vjs:[&[data-volume-level="low"]_.volume-low-icon]:inline', - 'vjs:[&[data-volume-level="off"]_.volume-off-icon]:inline', - ), - VolumeHighIcon: cn('volume-high-icon'), - VolumeLowIcon: cn('volume-low-icon'), - VolumeOffIcon: cn('volume-off-icon'), - FullscreenButton: cn( - 'vjs:[&_.fullscreen-enter-icon]:opacity-100 vjs:[&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0', - 'vjs:[&_.fullscreen-exit-icon]:opacity-0 vjs:[&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100', - 'vjs:[&_path]:transition-transform vjs:ease-out', - ), + VolumeHighIcon: cn('vjs:hidden vjs:group-data-[volume-level=high]/button:inline vjs:group-data-[volume-level=medium]/button:inline'), + VolumeLowIcon: cn('vjs:hidden vjs:group-data-[volume-level=low]/button:inline'), + VolumeOffIcon: cn('vjs:hidden vjs:group-data-[volume-level=off]/button:inline'), FullscreenEnterIcon: cn( - 'fullscreen-enter-icon', + 'vjs:group-data-fullscreen/button:hidden', 'vjs:group-hover/button:[&_.arrow-1]:-translate-x-px vjs:group-hover/button:[&_.arrow-1]:-translate-y-px', 'vjs:group-hover/button:[&_.arrow-2]:translate-x-px vjs:group-hover/button:[&_.arrow-2]:translate-y-px', ), FullscreenExitIcon: cn( - 'fullscreen-exit-icon', + 'vjs:hidden vjs:group-data-fullscreen/button:inline', 'vjs:[&_.arrow-1]:-translate-x-px vjs:[&_.arrow-1]:-translate-y-px', 'vjs:[&_.arrow-2]:translate-x-px vjs:[&_.arrow-2]:translate-y-px', 'vjs:group-hover/button:[&_.arrow-1]:translate-0', 'vjs:group-hover/button:[&_.arrow-2]:translate-0', ), FullscreenTooltipPopup: cn( - 'vjs:[&_.fullscreen-enter-tooltip]:inline vjs:[&[data-fullscreen]_.fullscreen-enter-tooltip]:hidden', - 'vjs:[&_.fullscreen-exit-tooltip]:hidden vjs:[&[data-fullscreen]_.fullscreen-exit-tooltip]:inline', + 'vjs:[&_.fullscreen-enter-tooltip]:inline vjs:data-fullscreen:[&_.fullscreen-enter-tooltip]:hidden', + 'vjs:[&_.fullscreen-exit-tooltip]:hidden vjs:data-fullscreen:[&_.fullscreen-exit-tooltip]:inline', ), FullscreenEnterTooltip: cn('fullscreen-enter-tooltip'), FullscreenExitTooltip: cn('fullscreen-exit-tooltip'), @@ -124,13 +113,13 @@ const styles: FrostedSkinStyles = { TimeDisplay: cn('vjs:tabular-nums vjs:text-shadow-2xs/25'), SliderRoot: cn( 'vjs:group/slider vjs:outline-0 vjs:flex vjs:items-center vjs:justify-center vjs:flex-1 vjs:relative vjs:rounded-full', - 'vjs:[&[data-orientation="horizontal"]]:h-5 vjs:[&[data-orientation="horizontal"]]:min-w-20', - 'vjs:[&[data-orientation="vertical"]]:w-5 vjs:[&[data-orientation="vertical"]]:h-20', + 'vjs:data-[orientation=horizontal]:h-5 vjs:data-[orientation=horizontal]:min-w-20', + 'vjs:data-[orientation=vertical]:w-5 vjs:data-[orientation=vertical]:h-20', ), SliderTrack: cn( 'vjs:relative vjs:select-none vjs:transition-[outline-offset] vjs:rounded-[inherit] vjs:bg-white/20 vjs:ring-1 vjs:ring-black/5', - 'vjs:[&[data-orientation="horizontal"]]:w-full vjs:[&[data-orientation="horizontal"]]:h-1', - 'vjs:[&[data-orientation="vertical"]]:w-1', + 'vjs:data-[orientation=horizontal]:w-full vjs:data-[orientation=horizontal]:h-1', + 'vjs:data-[orientation=vertical]:w-1', 'vjs:-outline-offset-2 vjs:group-focus-visible/slider:outline-2 vjs:group-focus-visible/slider:outline-offset-6 vjs:group-focus-visible/slider:outline-blue-500', ), SliderProgress: cn('vjs:bg-white vjs:rounded-[inherit]'), @@ -140,22 +129,18 @@ const styles: FrostedSkinStyles = { 'vjs:bg-white vjs:z-10 vjs:select-none vjs:ring vjs:ring-black/10 vjs:rounded-full vjs:shadow-sm vjs:shadow-black/15 vjs:opacity-0 vjs:transition-[opacity,height,width] vjs:ease-out', 'vjs:group-hover/slider:opacity-100 vjs:group-focus-within/slider:opacity-100', 'vjs:size-2.5 vjs:active:size-3 vjs:group-active/slider:size-3', - 'vjs:[&[data-orientation="horizontal"]]:hover:cursor-ew-resize', - 'vjs:[&[data-orientation="vertical"]]:hover:cursor-ns-resize', + 'vjs:data-[orientation=horizontal]:hover:cursor-ew-resize', + 'vjs:data-[orientation=vertical]:hover:cursor-ns-resize', ), PopupAnimation: cn( // Animation // XXX: We can't use transforms since floating UI uses them for positioning. - 'vjs:transition-[transform,scale,opacity,filter] vjs:origin-bottom vjs:duration-200 vjs:data-[instant]:duration-0', - 'vjs:data-[starting-style]:scale-0 vjs:data-[starting-style]:opacity-0 vjs:data-[starting-style]:blur-sm', - 'vjs:data-[ending-style]:scale-0 vjs:data-[ending-style]:opacity-0 vjs:data-[ending-style]:blur-sm', - ), - PopoverPopup: cn( - 'vjs:relative vjs:px-1 vjs:py-3 vjs:rounded-full', - ), - TooltipPopup: cn( - 'vjs:whitespace-nowrap vjs:rounded-full vjs:text-white vjs:text-xs vjs:@7xl/root:text-sm vjs:px-2.5 vjs:py-1', + 'vjs:transition-[transform,scale,opacity,filter] vjs:origin-bottom vjs:duration-200 vjs:data-instant:duration-0', + 'vjs:data-starting-style:scale-0 vjs:data-starting-style:opacity-0 vjs:data-starting-style:blur-sm', + 'vjs:data-ending-style:scale-0 vjs:data-ending-style:opacity-0 vjs:data-ending-style:blur-sm', ), + PopoverPopup: cn('vjs:relative vjs:px-1 vjs:py-3 vjs:rounded-full'), + TooltipPopup: cn('vjs:whitespace-nowrap vjs:rounded-full vjs:text-white vjs:text-xs vjs:@7xl/root:text-sm vjs:px-2.5 vjs:py-1'), }; /* diff --git a/packages/react/src/skins/frosted/types.ts b/packages/react/src/skins/frosted/types.ts index b42654ce..734f3c54 100644 --- a/packages/react/src/skins/frosted/types.ts +++ b/packages/react/src/skins/frosted/types.ts @@ -6,17 +6,14 @@ export interface FrostedSkinStyles { readonly Icon: string; readonly Button: string; readonly IconButton: string; - readonly PlayButton: string; readonly PlayIcon: string; readonly PauseIcon: string; readonly PlayTooltipPopup: string; readonly PlayTooltip: string; readonly PauseTooltip: string; - readonly MuteButton: string; readonly VolumeHighIcon: string; readonly VolumeLowIcon: string; readonly VolumeOffIcon: string; - readonly FullscreenButton: string; readonly FullscreenEnterIcon: string; readonly FullscreenExitIcon: string; readonly FullscreenTooltipPopup: string; diff --git a/packages/react/src/skins/minimal/MinimalSkin.tsx b/packages/react/src/skins/minimal/MinimalSkin.tsx index 161ced61..add81185 100644 --- a/packages/react/src/skins/minimal/MinimalSkin.tsx +++ b/packages/react/src/skins/minimal/MinimalSkin.tsx @@ -36,9 +36,9 @@ export default function MinimalSkin({ children, className = '' }: SkinProps): JS
- - - + + + @@ -86,10 +86,10 @@ export default function MinimalSkin({ children, className = '' }: SkinProps): JS
- - - - + + + + @@ -108,9 +108,9 @@ export default function MinimalSkin({ children, className = '' }: SkinProps): JS - - - + + + diff --git a/packages/react/src/skins/minimal/minimal-skin.css b/packages/react/src/skins/minimal/minimal-skin.css index 833a93dc..9e59a062 100644 --- a/packages/react/src/skins/minimal/minimal-skin.css +++ b/packages/react/src/skins/minimal/minimal-skin.css @@ -1,6 +1,3 @@ @layer theme, base, components, utilities; @import 'tailwindcss/theme.css' layer(theme) prefix(vjs); @import 'tailwindcss/utilities.css' layer(utilities) prefix(vjs); -.vjs { - font-family: inherit; -} diff --git a/packages/react/src/skins/minimal/styles.ts b/packages/react/src/skins/minimal/styles.ts index 86cc82ca..6cabf86b 100644 --- a/packages/react/src/skins/minimal/styles.ts +++ b/packages/react/src/skins/minimal/styles.ts @@ -12,38 +12,46 @@ function cn(...classes: (string | undefined)[]): string { const styles: MinimalSkinStyles = { MediaContainer: cn( 'vjs', // Scope preflight - 'vjs:relative vjs:isolate vjs:@container/root vjs:group/root vjs:overflow-clip vjs:bg-black', + 'vjs:relative vjs:isolate vjs:@container/root vjs:group/root vjs:overflow-clip vjs:bg-black vjs:rounded-(--vjs-border-radius,0.75rem)', // Base typography - 'vjs:text-[0.8125rem]', // 13px - 'vjs:after:absolute vjs:after:inset-0 vjs:after:ring-black/20 vjs:after:ring-1 vjs:dark:after:ring-white/20 vjs:after:ring-inset vjs:after:z-10 vjs:after:pointer-events-none vjs:after:rounded-[inherit]', - // Prevent rounded corners in fullscreen. + 'vjs:text-[0.8125rem]', + // Fancy borders + 'vjs:after:absolute vjs:after:inset-0 vjs:after:ring-black/15 vjs:after:ring-1 vjs:dark:after:ring-white/15 vjs:after:ring-inset vjs:after:z-10 vjs:after:pointer-events-none vjs:after:rounded-[inherit]', + // Prevent rounded corners in fullscreen 'vjs:[&:fullscreen]:rounded-none', - // Ensure the nested video inherits the radius. + // Ensure the nested video inherits the radius 'vjs:[&_video]:w-full vjs:[&_video]:h-full', ), Overlay: cn( 'vjs:absolute vjs:inset-0 vjs:rounded-[inherit] vjs:pointer-events-none', 'vjs:bg-gradient-to-t vjs:from-black/70 vjs:via-black/50 vjs:via-[7.5rem] vjs:to-transparent', 'vjs:opacity-0 vjs:delay-500 vjs:duration-300', + // High contrast mode + 'vjs:contrast-more:from-black/75', + // ------------------------------------ // FIXME: Temporary hide/show logic 'vjs:has-[+.controls_[data-paused]]:opacity-100 vjs:has-[+.controls_[data-paused]]:delay-0 vjs:has-[+.controls_[data-paused]]:duration-75', 'vjs:has-[+.controls_[aria-expanded="true"]]:opacity-100 vjs:has-[+.controls_[aria-expanded="true"]]:delay-0 vjs:has-[+.controls_[aria-expanded="true"]]:duration-75', 'vjs:group-hover/root:opacity-100 vjs:group-hover/root:delay-0 vjs:group-hover/root:duration-75', - // High contrast mode - 'vjs:contrast-more:from-black/75', + // ------------------------------------ ), Controls: cn( - 'controls', // FIXME: Temporary className hook for above logic in the overlay. Can be removed once have a proper way to handle controls visibility. + // ------------------------------------ + // FIXME: Temporary className hook for above logic in the overlay. Can be removed once have a proper way to handle controls visibility. + 'controls', + // ------------------------------------ 'vjs:@container/controls vjs:absolute vjs:inset-x-0 vjs:bottom-0 vjs:flex vjs:items-center vjs:gap-3.5 vjs:z-20 vjs:px-3 vjs:pb-3 vjs:pt-10 vjs:text-white', // Animation 'vjs:transition vjs:will-change-[transform,filter,opacity] vjs:ease-out', + // ------------------------------------ // FIXME: Temporary hide/show logic 'vjs:translate-y-full vjs:opacity-0 vjs:blur-sm vjs:delay-500 vjs:duration-300', 'vjs:has-[[data-paused]]:translate-y-0 vjs:has-[[data-paused]]:opacity-100 vjs:has-[[data-paused]]:blur-none vjs:has-[[data-paused]]:delay-0 vjs:has-[[data-paused]]:duration-75', 'vjs:has-[[aria-expanded="true"]]:translate-y-0 vjs:has-[[aria-expanded="true"]]:opacity-100 vjs:has-[[aria-expanded="true"]]:blur-none vjs:has-[[aria-expanded="true"]]:delay-0 vjs:has-[[aria-expanded="true"]]:duration-75', 'vjs:group-hover/root:translate-y-0 vjs:group-hover/root:opacity-100 vjs:group-hover/root:blur-none vjs:group-hover/root:delay-0 vjs:group-hover/root:duration-75', + // ------------------------------------ ), - Icon: cn('icon'), + Icon: cn('icon vjs:[&_path]:transition-transform vjs:[&_path]:ease-out'), TimeDisplayGroup: cn('flex items-center gap-1'), Button: cn( 'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition-[color,background,outline-offset] vjs:select-none vjs:p-2.5 vjs:rounded-md', @@ -65,48 +73,32 @@ const styles: MinimalSkinStyles = { 'vjs:grid vjs:[&_.icon]:[grid-area:1/1]', 'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition-opacity vjs:[&_.icon]:duration-150 vjs:[&_.icon]:ease-linear vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/40', ), - PlayButton: cn( - 'vjs:[&_.pause-icon]:opacity-100 vjs:[&[data-paused]_.pause-icon]:opacity-0', - 'vjs:[&_.play-icon]:opacity-0 vjs:[&[data-paused]_.play-icon]:opacity-100', - ), - PlayIcon: cn('play-icon'), - PauseIcon: cn('pause-icon'), + PlayIcon: cn('vjs:opacity-0 vjs:group-data-paused/button:opacity-100'), + PauseIcon: cn('vjs:group-data-paused/button:opacity-0'), PlayTooltipPopup: cn( - 'vjs:[&_.pause-tooltip]:inline vjs:[&[data-paused]_.pause-tooltip]:hidden', - 'vjs:[&_.play-tooltip]:hidden vjs:[&[data-paused]_.play-tooltip]:inline', + 'vjs:[&_.pause-tooltip]:inline vjs:data-paused:[&_.pause-tooltip]:hidden', + 'vjs:[&_.play-tooltip]:hidden vjs:data-paused:[&_.play-tooltip]:inline', ), PlayTooltip: cn('play-tooltip'), PauseTooltip: cn('pause-tooltip'), - MuteButton: cn( - 'vjs:[&_.icon]:hidden', - 'vjs:[&[data-volume-level="high"]_.volume-high-icon]:inline', - 'vjs:[&[data-volume-level="medium"]_.volume-low-icon]:inline', - 'vjs:[&[data-volume-level="low"]_.volume-low-icon]:inline', - 'vjs:[&[data-volume-level="off"]_.volume-off-icon]:inline', - ), - VolumeHighIcon: cn('volume-high-icon'), - VolumeLowIcon: cn('volume-low-icon'), - VolumeOffIcon: cn('volume-off-icon'), - FullscreenButton: cn( - 'vjs:[&_.fullscreen-enter-icon]:opacity-100 vjs:[&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0', - 'vjs:[&_.fullscreen-exit-icon]:opacity-0 vjs:[&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100', - 'vjs:[&_path]:transition-transform vjs:ease-out', - ), + VolumeHighIcon: cn('vjs:hidden vjs:group-data-[volume-level=high]/button:inline vjs:group-data-[volume-level=medium]/button:inline'), + VolumeLowIcon: cn('vjs:hidden vjs:group-data-[volume-level=low]/button:inline'), + VolumeOffIcon: cn('vjs:hidden vjs:group-data-[volume-level=off]/button:inline'), FullscreenEnterIcon: cn( - 'fullscreen-enter-icon', + 'vjs:group-data-fullscreen/button:hidden', 'vjs:group-hover/button:[&_.arrow-1]:translate-x-px vjs:group-hover/button:[&_.arrow-1]:-translate-y-px', 'vjs:group-hover/button:[&_.arrow-2]:-translate-x-px vjs:group-hover/button:[&_.arrow-2]:translate-y-px', ), FullscreenExitIcon: cn( - 'fullscreen-exit-icon', + 'vjs:hidden vjs:group-data-fullscreen/button:inline', 'vjs:[&_.arrow-1]:translate-x-px vjs:[&_.arrow-1]:-translate-y-px', 'vjs:[&_.arrow-2]:-translate-x-px vjs:[&_.arrow-2]:translate-y-px', 'vjs:group-hover/button:[&_.arrow-1]:translate-0', 'vjs:group-hover/button:[&_.arrow-2]:translate-0', ), FullscreenTooltipPopup: cn( - 'vjs:[&_.fullscreen-enter-tooltip]:inline vjs:[&[data-fullscreen]_.fullscreen-enter-tooltip]:hidden', - 'vjs:[&_.fullscreen-exit-tooltip]:hidden vjs:[&[data-fullscreen]_.fullscreen-exit-tooltip]:inline', + 'vjs:[&_.fullscreen-enter-tooltip]:inline vjs:data-fullscreen:[&_.fullscreen-enter-tooltip]:hidden', + 'vjs:[&_.fullscreen-exit-tooltip]:hidden vjs:data-fullscreen:[&_.fullscreen-exit-tooltip]:inline', ), FullscreenEnterTooltip: cn('fullscreen-enter-tooltip'), FullscreenExitTooltip: cn('fullscreen-exit-tooltip'), @@ -115,13 +107,13 @@ const styles: MinimalSkinStyles = { DurationDisplay: cn('vjs:text-white/50 vjs:contents'), SliderRoot: cn( 'vjs:group/slider vjs:outline-0 vjs:flex vjs:items-center vjs:justify-center vjs:flex-1 vjs:group/slider vjs:relative vjs:rounded-full', - 'vjs:[&[data-orientation="horizontal"]]:h-5 vjs:[&[data-orientation="horizontal"]]:min-w-20', - 'vjs:[&[data-orientation="vertical"]]:w-5 vjs:[&[data-orientation="vertical"]]:h-18', + 'vjs:data-[orientation=horizontal]:h-5 vjs:data-[orientation=horizontal]:min-w-20', + 'vjs:data-[orientation=vertical]:w-5 vjs:data-[orientation=vertical]:h-18', ), SliderTrack: cn( 'vjs:relative vjs:select-none vjs:rounded-[inherit] vjs:bg-white/10', - 'vjs:[&[data-orientation="horizontal"]]:w-full vjs:[&[data-orientation="horizontal"]]:h-[0.1875rem]', - 'vjs:[&[data-orientation="vertical"]]:w-[0.1875rem]', + 'vjs:data-[orientation=horizontal]:w-full vjs:data-[orientation=horizontal]:h-[0.1875rem]', + 'vjs:data-[orientation=vertical]:w-[0.1875rem]', 'vjs:-outline-offset-2 vjs:group-focus-visible/slider:outline-2 vjs:group-focus-visible/slider:outline-offset-6 vjs:group-focus-visible/slider:outline-white', ), SliderProgress: cn('vjs:bg-white vjs:rounded-[inherit]'), @@ -129,19 +121,17 @@ const styles: MinimalSkinStyles = { SliderThumb: cn( 'vjs:bg-white vjs:z-10 vjs:size-3 vjs:select-none vjs:ring vjs:ring-black/10 vjs:rounded-full vjs:shadow-sm vjs:shadow-black/15 vjs:transition-[opacity,scale] vjs:ease-out vjs:opacity-0 vjs:scale-70 vjs:origin-center', 'vjs:group-hover/slider:opacity-100 vjs:group-hover/slider:scale-100', - 'vjs:[&[data-orientation="horizontal"]]:hover:cursor-ew-resize', - 'vjs:[&[data-orientation="vertical"]]:hover:cursor-ns-resize', + 'vjs:data-[orientation=horizontal]:hover:cursor-ew-resize', + 'vjs:data-[orientation=vertical]:hover:cursor-ns-resize', ), PopupAnimation: cn( // Animation // XXX: We can't use transforms since floating UI uses them for positioning. - 'vjs:transition-[transform,scale,opacity,filter] vjs:origin-bottom vjs:duration-200 vjs:data-[instant]:duration-0', - 'vjs:data-[starting-style]:scale-0 vjs:data-[starting-style]:opacity-0 vjs:data-[starting-style]:blur-sm', - 'vjs:data-[ending-style]:scale-0 vjs:data-[ending-style]:opacity-0 vjs:data-[ending-style]:blur-sm', - ), - PopoverPopup: cn( - 'vjs:py-2', + 'vjs:transition-[transform,scale,opacity,filter] vjs:origin-bottom vjs:duration-200 vjs:data-instant:duration-0', + 'vjs:data-starting-style:scale-0 vjs:data-starting-style:opacity-0 vjs:data-starting-style:blur-sm', + 'vjs:data-ending-style:scale-0 vjs:data-ending-style:opacity-0 vjs:data-ending-style:blur-sm', ), + PopoverPopup: cn('vjs:py-2'), TooltipPopup: cn( 'vjs:whitespace-nowrap vjs:flex vjs:flex-col vjs:rounded vjs:text-white vjs:text-xs vjs:@7xl/root:text-sm vjs:px-2 vjs:py-1 vjs:bg-white/20 vjs:backdrop-blur-3xl vjs:backdrop-saturate-150 vjs:backdrop-brightness-90 vjs:shadow-md vjs:shadow-black/5', ), diff --git a/packages/react/src/skins/minimal/types.ts b/packages/react/src/skins/minimal/types.ts index babbc62c..6d1f8301 100644 --- a/packages/react/src/skins/minimal/types.ts +++ b/packages/react/src/skins/minimal/types.ts @@ -6,17 +6,14 @@ export interface MinimalSkinStyles { readonly Button: string; readonly ButtonGroup: string; readonly IconButton: string; - readonly PlayButton: string; readonly PlayIcon: string; readonly PauseIcon: string; readonly PlayTooltipPopup: string; readonly PlayTooltip: string; readonly PauseTooltip: string; - readonly MuteButton: string; readonly VolumeHighIcon: string; readonly VolumeLowIcon: string; readonly VolumeOffIcon: string; - readonly FullscreenButton: string; readonly FullscreenEnterIcon: string; readonly FullscreenExitIcon: string; readonly FullscreenTooltipPopup: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33916796..224ce2a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,9 +151,6 @@ importers: react-dom: specifier: ^18.0.0 version: 18.3.1(react@18.3.1) - screenfull: - specifier: ^6.0.2 - version: 6.0.2 tailwindcss: specifier: ^4.1.13 version: 4.1.14 @@ -237,7 +234,7 @@ importers: dependencies: '@floating-ui/react': specifier: ^0.27.16 - version: 0.27.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 0.27.16(react-dom@19.2.0(react@18.3.1))(react@18.3.1) '@videojs/core': specifier: workspace:* version: link:../core @@ -5605,10 +5602,6 @@ packages: schema-dts@1.1.5: resolution: {integrity: sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==} - screenfull@6.0.2: - resolution: {integrity: sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw==} - engines: {node: ^14.13.1 || >=16.0.0} - scslre@0.3.0: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} @@ -7411,12 +7404,18 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@floating-ui/react@0.27.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/dom': 1.7.4 + react: 18.3.1 + react-dom: 19.2.0(react@18.3.1) + + '@floating-ui/react@0.27.16(react-dom@19.2.0(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@18.3.1))(react@18.3.1) '@floating-ui/utils': 0.2.10 react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.2.0(react@18.3.1) tabbable: 6.2.0 '@floating-ui/utils@0.2.10': {} @@ -9775,7 +9774,7 @@ snapshots: eslint: 9.37.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.37.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.37.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.37.0(jiti@2.6.1)) @@ -9817,7 +9816,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -9893,7 +9892,7 @@ snapshots: optionalDependencies: typescript: 5.9.2 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.37.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -12392,6 +12391,11 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-dom@19.2.0(react@18.3.1): + dependencies: + react: 18.3.1 + scheduler: 0.27.0 + react-dom@19.2.0(react@19.2.0): dependencies: react: 19.2.0 @@ -12775,8 +12779,6 @@ snapshots: schema-dts@1.1.5: {} - screenfull@6.0.2: {} - scslre@0.3.0: dependencies: '@eslint-community/regexpp': 4.12.1