diff --git a/examples/html-demo/frosted-eject.html b/examples/html-demo/frosted-eject.html index 6fc81660..b24883a4 100644 --- a/examples/html-demo/frosted-eject.html +++ b/examples/html-demo/frosted-eject.html @@ -35,9 +35,9 @@ >
diff --git a/examples/html-demo/minimal-eject.html b/examples/html-demo/minimal-eject.html index d894a924..f72ac378 100644 --- a/examples/html-demo/minimal-eject.html +++ b/examples/html-demo/minimal-eject.html @@ -35,9 +35,9 @@ >
diff --git a/examples/html-demo/src/frosted-eject.ts b/examples/html-demo/src/frosted-eject.ts index 8d60c4d8..6c4f1ad6 100644 --- a/examples/html-demo/src/frosted-eject.ts +++ b/examples/html-demo/src/frosted-eject.ts @@ -1,6 +1,6 @@ import './frosted-eject.css'; import '@videojs/html/icons'; -// be sure to import video-provider first +// be sure to import video-provider first for proper context initialization import '@videojs/html/define/video-provider'; import '@videojs/html/define/media-container'; import '@videojs/html/define/media-play-button'; diff --git a/examples/html-demo/src/minimal-eject.ts b/examples/html-demo/src/minimal-eject.ts index a0d011e5..1dbbdc1c 100644 --- a/examples/html-demo/src/minimal-eject.ts +++ b/examples/html-demo/src/minimal-eject.ts @@ -1,6 +1,6 @@ import './minimal-eject.css'; import '@videojs/html/icons'; -// be sure to import video-provider first +// be sure to import video-provider first for proper context initialization import '@videojs/html/define/video-provider'; import '@videojs/html/define/media-container'; import '@videojs/html/define/media-play-button'; diff --git a/packages/html/package.json b/packages/html/package.json index f83f5347..a9c5fc18 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -52,8 +52,6 @@ "clean": "rm -rf dist" }, "dependencies": { - "@floating-ui/core": "^1.6.13", - "@floating-ui/dom": "^1.6.13", "@open-wc/context-protocol": "^0.0.9", "@videojs/core": "workspace:*", "@videojs/icons": "workspace:*", diff --git a/packages/html/src/define/index.ts b/packages/html/src/define/index.ts index af271e41..239d0bed 100644 --- a/packages/html/src/define/index.ts +++ b/packages/html/src/define/index.ts @@ -1,5 +1,6 @@ -import './media-container'; +// be sure to import video-provider first for proper context initialization import './video-provider'; +import './media-container'; import './media-play-button'; import './media-mute-button'; import './media-volume-slider'; diff --git a/packages/html/src/elements/button.ts b/packages/html/src/elements/button.ts index d2d1521b..be72c1ba 100644 --- a/packages/html/src/elements/button.ts +++ b/packages/html/src/elements/button.ts @@ -27,6 +27,8 @@ export class ButtonElement extends HTMLElement { static getTemplateHTML: typeof getTemplateHTML = getTemplateHTML; + static observedAttributes: string[] = ['commandfor']; + constructor() { super(); @@ -46,6 +48,12 @@ export class ButtonElement extends HTMLElement { this.addEventListener('keydown', this); } + attributeChangedCallback(name: string, _oldValue: string, newValue: string): void { + if (name === 'commandfor') { + this.style.setProperty('anchor-name', `--${newValue}`); + } + } + handleEvent(event: Event): void { const { type } = event; if (type === 'keydown') { diff --git a/packages/html/src/elements/popover.ts b/packages/html/src/elements/popover.ts index c47c82b1..ccb848c3 100644 --- a/packages/html/src/elements/popover.ts +++ b/packages/html/src/elements/popover.ts @@ -1,26 +1,27 @@ -import type { ComputePositionReturn } from '@floating-ui/core'; -import type { Placement } from '@floating-ui/dom'; -import { autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom'; import { contains, getDocument, getDocumentOrShadowRoot, safePolygon } from '@videojs/utils/dom'; -type Prettify = { - [K in keyof T]: T[K]; -}; - -type FloatingContext = Prettify & { - elements: { - domReference: HTMLElement; - floating: HTMLElement; - }; -}; +type Placement = 'top' | 'bottom' | 'left' | 'right'; export class PopoverElement extends HTMLElement { + static get observedAttributes(): string[] { + return ['id', 'open-on-hover', 'delay', 'close-delay', 'side', 'side-offset']; + } + #open = false; #transitionStatus: 'initial' | 'open' | 'close' | 'unmounted' = 'initial'; #hoverTimeout: ReturnType | null = null; #cleanup: (() => void) | null = null; #abortController: AbortController | null = null; - #floatingContext: FloatingContext | null = null; + + attributeChangedCallback(name: string, _oldValue: string, newValue: string): void { + if (name === 'id') { + this.style.setProperty('position-anchor', `--${newValue}`); + } + + this.style.setProperty('top', `calc(anchor(${this.side}) - ${this.sideOffset}px)`); + this.style.setProperty('translate', `0 -100%`); + this.style.setProperty('justify-self', 'anchor-center'); + } connectedCallback(): void { this.#abortController ??= new AbortController(); @@ -71,10 +72,6 @@ export class PopoverElement extends HTMLElement { } } - static get observedAttributes(): string[] { - return ['open-on-hover', 'delay', 'close-delay', 'side', 'side-offset']; - } - get openOnHover(): boolean { return this.hasAttribute('open-on-hover'); } @@ -105,8 +102,6 @@ export class PopoverElement extends HTMLElement { this.#open = open; if (open) { - this.#setupFloating(); - this.#transitionStatus = 'initial'; this.#updateVisibility(); @@ -141,38 +136,6 @@ export class PopoverElement extends HTMLElement { this.toggleAttribute('data-closed', this.#transitionStatus === 'close' || this.#transitionStatus === 'unmounted'); } - #setupFloating(): void { - const trigger = this.#triggerElement as HTMLElement; - if (!trigger) return; - - const placement = this.side ?? 'top'; - const sideOffset = this.sideOffset; - - const updatePosition = () => { - computePosition(trigger, this, { - placement, - middleware: [offset(sideOffset), flip(), shift()], - strategy: 'fixed', - }).then((data: ComputePositionReturn) => { - this.#floatingContext = { - ...data, - elements: { - domReference: trigger, - floating: this, - }, - }; - - Object.assign(this.style, { - left: `${data.x}px`, - top: `${data.y}px`, - }); - }); - }; - - updatePosition(); - this.#cleanup = autoUpdate(trigger, this, updatePosition); - } - #clearHoverTimeout(): void { if (this.#hoverTimeout) { globalThis.clearTimeout(this.#hoverTimeout); @@ -210,10 +173,14 @@ export class PopoverElement extends HTMLElement { } #handlePointerMove(event: PointerEvent): void { - if (!this.openOnHover || !this.#floatingContext) return; + if (!this.openOnHover || !this.#triggerElement) return; const close = safePolygon({ blockPointerEvents: true })({ - ...this.#floatingContext, + placement: this.side, + elements: { + domReference: this.#triggerElement, + floating: this, + }, x: event.clientX, y: event.clientY, onClose: () => { diff --git a/packages/html/src/elements/time-slider.ts b/packages/html/src/elements/time-slider.ts index 3fe0f3f8..44cf6b14 100644 --- a/packages/html/src/elements/time-slider.ts +++ b/packages/html/src/elements/time-slider.ts @@ -50,7 +50,7 @@ export const getTimeSliderRootProps: PropsHook<{ }; export class TimeSliderRoot extends HTMLElement { - static readonly observedAttributes: readonly string[] = ['orientation']; + static readonly observedAttributes: readonly string[] = ['commandfor', 'orientation']; _state: TimeSliderRootState | undefined; _core: CoreTimeSlider | null = null; @@ -67,9 +67,11 @@ export class TimeSliderRoot extends HTMLElement { return (this.getAttribute('orientation') as 'horizontal' | 'vertical') || 'horizontal'; } - attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void { + attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void { if (name === 'orientation' && this._state) { this._render(getTimeSliderRootProps(this._state, this), this._state); + } else if (name === 'commandfor') { + this.style.setProperty('anchor-name', `--${newValue}`); } } diff --git a/packages/html/src/elements/tooltip.ts b/packages/html/src/elements/tooltip.ts index a79965f6..2bafbf30 100644 --- a/packages/html/src/elements/tooltip.ts +++ b/packages/html/src/elements/tooltip.ts @@ -1,18 +1,46 @@ -import type { Placement } from '@floating-ui/dom'; import type { MediaContainerElement } from '@/media/media-container'; -import { arrow, autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom'; -import { getDocumentOrShadowRoot } from '@videojs/utils/dom'; +import { + getBoundingClientRectWithoutTransform, + getDocumentOrShadowRoot, + getInBoundsAdjustments, +} from '@videojs/utils/dom'; + +type Placement = 'top' | 'bottom' | 'left' | 'right'; export class TooltipElement extends HTMLElement { + static get observedAttributes(): string[] { + return ['id', 'delay', 'close-delay', 'track-cursor-axis', 'side', 'side-offset', 'collision-padding']; + } + #open = false; #hoverTimeout: ReturnType | null = null; - #cleanup: (() => void) | null = null; - #arrowElement: HTMLElement | null = null; #pointerPosition = { x: 0, y: 0 }; #transitionStatus: 'initial' | 'open' | 'close' | 'unmounted' = 'initial'; #abortController: AbortController | null = null; + constructor() { + super(); + + const resizeObserver = new ResizeObserver(() => this.#checkCollision()); + resizeObserver.observe(this); + } + + attributeChangedCallback(name: string, _oldValue: string, newValue: string): void { + if (name === 'id') { + this.style.setProperty('position-anchor', `--${newValue}`); + } + + this.style.setProperty('top', `calc(anchor(${this.side}) - ${this.sideOffset}px)`); + + if (this.trackCursorAxis) { + this.style.setProperty('translate', `-50% -100%`); + } else { + this.style.setProperty('translate', `0 -100%`); + this.style.setProperty('justify-self', 'anchor-center'); + } + } + connectedCallback(): void { this.setAttribute('role', 'tooltip'); @@ -33,7 +61,6 @@ export class TooltipElement extends HTMLElement { disconnectedCallback(): void { this.#clearHoverTimeout(); - this.#cleanup?.(); this.#abortController?.abort(); this.#abortController = null; @@ -57,10 +84,6 @@ export class TooltipElement extends HTMLElement { } } - static get observedAttributes(): string[] { - return ['delay', 'close-delay', 'track-cursor-axis', 'side', 'side-offset', 'collision-padding']; - } - get delay(): number { return Number.parseInt(this.getAttribute('delay') ?? '0', 10); } @@ -96,8 +119,6 @@ export class TooltipElement extends HTMLElement { this.#open = open; if (open) { - this.#setupFloating(); - this.#transitionStatus = 'initial'; this.#updateVisibility(); @@ -106,6 +127,7 @@ export class TooltipElement extends HTMLElement { requestAnimationFrame(() => { this.#transitionStatus = 'open'; this.#updateVisibility(); + this.#checkCollision(); }); } else { this.#transitionStatus = 'close'; @@ -119,16 +141,16 @@ export class TooltipElement extends HTMLElement { } else { this.hidePopover(); } - - this.#cleanup?.(); - this.#cleanup = null; } } #updateVisibility(): void { this.toggleAttribute('data-starting-style', this.#transitionStatus === 'initial'); this.toggleAttribute('data-open', this.#transitionStatus === 'initial' || this.#transitionStatus === 'open'); - this.toggleAttribute('data-ending-style', this.#transitionStatus === 'close' || this.#transitionStatus === 'unmounted'); + this.toggleAttribute( + 'data-ending-style', + this.#transitionStatus === 'close' || this.#transitionStatus === 'unmounted', + ); this.toggleAttribute('data-closed', this.#transitionStatus === 'close' || this.#transitionStatus === 'unmounted'); const triggerElement = this.#triggerElement as HTMLElement; @@ -137,105 +159,34 @@ export class TooltipElement extends HTMLElement { } } - #setupFloating(): void { - const trigger = this.#triggerElement as HTMLElement; - if (!trigger) return; - - const placement = this.side; - const sideOffset = this.sideOffset; - const collisionPadding = this.collisionPadding; - const mediaContainer = this.closest('media-container') as MediaContainerElement; - - this.#arrowElement = this.querySelector('media-tooltip-arrow') as HTMLElement; - - const updatePosition = () => { - const middleware = [ - offset(sideOffset), - flip(), - shift({ - boundary: mediaContainer, - padding: collisionPadding, - }), - ]; - - if (this.#arrowElement) { - middleware.push(arrow({ element: this.#arrowElement })); - } - - const referenceElement = this.trackCursorAxis - ? { - getBoundingClientRect: () => { - const triggerRect = trigger.getBoundingClientRect(); - - if (this.trackCursorAxis === 'x') { - return { - width: 0, - height: 0, - top: triggerRect.top, - right: this.#pointerPosition.x, - bottom: triggerRect.bottom, - left: this.#pointerPosition.x, - x: this.#pointerPosition.x, - y: triggerRect.top, - }; - } else if (this.trackCursorAxis === 'y') { - return { - width: 0, - height: 0, - top: this.#pointerPosition.y, - right: triggerRect.right, - bottom: this.#pointerPosition.y, - left: triggerRect.left, - x: triggerRect.left, - y: this.#pointerPosition.y, - }; - } else { - // Track both axes (trackCursorAxis === 'both') - return { - width: 0, - height: 0, - top: this.#pointerPosition.y, - right: this.#pointerPosition.x, - bottom: this.#pointerPosition.y, - left: this.#pointerPosition.x, - x: this.#pointerPosition.x, - y: this.#pointerPosition.y, - }; - } - }, - } - : trigger; - - computePosition(referenceElement, this, { - placement, - middleware, - strategy: 'fixed', - }).then(({ x, y, middlewareData }: { x: number; y: number; middlewareData: any }) => { - Object.assign(this.style, { - left: `${x}px`, - top: `${y}px`, - }); - - if (this.#arrowElement && middlewareData.arrow) { - const { x: arrowX, y: arrowY } = middlewareData.arrow; - Object.assign(this.#arrowElement.style, { - left: arrowX != null ? `${arrowX}px` : undefined, - top: arrowY != null ? `${arrowY}px` : undefined, - }); - } - }); - }; - - updatePosition(); - - if (!this.trackCursorAxis) { - this.#cleanup = autoUpdate(trigger, this, updatePosition); + #updatePosition(): void { + if (this.#open && this.trackCursorAxis) { + this.style.setProperty('left', `${this.#pointerPosition.x}px`); + this.#checkCollision(); } } - #updatePosition(): void { - if (this.#open && this.trackCursorAxis) { - this.#setupFloating(); + #checkCollision(): void { + const mediaContainer = this.closest('media-container') as MediaContainerElement; + if (!mediaContainer || !this.#open) return; + + const popupRect = getBoundingClientRectWithoutTransform(this); + const boundsRect = getBoundingClientRectWithoutTransform(mediaContainer); + const { x } = getInBoundsAdjustments(popupRect, boundsRect, this.collisionPadding); + + if (x !== 0) { + if (this.trackCursorAxis) { + const currentLeft = Number.parseFloat(this.style.left || '0'); + this.style.setProperty('left', `${currentLeft + x}px`); + } else { + this.style.setProperty('translate', `${x}px -100%`); + } + } else { + if (this.trackCursorAxis) { + this.style.setProperty('translate', '-50% -100%'); + } else { + this.style.setProperty('translate', '0 -100%'); + } } } diff --git a/packages/html/src/elements/volume-slider.ts b/packages/html/src/elements/volume-slider.ts index 9b71b997..f5f87e36 100644 --- a/packages/html/src/elements/volume-slider.ts +++ b/packages/html/src/elements/volume-slider.ts @@ -132,7 +132,7 @@ export class VolumeSliderTrack extends HTMLElement { /** * VolumeSlider Progress component - Shows current progress */ -export class VolumeSliderIndicatorElement extends HTMLElement { +export class VolumeSliderIndicator extends HTMLElement { constructor() { super(); this.style.position = 'absolute'; @@ -255,8 +255,8 @@ export const VolumeSliderTrackElement: ConnectedComponentConstructor = toCo /** * Connected VolumeSlider Progress component */ -export const VolumeSliderProgressElement: ConnectedComponentConstructor = toConnectedHTMLComponent( - VolumeSliderIndicatorElement, +export const VolumeSliderIndicatorElement: ConnectedComponentConstructor = toConnectedHTMLComponent( + VolumeSliderIndicator, { keys: [], transform: () => ({}) }, getVolumeSliderProgressProps, 'VolumeSliderProgress', @@ -280,12 +280,12 @@ export const VolumeSliderElement = Object.assign( { Root: VolumeSliderRootElement, Track: VolumeSliderTrackElement, - Progress: VolumeSliderProgressElement, + Indicator: VolumeSliderIndicatorElement, Thumb: VolumeSliderThumbElement, }, ) as { Root: typeof VolumeSliderRootElement; Track: typeof VolumeSliderTrackElement; - Progress: typeof VolumeSliderProgressElement; + Indicator: typeof VolumeSliderIndicatorElement; Thumb: typeof VolumeSliderThumbElement; }; diff --git a/packages/html/src/skins/frosted/index.ts b/packages/html/src/skins/frosted/index.ts index daea0162..0ccf2160 100644 --- a/packages/html/src/skins/frosted/index.ts +++ b/packages/html/src/skins/frosted/index.ts @@ -1,8 +1,9 @@ import { MediaSkinElement } from '@/media/media-skin'; import { defineCustomElement } from '@/utils/custom-element'; import styles from './styles.css'; -import '@/define/media-container'; +// be sure to import video-provider first for proper context initialization import '@/define/video-provider'; +import '@/define/media-container'; import '@/define/media-play-button'; import '@/define/media-mute-button'; import '@/define/media-volume-slider'; diff --git a/packages/html/src/skins/minimal/index.ts b/packages/html/src/skins/minimal/index.ts index 2d5b7de9..9ec14ce1 100644 --- a/packages/html/src/skins/minimal/index.ts +++ b/packages/html/src/skins/minimal/index.ts @@ -1,8 +1,9 @@ import { MediaSkinElement } from '@/media/media-skin'; import { defineCustomElement } from '@/utils/custom-element'; import styles from './styles.css'; -import '@/define/media-container'; +// be sure to import video-provider first for proper context initialization import '@/define/video-provider'; +import '@/define/media-container'; import '@/define/media-play-button'; import '@/define/media-mute-button'; import '@/define/media-volume-slider'; diff --git a/packages/utils/src/dom/element.ts b/packages/utils/src/dom/element.ts index 7ab1e2bf..5c7f215f 100644 --- a/packages/utils/src/dom/element.ts +++ b/packages/utils/src/dom/element.ts @@ -3,9 +3,7 @@ * * @param root - The root node to search for the active element. */ -export function activeElement( - root: Document = document, -): Element | null { +export function activeElement(root: Document = document): Element | null { let element = root.activeElement; while (element?.shadowRoot?.activeElement != null) { @@ -20,9 +18,7 @@ export function activeElement( * https://developer.mozilla.org/en-US/docs/Web/API/Node/getRootNode#return_value * @param node - The node to get the root node from. */ -export function getDocumentOrShadowRoot( - node: Node, -): Document | ShadowRoot | null { +export function getDocumentOrShadowRoot(node: Node): Document | ShadowRoot | null { const rootNode = node?.getRootNode?.(); if (rootNode instanceof ShadowRoot || rootNode instanceof Document) { return rootNode; @@ -85,9 +81,7 @@ export function isShadowRoot(value: unknown): value is ShadowRoot { return false; } - return ( - value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot - ); + return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot; } function hasWindow() { @@ -102,7 +96,7 @@ export interface FloatingNodeType { id: string; parentId: string | null; context: FloatingContext; -}; +} interface FloatingContext { open: boolean; @@ -113,11 +107,59 @@ export function getNodeChildren( id: string | undefined, onlyOpenChildren = true, ): Array { - const directChildren = nodes.filter( - node => node.parentId === id && (!onlyOpenChildren || node.context?.open), - ); - return directChildren.flatMap(child => [ - child, - ...getNodeChildren(nodes, child.id, onlyOpenChildren), - ]); + const directChildren = nodes.filter(node => node.parentId === id && (!onlyOpenChildren || node.context?.open)); + return directChildren.flatMap(child => [child, ...getNodeChildren(nodes, child.id, onlyOpenChildren)]); +} + +export function getBoundingClientRectWithoutTransform(element: HTMLElement): DOMRect { + let el = element; + let left = 0; + let top = 0; + + do { + left += el.offsetLeft; + top += el.offsetTop; + el = el.offsetParent as HTMLElement; + } while (el); + + return { + x: left, + y: top, + left, + top, + bottom: top + element.offsetHeight, + right: left + element.offsetWidth, + width: element.offsetWidth, + height: element.offsetHeight, + } as DOMRect; +} + +export function getInBoundsAdjustments( + popupRect: DOMRect, + containerRect: DOMRect, + collisionPadding: number, +): { x: number; y: number } { + const bounds = { + top: containerRect.top + collisionPadding, + right: containerRect.right - collisionPadding, + bottom: containerRect.bottom - collisionPadding, + left: containerRect.left + collisionPadding, + }; + + let x = 0; + let y = 0; + + if (popupRect.left < bounds.left) { + x = bounds.left - popupRect.left; + } else if (popupRect.right > bounds.right) { + x = bounds.right - popupRect.right; + } + + if (popupRect.top < bounds.top) { + y = bounds.top - popupRect.top; + } else if (popupRect.bottom > bounds.bottom) { + y = bounds.bottom - popupRect.bottom; + } + + return { x, y }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33916796..5113f682 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -198,12 +198,6 @@ importers: packages/html: dependencies: - '@floating-ui/core': - specifier: ^1.6.13 - version: 1.7.3 - '@floating-ui/dom': - specifier: ^1.6.13 - version: 1.7.4 '@open-wc/context-protocol': specifier: ^0.0.9 version: 0.0.9 @@ -237,7 +231,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 @@ -7411,12 +7405,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 +9775,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 +9817,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 +9893,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 +12392,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 diff --git a/site/src/utils/ejectCodeGenerator.ts b/site/src/utils/ejectCodeGenerator.ts index a2a4948f..7ecadf52 100644 --- a/site/src/utils/ejectCodeGenerator.ts +++ b/site/src/utils/ejectCodeGenerator.ts @@ -1916,7 +1916,7 @@ export function generateHTMLJS(skin: Skin): string { // npm install @videojs/html@next import '@videojs/html/icons'; -// be sure to import video-provider first +// be sure to import video-provider first for proper context initialization import '@videojs/html/define/video-provider'; import '@videojs/html/define/media-container'; import '@videojs/html/define/media-play-button';