@videojs/react 10.0.0-beta.28 → 10.0.0-beta.29
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/dist/default/__generated__/skins/default-video/styles/buttons.css +132 -18
- package/dist/default/__generated__/skins/default-video/styles/captions.css +22 -0
- package/dist/default/__generated__/skins/default-video/styles/container.css +121 -8
- package/dist/default/__generated__/skins/default-video/styles/controls.css +436 -21
- package/dist/default/__generated__/skins/default-video/styles/dialog.css +169 -0
- package/dist/default/__generated__/skins/default-video/styles/indicator.css +459 -0
- package/dist/default/__generated__/skins/default-video/styles/menus.css +254 -0
- package/dist/default/__generated__/skins/default-video/styles/overlays.css +26 -2
- package/dist/default/__generated__/skins/default-video/styles/popups.css +338 -12
- package/dist/default/__generated__/skins/default-video/styles/poster.css +4 -4
- package/dist/default/__generated__/skins/default-video/styles/sliders.css +355 -31
- package/dist/default/__generated__/skins/default-video/styles/styles.css +2455 -216
- package/dist/default/__generated__/skins/default-video/styles/theme.css +4 -19
- package/dist/default/__generated__/skins/default-video/styles/video.css +29 -0
- package/dist/default/__generated__/skins/minimal-video/styles/base.css +25 -0
- package/dist/default/__generated__/skins/minimal-video/styles/buttons.css +266 -0
- package/dist/default/__generated__/skins/minimal-video/styles/captions.css +22 -0
- package/dist/default/__generated__/skins/minimal-video/styles/container.css +158 -0
- package/dist/default/__generated__/skins/minimal-video/styles/controls.css +182 -0
- package/dist/default/__generated__/skins/minimal-video/styles/dialog.css +77 -0
- package/dist/default/__generated__/skins/minimal-video/styles/indicator.css +322 -0
- package/dist/default/__generated__/skins/minimal-video/styles/menus.css +254 -0
- package/dist/default/__generated__/skins/minimal-video/styles/overlays.css +35 -0
- package/dist/default/__generated__/skins/minimal-video/styles/popups.css +371 -0
- package/dist/default/__generated__/skins/minimal-video/styles/poster.css +47 -0
- package/dist/default/__generated__/skins/minimal-video/styles/sliders.css +436 -0
- package/dist/default/__generated__/skins/minimal-video/styles/styles.css +2246 -0
- package/dist/default/__generated__/skins/minimal-video/styles/theme.css +7 -0
- package/dist/default/__generated__/skins/minimal-video/styles/video.css +29 -0
- package/dist/default/i18n/index.js +2 -1
- package/dist/default/i18n/text.js +20 -0
- package/dist/default/i18n/text.js.map +1 -0
- package/dist/default/icons/dist/react/default/airplay-exit.js +3 -3
- package/dist/default/icons/dist/react/default/airplay-exit.js.map +1 -1
- package/dist/default/icons/dist/react/minimal/airplay-exit.js +3 -3
- package/dist/default/icons/dist/react/minimal/airplay-exit.js.map +1 -1
- package/dist/default/index.js +2 -1
- package/dist/default/media/hls-background-video/media.js +18 -3
- package/dist/default/media/hls-background-video/media.js.map +1 -1
- package/dist/default/presets/audio/minimal-skin.css +103 -101
- package/dist/default/presets/audio/minimal-skin.js +1 -1
- package/dist/default/presets/audio/minimal-skin.tailwind.js +1 -1
- package/dist/default/presets/audio/skin.css +68 -69
- package/dist/default/presets/audio/skin.js +1 -1
- package/dist/default/presets/audio/skin.tailwind.js +1 -1
- package/dist/default/presets/live-audio/minimal-skin.css +103 -101
- package/dist/default/presets/live-audio/skin.css +68 -69
- package/dist/default/presets/live-video/minimal-skin.css +140 -120
- package/dist/default/presets/live-video/minimal-skin.js +3 -8
- package/dist/default/presets/live-video/minimal-skin.js.map +1 -1
- package/dist/default/presets/live-video/minimal-skin.tailwind.js +5 -8
- package/dist/default/presets/live-video/minimal-skin.tailwind.js.map +1 -1
- package/dist/default/presets/live-video/skin.css +89 -76
- package/dist/default/presets/live-video/skin.js +3 -8
- package/dist/default/presets/live-video/skin.js.map +1 -1
- package/dist/default/presets/live-video/skin.tailwind.js +7 -10
- package/dist/default/presets/live-video/skin.tailwind.js.map +1 -1
- package/dist/default/presets/video/minimal-skin.css +140 -120
- package/dist/default/presets/video/minimal-skin.js +3 -8
- package/dist/default/presets/video/minimal-skin.js.map +1 -1
- package/dist/default/presets/video/minimal-skin.tailwind.js +5 -8
- package/dist/default/presets/video/minimal-skin.tailwind.js.map +1 -1
- package/dist/default/presets/video/skin.css +89 -76
- package/dist/default/presets/video/skin.js +3 -8
- package/dist/default/presets/video/skin.js.map +1 -1
- package/dist/default/presets/video/skin.tailwind.js +6 -9
- package/dist/default/presets/video/skin.tailwind.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/button.js +3 -1
- package/dist/default/skins/dist/default/default/tailwind/components/button.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/poster.js +8 -1
- package/dist/default/skins/dist/default/default/tailwind/components/poster.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/slider.js +10 -10
- package/dist/default/skins/dist/default/default/tailwind/components/slider.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/thumbnail.js +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/thumbnail.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/video.tailwind.js +2 -2
- package/dist/default/skins/dist/default/default/tailwind/video.tailwind.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/poster.js +8 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/poster.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/slider.js +13 -12
- package/dist/default/skins/dist/default/minimal/tailwind/components/slider.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/thumbnail.js +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/thumbnail.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/video.tailwind.js +6 -5
- package/dist/default/skins/dist/default/minimal/tailwind/video.tailwind.js.map +1 -1
- package/dist/default/skins/dist/default/shared/tailwind/icon-state.js +4 -4
- package/dist/default/skins/dist/default/shared/tailwind/icon-state.js.map +1 -1
- package/dist/default/ui/gesture/gesture.js.map +1 -1
- package/dist/default/ui/gesture/use-doubletap-gesture.js.map +1 -1
- package/dist/default/ui/gesture/use-tap-gesture.js.map +1 -1
- package/dist/default/ui/hotkey/hotkey.js.map +1 -1
- package/dist/default/ui/menu/context.js +6 -1
- package/dist/default/ui/menu/context.js.map +1 -1
- package/dist/default/ui/menu/menu-item-indicator.js +3 -2
- package/dist/default/ui/menu/menu-item-indicator.js.map +1 -1
- package/dist/default/ui/menu/menu-radio-item.js +19 -15
- package/dist/default/ui/menu/menu-radio-item.js.map +1 -1
- package/dist/default/ui/menu/menu-root.js +5 -6
- package/dist/default/ui/menu/menu-root.js.map +1 -1
- package/dist/default/ui/poster/poster.js +64 -17
- package/dist/default/ui/poster/poster.js.map +1 -1
- package/dist/default/ui/slider/slider-preview.js.map +1 -1
- package/dist/default/utils/use-render.js +2 -8
- package/dist/default/utils/use-render.js.map +1 -1
- package/dist/dev/__generated__/skins/default-video/styles/buttons.css +132 -18
- package/dist/dev/__generated__/skins/default-video/styles/captions.css +22 -0
- package/dist/dev/__generated__/skins/default-video/styles/container.css +121 -8
- package/dist/dev/__generated__/skins/default-video/styles/controls.css +436 -21
- package/dist/dev/__generated__/skins/default-video/styles/dialog.css +169 -0
- package/dist/dev/__generated__/skins/default-video/styles/indicator.css +459 -0
- package/dist/dev/__generated__/skins/default-video/styles/menus.css +254 -0
- package/dist/dev/__generated__/skins/default-video/styles/overlays.css +26 -2
- package/dist/dev/__generated__/skins/default-video/styles/popups.css +338 -12
- package/dist/dev/__generated__/skins/default-video/styles/poster.css +4 -4
- package/dist/dev/__generated__/skins/default-video/styles/sliders.css +355 -31
- package/dist/dev/__generated__/skins/default-video/styles/styles.css +2455 -216
- package/dist/dev/__generated__/skins/default-video/styles/theme.css +4 -19
- package/dist/dev/__generated__/skins/default-video/styles/video.css +29 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/base.css +25 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/buttons.css +266 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/captions.css +22 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/container.css +158 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/controls.css +182 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/dialog.css +77 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/indicator.css +322 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/menus.css +254 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/overlays.css +35 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/popups.css +371 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/poster.css +47 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/sliders.css +436 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/styles.css +2246 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/theme.css +7 -0
- package/dist/dev/__generated__/skins/minimal-video/styles/video.css +29 -0
- package/dist/dev/i18n/index.d.ts +2 -1
- package/dist/dev/i18n/index.js +2 -1
- package/dist/dev/i18n/text.d.ts +11 -0
- package/dist/dev/i18n/text.d.ts.map +1 -0
- package/dist/dev/i18n/text.js +20 -0
- package/dist/dev/i18n/text.js.map +1 -0
- package/dist/dev/icons/dist/react/default/airplay-exit.js +3 -3
- package/dist/dev/icons/dist/react/default/airplay-exit.js.map +1 -1
- package/dist/dev/icons/dist/react/minimal/airplay-exit.js +3 -3
- package/dist/dev/icons/dist/react/minimal/airplay-exit.js.map +1 -1
- package/dist/dev/icons/index.d.ts +6 -1
- package/dist/dev/icons/index.d.ts.map +1 -0
- package/dist/dev/icons/minimal/index.d.ts +6 -1
- package/dist/dev/icons/minimal/index.d.ts.map +1 -0
- package/dist/dev/index.d.ts +3 -2
- package/dist/dev/index.js +2 -1
- package/dist/dev/media/hls-background-video/media.d.ts +8 -0
- package/dist/dev/media/hls-background-video/media.d.ts.map +1 -1
- package/dist/dev/media/hls-background-video/media.js +18 -3
- package/dist/dev/media/hls-background-video/media.js.map +1 -1
- package/dist/dev/presets/audio/minimal-skin.css +103 -101
- package/dist/dev/presets/audio/minimal-skin.js +1 -1
- package/dist/dev/presets/audio/minimal-skin.tailwind.js +1 -1
- package/dist/dev/presets/audio/player.d.ts +2 -2
- package/dist/dev/presets/audio/skin.css +68 -69
- package/dist/dev/presets/audio/skin.js +1 -1
- package/dist/dev/presets/audio/skin.tailwind.js +1 -1
- package/dist/dev/presets/live-audio/minimal-skin.css +103 -101
- package/dist/dev/presets/live-audio/player.d.ts +2 -2
- package/dist/dev/presets/live-audio/skin.css +68 -69
- package/dist/dev/presets/live-video/minimal-skin.css +140 -120
- package/dist/dev/presets/live-video/minimal-skin.d.ts.map +1 -1
- package/dist/dev/presets/live-video/minimal-skin.js +3 -8
- package/dist/dev/presets/live-video/minimal-skin.js.map +1 -1
- package/dist/dev/presets/live-video/minimal-skin.tailwind.d.ts.map +1 -1
- package/dist/dev/presets/live-video/minimal-skin.tailwind.js +5 -8
- package/dist/dev/presets/live-video/minimal-skin.tailwind.js.map +1 -1
- package/dist/dev/presets/live-video/player.d.ts +2 -2
- package/dist/dev/presets/live-video/skin.css +89 -76
- package/dist/dev/presets/live-video/skin.d.ts.map +1 -1
- package/dist/dev/presets/live-video/skin.js +3 -8
- package/dist/dev/presets/live-video/skin.js.map +1 -1
- package/dist/dev/presets/live-video/skin.tailwind.d.ts.map +1 -1
- package/dist/dev/presets/live-video/skin.tailwind.js +7 -10
- package/dist/dev/presets/live-video/skin.tailwind.js.map +1 -1
- package/dist/dev/presets/types.d.ts +15 -2
- package/dist/dev/presets/types.d.ts.map +1 -1
- package/dist/dev/presets/video/minimal-skin.css +140 -120
- package/dist/dev/presets/video/minimal-skin.d.ts.map +1 -1
- package/dist/dev/presets/video/minimal-skin.js +3 -8
- package/dist/dev/presets/video/minimal-skin.js.map +1 -1
- package/dist/dev/presets/video/minimal-skin.tailwind.d.ts.map +1 -1
- package/dist/dev/presets/video/minimal-skin.tailwind.js +5 -8
- package/dist/dev/presets/video/minimal-skin.tailwind.js.map +1 -1
- package/dist/dev/presets/video/player.d.ts +2 -2
- package/dist/dev/presets/video/skin.css +89 -76
- package/dist/dev/presets/video/skin.d.ts.map +1 -1
- package/dist/dev/presets/video/skin.js +3 -8
- package/dist/dev/presets/video/skin.js.map +1 -1
- package/dist/dev/presets/video/skin.tailwind.d.ts.map +1 -1
- package/dist/dev/presets/video/skin.tailwind.js +6 -9
- package/dist/dev/presets/video/skin.tailwind.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/button.js +3 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/button.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/poster.js +8 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/poster.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/slider.js +10 -10
- package/dist/dev/skins/dist/default/default/tailwind/components/slider.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/thumbnail.js +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/thumbnail.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/video.tailwind.js +2 -2
- package/dist/dev/skins/dist/default/default/tailwind/video.tailwind.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/poster.js +8 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/poster.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/slider.js +13 -12
- package/dist/dev/skins/dist/default/minimal/tailwind/components/slider.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/thumbnail.js +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/thumbnail.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/video.tailwind.js +6 -5
- package/dist/dev/skins/dist/default/minimal/tailwind/video.tailwind.js.map +1 -1
- package/dist/dev/skins/dist/default/shared/tailwind/icon-state.js +4 -4
- package/dist/dev/skins/dist/default/shared/tailwind/icon-state.js.map +1 -1
- package/dist/dev/ui/gesture/gesture.d.ts +6 -13
- package/dist/dev/ui/gesture/gesture.d.ts.map +1 -1
- package/dist/dev/ui/gesture/gesture.js.map +1 -1
- package/dist/dev/ui/gesture/use-doubletap-gesture.d.ts +2 -5
- package/dist/dev/ui/gesture/use-doubletap-gesture.d.ts.map +1 -1
- package/dist/dev/ui/gesture/use-doubletap-gesture.js.map +1 -1
- package/dist/dev/ui/gesture/use-tap-gesture.d.ts +2 -5
- package/dist/dev/ui/gesture/use-tap-gesture.d.ts.map +1 -1
- package/dist/dev/ui/gesture/use-tap-gesture.js.map +1 -1
- package/dist/dev/ui/hotkey/hotkey.d.ts +6 -12
- package/dist/dev/ui/hotkey/hotkey.d.ts.map +1 -1
- package/dist/dev/ui/hotkey/hotkey.js.map +1 -1
- package/dist/dev/ui/menu/context.js +6 -1
- package/dist/dev/ui/menu/context.js.map +1 -1
- package/dist/dev/ui/menu/menu-item-indicator.d.ts.map +1 -1
- package/dist/dev/ui/menu/menu-item-indicator.js +3 -2
- package/dist/dev/ui/menu/menu-item-indicator.js.map +1 -1
- package/dist/dev/ui/menu/menu-radio-item.d.ts.map +1 -1
- package/dist/dev/ui/menu/menu-radio-item.js +19 -15
- package/dist/dev/ui/menu/menu-radio-item.js.map +1 -1
- package/dist/dev/ui/menu/menu-root.js +5 -6
- package/dist/dev/ui/menu/menu-root.js.map +1 -1
- package/dist/dev/ui/poster/poster.d.ts +15 -4
- package/dist/dev/ui/poster/poster.d.ts.map +1 -1
- package/dist/dev/ui/poster/poster.js +64 -17
- package/dist/dev/ui/poster/poster.js.map +1 -1
- package/dist/dev/ui/slider/slider-preview.d.ts +5 -9
- package/dist/dev/ui/slider/slider-preview.d.ts.map +1 -1
- package/dist/dev/ui/slider/slider-preview.js.map +1 -1
- package/dist/dev/utils/use-render.d.ts.map +1 -1
- package/dist/dev/utils/use-render.js +2 -8
- package/dist/dev/utils/use-render.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/concepts/skins.md +97 -96
- package/docs/how-to/customize-skins.md +421 -411
- package/docs/reference/create-player.md +2 -2
- package/docs/reference/menu.md +6 -18
- package/docs/reference/popover.md +6 -6
- package/docs/reference/poster.md +187 -13
- package/docs/reference/slider.md +1 -1
- package/docs/reference/time-slider.md +1 -1
- package/docs/reference/tooltip.md +10 -10
- package/docs/reference/volume-slider.md +1 -1
- package/package.json +13 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hotkey.js","names":[],"sources":["../../../../src/ui/hotkey/hotkey.tsx"],"sourcesContent":["import type { AnyPlayerStore } from '@videojs/core/dom';\nimport { createHotkey,
|
|
1
|
+
{"version":3,"file":"hotkey.js","names":[],"sources":["../../../../src/ui/hotkey/hotkey.tsx"],"sourcesContent":["import type { HotkeyProps as CoreHotkeyProps } from '@videojs/core';\nimport type { AnyPlayerStore } from '@videojs/core/dom';\nimport { createHotkey, isHotkeyToggleAction, resolveHotkeyAction } from '@videojs/core/dom';\nimport type { ReactNode } from 'react';\nimport { useEffect } from 'react';\n\nimport { useContainer, usePlayer } from '../../player/context';\n\nexport interface HotkeyProps extends CoreHotkeyProps {}\n\nexport function Hotkey({ keys, action, value, disabled, target }: HotkeyProps): ReactNode {\n const store = usePlayer() as AnyPlayerStore;\n const container = useContainer();\n\n useEffect(() => {\n if (!container || !keys || !action || disabled) return;\n\n const resolver = resolveHotkeyAction(action);\n if (!resolver) return;\n\n return createHotkey(container, {\n keys,\n action,\n value,\n target,\n disabled,\n repeatable: !isHotkeyToggleAction(action),\n onActivate: (_event, key) => {\n resolver({ store, key, value });\n },\n });\n }, [container, store, keys, action, value, disabled, target]);\n\n return null;\n}\n\nexport namespace Hotkey {\n export type Props = HotkeyProps;\n}\n\n/** @deprecated Use `HotkeyProps` instead. */\nexport type MediaHotkeyProps = HotkeyProps;\n\n/** @deprecated Use `Hotkey` instead. */\nexport const MediaHotkey = Hotkey;\n"],"mappings":";;;;AAUA,SAAgB,OAAO,EAAE,MAAM,QAAQ,OAAO,UAAU,UAAkC;CACxF,MAAM,QAAQ,UAAU;CACxB,MAAM,YAAY,aAAa;CAE/B,gBAAgB;EACd,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,UAAU;EAEhD,MAAM,WAAW,oBAAoB,MAAM;EAC3C,IAAI,CAAC,UAAU;EAEf,OAAO,aAAa,WAAW;GAC7B;GACA;GACA;GACA;GACA;GACA,YAAY,CAAC,qBAAqB,MAAM;GACxC,aAAa,QAAQ,QAAQ;IAC3B,SAAS;KAAE;KAAO;KAAK;IAAM,CAAC;GAChC;EACF,CAAC;CACH,GAAG;EAAC;EAAW;EAAO;EAAM;EAAQ;EAAO;EAAU;CAAM,CAAC;CAE5D,OAAO;AACT;;AAUA,MAAa,cAAc"}
|
|
@@ -22,12 +22,17 @@ function useMenuRadioGroupContext() {
|
|
|
22
22
|
if (!ctx) throw new Error("Menu.RadioItem must be used within a Menu.RadioGroup");
|
|
23
23
|
return ctx;
|
|
24
24
|
}
|
|
25
|
+
const MenuRadioItemContext = createContext(false);
|
|
26
|
+
const MenuRadioItemContextProvider = MenuRadioItemContext.Provider;
|
|
27
|
+
function useOptionalMenuRadioItemContext() {
|
|
28
|
+
return useContext(MenuRadioItemContext);
|
|
29
|
+
}
|
|
25
30
|
const MenuTriggerChildContext = createContext(false);
|
|
26
31
|
const MenuTriggerChildContextProvider = MenuTriggerChildContext.Provider;
|
|
27
32
|
function useOptionalMenuTriggerChildContext() {
|
|
28
33
|
return useContext(MenuTriggerChildContext);
|
|
29
34
|
}
|
|
30
35
|
//#endregion
|
|
31
|
-
export { MenuContextProvider, MenuGroupContextProvider, MenuRadioGroupContextProvider, MenuTriggerChildContextProvider, useMenuContext, useMenuGroupContext, useMenuRadioGroupContext, useOptionalMenuContext, useOptionalMenuTriggerChildContext };
|
|
36
|
+
export { MenuContextProvider, MenuGroupContextProvider, MenuRadioGroupContextProvider, MenuRadioItemContextProvider, MenuTriggerChildContextProvider, useMenuContext, useMenuGroupContext, useMenuRadioGroupContext, useOptionalMenuContext, useOptionalMenuRadioItemContext, useOptionalMenuTriggerChildContext };
|
|
32
37
|
|
|
33
38
|
//# sourceMappingURL=context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../../../src/ui/menu/context.tsx"],"sourcesContent":["import type { MenuCore, MenuState, StateAttrMap } from '@videojs/core';\nimport type { MediaContainer, MenuApi, PositioningBoundary } from '@videojs/core/dom';\nimport { createContext, useContext } from 'react';\n\nexport interface MenuContextValue {\n core: MenuCore;\n menu: MenuApi;\n parent: MenuContextValue | null;\n state: MenuState;\n preferredSide: MenuState['side'];\n setPositionedSide: (side: MenuState['side']) => void;\n stateAttrMap: StateAttrMap<MenuState>;\n contentId: string;\n anchorName: string;\n boundary: PositioningBoundary;\n container: MediaContainer | null;\n}\n\nconst MenuContext = createContext<MenuContextValue | null>(null);\n\nexport const MenuContextProvider = MenuContext.Provider;\n\nexport function useMenuContext(): MenuContextValue {\n const ctx = useContext(MenuContext);\n if (!ctx) throw new Error('Menu compound components must be used within a Menu.Root');\n return ctx;\n}\n\nexport function useOptionalMenuContext(): MenuContextValue | null {\n return useContext(MenuContext);\n}\n\n// ---------------------------------------------------------------------------\n// Group context — shared by group-like parts and MenuGroupLabel\n// ---------------------------------------------------------------------------\n\nexport interface MenuGroupContextValue {\n registerLabel: (id: string) => () => void;\n}\n\nconst MenuGroupContext = createContext<MenuGroupContextValue | null>(null);\n\nexport const MenuGroupContextProvider = MenuGroupContext.Provider;\n\nexport function useMenuGroupContext(): MenuGroupContextValue | null {\n return useContext(MenuGroupContext);\n}\n\n// ---------------------------------------------------------------------------\n// Radio group context — shared between MenuRadioGroup and MenuRadioItem\n// ---------------------------------------------------------------------------\n\nexport interface MenuRadioGroupContextValue {\n value: string;\n onValueChange: (value: string) => void;\n}\n\nconst MenuRadioGroupContext = createContext<MenuRadioGroupContextValue | null>(null);\n\nexport const MenuRadioGroupContextProvider = MenuRadioGroupContext.Provider;\n\nexport function useMenuRadioGroupContext(): MenuRadioGroupContextValue {\n const ctx = useContext(MenuRadioGroupContext);\n if (!ctx) throw new Error('Menu.RadioItem must be used within a Menu.RadioGroup');\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Root trigger render context — provided by Menu.Trigger for render children.\n// ---------------------------------------------------------------------------\n\nconst MenuTriggerChildContext = createContext(false);\n\nexport const MenuTriggerChildContextProvider = MenuTriggerChildContext.Provider;\n\nexport function useOptionalMenuTriggerChildContext(): boolean {\n return useContext(MenuTriggerChildContext);\n}\n"],"mappings":";;AAkBA,MAAM,cAAc,cAAuC,IAAI;AAE/D,MAAa,sBAAsB,YAAY;AAE/C,SAAgB,iBAAmC;CACjD,MAAM,MAAM,WAAW,WAAW;CAClC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,0DAA0D;CACpF,OAAO;AACT;AAEA,SAAgB,yBAAkD;CAChE,OAAO,WAAW,WAAW;AAC/B;AAUA,MAAM,mBAAmB,cAA4C,IAAI;AAEzE,MAAa,2BAA2B,iBAAiB;AAEzD,SAAgB,sBAAoD;CAClE,OAAO,WAAW,gBAAgB;AACpC;AAWA,MAAM,wBAAwB,cAAiD,IAAI;AAEnF,MAAa,gCAAgC,sBAAsB;AAEnE,SAAgB,2BAAuD;CACrE,MAAM,MAAM,WAAW,qBAAqB;CAC5C,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,sDAAsD;CAChF,OAAO;AACT;AAMA,MAAM,0BAA0B,cAAc,KAAK;AAEnD,MAAa,kCAAkC,wBAAwB;AAEvE,SAAgB,qCAA8C;CAC5D,OAAO,WAAW,uBAAuB;AAC3C"}
|
|
1
|
+
{"version":3,"file":"context.js","names":[],"sources":["../../../../src/ui/menu/context.tsx"],"sourcesContent":["import type { MenuCore, MenuState, StateAttrMap } from '@videojs/core';\nimport type { MediaContainer, MenuApi, PositioningBoundary } from '@videojs/core/dom';\nimport { createContext, useContext } from 'react';\n\nexport interface MenuContextValue {\n core: MenuCore;\n menu: MenuApi;\n parent: MenuContextValue | null;\n state: MenuState;\n preferredSide: MenuState['side'];\n setPositionedSide: (side: MenuState['side']) => void;\n stateAttrMap: StateAttrMap<MenuState>;\n contentId: string;\n anchorName: string;\n boundary: PositioningBoundary;\n container: MediaContainer | null;\n}\n\nconst MenuContext = createContext<MenuContextValue | null>(null);\n\nexport const MenuContextProvider = MenuContext.Provider;\n\nexport function useMenuContext(): MenuContextValue {\n const ctx = useContext(MenuContext);\n if (!ctx) throw new Error('Menu compound components must be used within a Menu.Root');\n return ctx;\n}\n\nexport function useOptionalMenuContext(): MenuContextValue | null {\n return useContext(MenuContext);\n}\n\n// ---------------------------------------------------------------------------\n// Group context — shared by group-like parts and MenuGroupLabel\n// ---------------------------------------------------------------------------\n\nexport interface MenuGroupContextValue {\n registerLabel: (id: string) => () => void;\n}\n\nconst MenuGroupContext = createContext<MenuGroupContextValue | null>(null);\n\nexport const MenuGroupContextProvider = MenuGroupContext.Provider;\n\nexport function useMenuGroupContext(): MenuGroupContextValue | null {\n return useContext(MenuGroupContext);\n}\n\n// ---------------------------------------------------------------------------\n// Radio group context — shared between MenuRadioGroup and MenuRadioItem\n// ---------------------------------------------------------------------------\n\nexport interface MenuRadioGroupContextValue {\n value: string;\n onValueChange: (value: string) => void;\n}\n\nconst MenuRadioGroupContext = createContext<MenuRadioGroupContextValue | null>(null);\n\nexport const MenuRadioGroupContextProvider = MenuRadioGroupContext.Provider;\n\nexport function useMenuRadioGroupContext(): MenuRadioGroupContextValue {\n const ctx = useContext(MenuRadioGroupContext);\n if (!ctx) throw new Error('Menu.RadioItem must be used within a Menu.RadioGroup');\n return ctx;\n}\n\nconst MenuRadioItemContext = createContext(false);\n\nexport const MenuRadioItemContextProvider = MenuRadioItemContext.Provider;\n\nexport function useOptionalMenuRadioItemContext(): boolean {\n return useContext(MenuRadioItemContext);\n}\n\n// ---------------------------------------------------------------------------\n// Root trigger render context — provided by Menu.Trigger for render children.\n// ---------------------------------------------------------------------------\n\nconst MenuTriggerChildContext = createContext(false);\n\nexport const MenuTriggerChildContextProvider = MenuTriggerChildContext.Provider;\n\nexport function useOptionalMenuTriggerChildContext(): boolean {\n return useContext(MenuTriggerChildContext);\n}\n"],"mappings":";;AAkBA,MAAM,cAAc,cAAuC,IAAI;AAE/D,MAAa,sBAAsB,YAAY;AAE/C,SAAgB,iBAAmC;CACjD,MAAM,MAAM,WAAW,WAAW;CAClC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,0DAA0D;CACpF,OAAO;AACT;AAEA,SAAgB,yBAAkD;CAChE,OAAO,WAAW,WAAW;AAC/B;AAUA,MAAM,mBAAmB,cAA4C,IAAI;AAEzE,MAAa,2BAA2B,iBAAiB;AAEzD,SAAgB,sBAAoD;CAClE,OAAO,WAAW,gBAAgB;AACpC;AAWA,MAAM,wBAAwB,cAAiD,IAAI;AAEnF,MAAa,gCAAgC,sBAAsB;AAEnE,SAAgB,2BAAuD;CACrE,MAAM,MAAM,WAAW,qBAAqB;CAC5C,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,sDAAsD;CAChF,OAAO;AACT;AAEA,MAAM,uBAAuB,cAAc,KAAK;AAEhD,MAAa,+BAA+B,qBAAqB;AAEjE,SAAgB,kCAA2C;CACzD,OAAO,WAAW,oBAAoB;AACxC;AAMA,MAAM,0BAA0B,cAAc,KAAK;AAEnD,MAAa,kCAAkC,wBAAwB;AAEvE,SAAgB,qCAA8C;CAC5D,OAAO,WAAW,uBAAuB;AAC3C"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { renderElement } from "../../utils/use-render.js";
|
|
2
|
-
import { useMenuContext } from "./context.js";
|
|
2
|
+
import { useMenuContext, useOptionalMenuRadioItemContext } from "./context.js";
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
//#region src/ui/menu/menu-item-indicator.tsx
|
|
5
5
|
/** Visual indicator for a checked state. Only renders when `checked` is `true` (or `forceMount` is set). */
|
|
6
6
|
const MenuItemIndicator = forwardRef(function MenuItemIndicator({ render, className, style, checked, forceMount = false, ...elementProps }, forwardedRef) {
|
|
7
7
|
const { state } = useMenuContext();
|
|
8
|
-
|
|
8
|
+
const itemChecked = useOptionalMenuRadioItemContext();
|
|
9
|
+
if (!(checked ?? itemChecked) && !forceMount) return null;
|
|
9
10
|
return renderElement("span", {
|
|
10
11
|
render,
|
|
11
12
|
className,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-item-indicator.js","names":[],"sources":["../../../../src/ui/menu/menu-item-indicator.tsx"],"sourcesContent":["import type { MenuState } from '@videojs/core';\nimport { forwardRef } from 'react';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { renderElement } from '../../utils/use-render';\nimport { useMenuContext } from './context';\n\nexport interface MenuItemIndicatorProps extends UIComponentProps<'span', MenuState> {\n /** Whether the indicator is currently shown. Typically bound to the parent item's checked state. */\n checked?: boolean;\n /** When `true`, renders even when unchecked (useful for animating out). Defaults to `false`. */\n forceMount?: boolean;\n}\n\n/** Visual indicator for a checked state. Only renders when `checked` is `true` (or `forceMount` is set). */\nexport const MenuItemIndicator = forwardRef<HTMLSpanElement, MenuItemIndicatorProps>(function MenuItemIndicator(\n { render, className, style, checked, forceMount = false, ...elementProps },\n forwardedRef\n) {\n const { state } = useMenuContext();\n\n if (!
|
|
1
|
+
{"version":3,"file":"menu-item-indicator.js","names":[],"sources":["../../../../src/ui/menu/menu-item-indicator.tsx"],"sourcesContent":["import type { MenuState } from '@videojs/core';\nimport { forwardRef } from 'react';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { renderElement } from '../../utils/use-render';\nimport { useMenuContext, useOptionalMenuRadioItemContext } from './context';\n\nexport interface MenuItemIndicatorProps extends UIComponentProps<'span', MenuState> {\n /** Whether the indicator is currently shown. Typically bound to the parent item's checked state. */\n checked?: boolean;\n /** When `true`, renders even when unchecked (useful for animating out). Defaults to `false`. */\n forceMount?: boolean;\n}\n\n/** Visual indicator for a checked state. Only renders when `checked` is `true` (or `forceMount` is set). */\nexport const MenuItemIndicator = forwardRef<HTMLSpanElement, MenuItemIndicatorProps>(function MenuItemIndicator(\n { render, className, style, checked, forceMount = false, ...elementProps },\n forwardedRef\n) {\n const { state } = useMenuContext();\n const itemChecked = useOptionalMenuRadioItemContext();\n const resolvedChecked = checked ?? itemChecked;\n\n if (!resolvedChecked && !forceMount) return null;\n\n return renderElement(\n 'span',\n { render, className, style },\n {\n state,\n ref: [forwardedRef],\n props: [{ 'aria-hidden': true }, elementProps],\n }\n );\n});\n\nexport namespace MenuItemIndicator {\n export type Props = MenuItemIndicatorProps;\n export type State = MenuState;\n}\n"],"mappings":";;;;;AAeA,MAAa,oBAAoB,WAAoD,SAAS,kBAC5F,EAAE,QAAQ,WAAW,OAAO,SAAS,aAAa,OAAO,GAAG,gBAC5D,cACA;CACA,MAAM,EAAE,UAAU,eAAe;CACjC,MAAM,cAAc,gCAAgC;CAGpD,IAAI,EAFoB,WAAW,gBAEX,CAAC,YAAY,OAAO;CAE5C,OAAO,cACL,QACA;EAAE;EAAQ;EAAW;CAAM,GAC3B;EACE;EACA,KAAK,CAAC,YAAY;EAClB,OAAO,CAAC,EAAE,eAAe,KAAK,GAAG,YAAY;CAC/C,CACF;AACF,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { renderElement } from "../../utils/use-render.js";
|
|
2
|
-
import { useMenuContext, useMenuRadioGroupContext } from "./context.js";
|
|
2
|
+
import { MenuRadioItemContextProvider, useMenuContext, useMenuRadioGroupContext } from "./context.js";
|
|
3
3
|
import { completeMenuItemSelection } from "@videojs/core/dom";
|
|
4
4
|
import { forwardRef, useCallback, useEffect, useRef } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
//#region src/ui/menu/menu-radio-item.tsx
|
|
6
7
|
/** A radio-style menu item. Renders a `<div>` with `role="menuitemradio"`. */
|
|
7
8
|
const MenuRadioItem = forwardRef(function MenuRadioItem({ render, className, style, value, disabled, onClick, ...elementProps }, forwardedRef) {
|
|
@@ -35,20 +36,23 @@ const MenuRadioItem = forwardRef(function MenuRadioItem({ render, className, sty
|
|
|
35
36
|
pointer: true
|
|
36
37
|
});
|
|
37
38
|
}, [menu, disabled]);
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
return /* @__PURE__ */ jsx(MenuRadioItemContextProvider, {
|
|
40
|
+
value: checked,
|
|
41
|
+
children: renderElement("div", {
|
|
42
|
+
render,
|
|
43
|
+
className,
|
|
44
|
+
style
|
|
45
|
+
}, {
|
|
46
|
+
state,
|
|
47
|
+
ref: [forwardedRef, elementRef],
|
|
48
|
+
props: [{
|
|
49
|
+
role: "menuitemradio",
|
|
50
|
+
"aria-checked": checked,
|
|
51
|
+
"aria-disabled": disabled ? true : void 0,
|
|
52
|
+
onClick: handleClick,
|
|
53
|
+
onPointerEnter: handlePointerEnter
|
|
54
|
+
}, elementProps]
|
|
55
|
+
})
|
|
52
56
|
});
|
|
53
57
|
});
|
|
54
58
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-radio-item.js","names":[],"sources":["../../../../src/ui/menu/menu-radio-item.tsx"],"sourcesContent":["import type { MenuState } from '@videojs/core';\nimport { completeMenuItemSelection } from '@videojs/core/dom';\nimport { forwardRef, useCallback, useEffect, useRef } from 'react';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { renderElement } from '../../utils/use-render';\nimport { useMenuContext, useMenuRadioGroupContext } from './context';\n\nexport interface MenuRadioItemProps extends UIComponentProps<'div', MenuState> {\n /** The value this item represents. */\n value: string;\n /** Whether the item is disabled. */\n disabled?: boolean;\n}\n\n/** A radio-style menu item. Renders a `<div>` with `role=\"menuitemradio\"`. */\nexport const MenuRadioItem = forwardRef<HTMLDivElement, MenuRadioItemProps>(function MenuRadioItem(\n { render, className, style, value, disabled, onClick, ...elementProps },\n forwardedRef\n) {\n const { menu, state } = useMenuContext();\n const { value: groupValue, onValueChange } = useMenuRadioGroupContext();\n const elementRef = useRef<HTMLDivElement>(null);\n const checked = groupValue === value;\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n return menu.registerItem(element);\n }, [menu]);\n\n const handleClick = useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return;\n onClick?.(event);\n if (event.defaultPrevented) return;\n onValueChange(value);\n completeMenuItemSelection(menu);\n },\n [disabled, onClick, onValueChange, value, menu]\n );\n\n const handlePointerEnter = useCallback(() => {\n const element = elementRef.current;\n if (!element || disabled) return;\n menu.highlight(element, { focus: false, pointer: true });\n }, [menu, disabled]);\n\n return renderElement(\n
|
|
1
|
+
{"version":3,"file":"menu-radio-item.js","names":[],"sources":["../../../../src/ui/menu/menu-radio-item.tsx"],"sourcesContent":["import type { MenuState } from '@videojs/core';\nimport { completeMenuItemSelection } from '@videojs/core/dom';\nimport { forwardRef, useCallback, useEffect, useRef } from 'react';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { renderElement } from '../../utils/use-render';\nimport { MenuRadioItemContextProvider, useMenuContext, useMenuRadioGroupContext } from './context';\n\nexport interface MenuRadioItemProps extends UIComponentProps<'div', MenuState> {\n /** The value this item represents. */\n value: string;\n /** Whether the item is disabled. */\n disabled?: boolean;\n}\n\n/** A radio-style menu item. Renders a `<div>` with `role=\"menuitemradio\"`. */\nexport const MenuRadioItem = forwardRef<HTMLDivElement, MenuRadioItemProps>(function MenuRadioItem(\n { render, className, style, value, disabled, onClick, ...elementProps },\n forwardedRef\n) {\n const { menu, state } = useMenuContext();\n const { value: groupValue, onValueChange } = useMenuRadioGroupContext();\n const elementRef = useRef<HTMLDivElement>(null);\n const checked = groupValue === value;\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n return menu.registerItem(element);\n }, [menu]);\n\n const handleClick = useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return;\n onClick?.(event);\n if (event.defaultPrevented) return;\n onValueChange(value);\n completeMenuItemSelection(menu);\n },\n [disabled, onClick, onValueChange, value, menu]\n );\n\n const handlePointerEnter = useCallback(() => {\n const element = elementRef.current;\n if (!element || disabled) return;\n menu.highlight(element, { focus: false, pointer: true });\n }, [menu, disabled]);\n\n return (\n <MenuRadioItemContextProvider value={checked}>\n {renderElement(\n 'div',\n { render, className, style },\n {\n state,\n ref: [forwardedRef, elementRef],\n props: [\n {\n role: 'menuitemradio' as const,\n 'aria-checked': checked,\n 'aria-disabled': disabled ? true : undefined,\n onClick: handleClick,\n onPointerEnter: handlePointerEnter,\n },\n elementProps,\n ],\n }\n )}\n </MenuRadioItemContextProvider>\n );\n});\n\nexport namespace MenuRadioItem {\n export type Props = MenuRadioItemProps;\n export type State = MenuState;\n}\n"],"mappings":";;;;;;;AAgBA,MAAa,gBAAgB,WAA+C,SAAS,cACnF,EAAE,QAAQ,WAAW,OAAO,OAAO,UAAU,SAAS,GAAG,gBACzD,cACA;CACA,MAAM,EAAE,MAAM,UAAU,eAAe;CACvC,MAAM,EAAE,OAAO,YAAY,kBAAkB,yBAAyB;CACtE,MAAM,aAAa,OAAuB,IAAI;CAC9C,MAAM,UAAU,eAAe;CAE/B,gBAAgB;EACd,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,SAAS;EACd,OAAO,KAAK,aAAa,OAAO;CAClC,GAAG,CAAC,IAAI,CAAC;CAET,MAAM,cAAc,aACjB,UAA4C;EAC3C,IAAI,UAAU;EACd,UAAU,KAAK;EACf,IAAI,MAAM,kBAAkB;EAC5B,cAAc,KAAK;EACnB,0BAA0B,IAAI;CAChC,GACA;EAAC;EAAU;EAAS;EAAe;EAAO;CAAI,CAChD;CAEA,MAAM,qBAAqB,kBAAkB;EAC3C,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,WAAW,UAAU;EAC1B,KAAK,UAAU,SAAS;GAAE,OAAO;GAAO,SAAS;EAAK,CAAC;CACzD,GAAG,CAAC,MAAM,QAAQ,CAAC;CAEnB,OACE,oBAAC,8BAAD;EAA8B,OAAO;EAClC,UAAA,cACC,OACA;GAAE;GAAQ;GAAW;EAAM,GAC3B;GACE;GACA,KAAK,CAAC,cAAc,UAAU;GAC9B,OAAO,CACL;IACE,MAAM;IACN,gBAAgB;IAChB,iBAAiB,WAAW,OAAO,KAAA;IACnC,SAAS;IACT,gBAAgB;GAClB,GACA,YACF;EACF,CACF;CAC4B,CAAA;AAElC,CAAC"}
|
|
@@ -20,10 +20,7 @@ function MenuRoot({ open: controlledOpen, defaultOpen = MenuCore.defaultProps.de
|
|
|
20
20
|
const popupGroup = useOptionalPopupGroup();
|
|
21
21
|
const isSubmenu = parentMenu !== null;
|
|
22
22
|
const { side, align, closeOnEscape, closeOnOutsideClick } = coreProps;
|
|
23
|
-
const [core] = useState(() => new MenuCore(
|
|
24
|
-
...coreProps,
|
|
25
|
-
isSubmenu
|
|
26
|
-
}));
|
|
23
|
+
const [core] = useState(() => new MenuCore(coreProps));
|
|
27
24
|
const isControlled = controlledOpen !== void 0;
|
|
28
25
|
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
29
26
|
const resolvedOpen = controlledOpen ?? uncontrolledOpen;
|
|
@@ -77,10 +74,12 @@ function MenuRoot({ open: controlledOpen, defaultOpen = MenuCore.defaultProps.de
|
|
|
77
74
|
side,
|
|
78
75
|
align,
|
|
79
76
|
closeOnEscape,
|
|
80
|
-
closeOnOutsideClick
|
|
77
|
+
closeOnOutsideClick
|
|
78
|
+
});
|
|
79
|
+
core.setInput({
|
|
80
|
+
...input,
|
|
81
81
|
isSubmenu
|
|
82
82
|
});
|
|
83
|
-
core.setInput(input);
|
|
84
83
|
return core.getState();
|
|
85
84
|
}, [
|
|
86
85
|
core,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-root.js","names":[],"sources":["../../../../src/ui/menu/menu-root.tsx"],"sourcesContent":["import { MenuCore, MenuDataAttrs } from '@videojs/core';\nimport {\n createMenu,\n createTransition,\n type MenuChangeDetails,\n type PositioningBoundary,\n selectControls,\n} from '@videojs/core/dom';\nimport { useSnapshot } from '@videojs/store/react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { useOptionalContainer, useOptionalPlayer } from '../../player/context';\nimport { useOptionalPopupGroup } from '../../player/popup-group-context';\nimport { useDestroy } from '../../utils/use-destroy';\nimport { useLatestRef } from '../../utils/use-latest-ref';\nimport { useSafeId } from '../../utils/use-safe-id';\nimport { useOptionalControlsContext } from '../controls/context';\nimport { usePositionedState } from '../hooks/use-positioned-state';\nimport { MenuContextProvider, useOptionalMenuContext } from './context';\n\nexport interface MenuRootProps extends MenuCore.Props {\n /** Boundary used to constrain the root menu popup size. */\n boundary?: PositioningBoundary;\n /** Called when the menu open state changes (fires immediately, before animations). */\n onOpenChange?: (open: boolean, details: MenuChangeDetails) => void;\n /** Called after open/close animations complete. */\n onOpenChangeComplete?: (open: boolean) => void;\n children?: ReactNode;\n}\n\nexport function MenuRoot({\n open: controlledOpen,\n defaultOpen = MenuCore.defaultProps.defaultOpen,\n onOpenChange: onOpenChangeProp,\n onOpenChangeComplete: onOpenChangeCompleteProp,\n boundary = 'container',\n children,\n ...coreProps\n}: MenuRootProps): ReactNode {\n // Detect if we are nested inside a parent Menu.Content — if so, operate as\n // a submenu: no popover positioning, Trigger acts as a parent item.\n const parentMenu = useOptionalMenuContext();\n const controls = useOptionalControlsContext();\n const controlsState = useOptionalPlayer(selectControls);\n const container = useOptionalContainer();\n const popupGroup = useOptionalPopupGroup();\n const isSubmenu = parentMenu !== null;\n const { side, align, closeOnEscape, closeOnOutsideClick } = coreProps;\n\n const [core] = useState(() => new MenuCore(
|
|
1
|
+
{"version":3,"file":"menu-root.js","names":[],"sources":["../../../../src/ui/menu/menu-root.tsx"],"sourcesContent":["import { MenuCore, MenuDataAttrs } from '@videojs/core';\nimport {\n createMenu,\n createTransition,\n type MenuChangeDetails,\n type PositioningBoundary,\n selectControls,\n} from '@videojs/core/dom';\nimport { useSnapshot } from '@videojs/store/react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { useOptionalContainer, useOptionalPlayer } from '../../player/context';\nimport { useOptionalPopupGroup } from '../../player/popup-group-context';\nimport { useDestroy } from '../../utils/use-destroy';\nimport { useLatestRef } from '../../utils/use-latest-ref';\nimport { useSafeId } from '../../utils/use-safe-id';\nimport { useOptionalControlsContext } from '../controls/context';\nimport { usePositionedState } from '../hooks/use-positioned-state';\nimport { MenuContextProvider, useOptionalMenuContext } from './context';\n\nexport interface MenuRootProps extends MenuCore.Props {\n /** Boundary used to constrain the root menu popup size. */\n boundary?: PositioningBoundary;\n /** Called when the menu open state changes (fires immediately, before animations). */\n onOpenChange?: (open: boolean, details: MenuChangeDetails) => void;\n /** Called after open/close animations complete. */\n onOpenChangeComplete?: (open: boolean) => void;\n children?: ReactNode;\n}\n\nexport function MenuRoot({\n open: controlledOpen,\n defaultOpen = MenuCore.defaultProps.defaultOpen,\n onOpenChange: onOpenChangeProp,\n onOpenChangeComplete: onOpenChangeCompleteProp,\n boundary = 'container',\n children,\n ...coreProps\n}: MenuRootProps): ReactNode {\n // Detect if we are nested inside a parent Menu.Content — if so, operate as\n // a submenu: no popover positioning, Trigger acts as a parent item.\n const parentMenu = useOptionalMenuContext();\n const controls = useOptionalControlsContext();\n const controlsState = useOptionalPlayer(selectControls);\n const container = useOptionalContainer();\n const popupGroup = useOptionalPopupGroup();\n const isSubmenu = parentMenu !== null;\n const { side, align, closeOnEscape, closeOnOutsideClick } = coreProps;\n\n const [core] = useState(() => new MenuCore(coreProps));\n\n const isControlled = controlledOpen !== undefined;\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const resolvedOpen = controlledOpen ?? uncontrolledOpen;\n\n const onOpenChangeRef = useLatestRef(onOpenChangeProp);\n const onOpenChangeCompleteRef = useLatestRef(onOpenChangeCompleteProp);\n const closeOnEscapeRef = useLatestRef(closeOnEscape);\n const closeOnOutsideClickRef = useLatestRef(closeOnOutsideClick);\n const popupGroupRef = useLatestRef(popupGroup);\n const isSubmenuRef = useLatestRef(isSubmenu);\n\n const [menu] = useState(() => {\n const instance = createMenu({\n transition: createTransition(),\n onOpenChange(nextOpen, details) {\n if (!isControlled) setUncontrolledOpen(nextOpen);\n onOpenChangeRef.current?.(nextOpen, details);\n },\n onOpenChangeComplete(nextOpen) {\n onOpenChangeCompleteRef.current?.(nextOpen);\n },\n closeOnEscape: () => closeOnEscapeRef.current ?? MenuCore.defaultProps.closeOnEscape,\n closeOnOutsideClick: () => closeOnOutsideClickRef.current ?? MenuCore.defaultProps.closeOnOutsideClick,\n group: () => (isSubmenuRef.current ? undefined : popupGroupRef.current),\n });\n\n return instance;\n });\n\n const anchorName = useSafeId();\n const contentId = useSafeId('menu');\n\n useLayoutEffect(() => parentMenu?.menu.registerSubmenu(menu), [menu, parentMenu?.menu]);\n\n // Commit only the open state resolved by controlled/uncontrolled ownership.\n useLayoutEffect(() => {\n menu.syncOpen(resolvedOpen);\n }, [menu, resolvedOpen]);\n\n useEffect(() => {\n if (isSubmenu || controls?.state.visible !== false) return;\n\n menu.close('imperative-action');\n }, [controls?.state.visible, isSubmenu, menu]);\n\n useDestroy(menu);\n\n const input = useSnapshot(menu.input);\n\n useEffect(() => {\n if (!input.active || isSubmenu) return;\n\n return controlsState?.requestControlsLock();\n }, [controlsState?.requestControlsLock, input.active, isSubmenu]);\n\n const preferredState = useMemo(() => {\n core.setProps({ side, align, closeOnEscape, closeOnOutsideClick });\n core.setInput({ ...input, isSubmenu });\n return core.getState();\n }, [core, input, side, align, closeOnEscape, closeOnOutsideClick, isSubmenu]);\n const { state, preferredSide, setPositionedSide } = usePositionedState(preferredState);\n\n const contextValue = useMemo(\n () => ({\n core,\n menu,\n parent: parentMenu,\n state,\n preferredSide,\n setPositionedSide,\n stateAttrMap: MenuDataAttrs,\n contentId,\n anchorName,\n boundary,\n container,\n }),\n [core, menu, parentMenu, state, preferredSide, setPositionedSide, contentId, anchorName, boundary, container]\n );\n\n return <MenuContextProvider value={contextValue}>{children}</MenuContextProvider>;\n}\n\nexport namespace MenuRoot {\n export type Props = MenuRootProps;\n}\n"],"mappings":";;;;;;;;;;;;;;AA8BA,SAAgB,SAAS,EACvB,MAAM,gBACN,cAAc,SAAS,aAAa,aACpC,cAAc,kBACd,sBAAsB,0BACtB,WAAW,aACX,UACA,GAAG,aACwB;CAG3B,MAAM,aAAa,uBAAuB;CAC1C,MAAM,WAAW,2BAA2B;CAC5C,MAAM,gBAAgB,kBAAkB,cAAc;CACtD,MAAM,YAAY,qBAAqB;CACvC,MAAM,aAAa,sBAAsB;CACzC,MAAM,YAAY,eAAe;CACjC,MAAM,EAAE,MAAM,OAAO,eAAe,wBAAwB;CAE5D,MAAM,CAAC,QAAQ,eAAe,IAAI,SAAS,SAAS,CAAC;CAErD,MAAM,eAAe,mBAAmB,KAAA;CACxC,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,WAAW;CACpE,MAAM,eAAe,kBAAkB;CAEvC,MAAM,kBAAkB,aAAa,gBAAgB;CACrD,MAAM,0BAA0B,aAAa,wBAAwB;CACrE,MAAM,mBAAmB,aAAa,aAAa;CACnD,MAAM,yBAAyB,aAAa,mBAAmB;CAC/D,MAAM,gBAAgB,aAAa,UAAU;CAC7C,MAAM,eAAe,aAAa,SAAS;CAE3C,MAAM,CAAC,QAAQ,eAAe;EAe5B,OAdiB,WAAW;GAC1B,YAAY,iBAAiB;GAC7B,aAAa,UAAU,SAAS;IAC9B,IAAI,CAAC,cAAc,oBAAoB,QAAQ;IAC/C,gBAAgB,UAAU,UAAU,OAAO;GAC7C;GACA,qBAAqB,UAAU;IAC7B,wBAAwB,UAAU,QAAQ;GAC5C;GACA,qBAAqB,iBAAiB,WAAW,SAAS,aAAa;GACvE,2BAA2B,uBAAuB,WAAW,SAAS,aAAa;GACnF,aAAc,aAAa,UAAU,KAAA,IAAY,cAAc;EACjE,CAEc;CAChB,CAAC;CAED,MAAM,aAAa,UAAU;CAC7B,MAAM,YAAY,UAAU,MAAM;CAElC,sBAAsB,YAAY,KAAK,gBAAgB,IAAI,GAAG,CAAC,MAAM,YAAY,IAAI,CAAC;CAGtF,sBAAsB;EACpB,KAAK,SAAS,YAAY;CAC5B,GAAG,CAAC,MAAM,YAAY,CAAC;CAEvB,gBAAgB;EACd,IAAI,aAAa,UAAU,MAAM,YAAY,OAAO;EAEpD,KAAK,MAAM,mBAAmB;CAChC,GAAG;EAAC,UAAU,MAAM;EAAS;EAAW;CAAI,CAAC;CAE7C,WAAW,IAAI;CAEf,MAAM,QAAQ,YAAY,KAAK,KAAK;CAEpC,gBAAgB;EACd,IAAI,CAAC,MAAM,UAAU,WAAW;EAEhC,OAAO,eAAe,oBAAoB;CAC5C,GAAG;EAAC,eAAe;EAAqB,MAAM;EAAQ;CAAS,CAAC;CAOhE,MAAM,EAAE,OAAO,eAAe,sBAAsB,mBAL7B,cAAc;EACnC,KAAK,SAAS;GAAE;GAAM;GAAO;GAAe;EAAoB,CAAC;EACjE,KAAK,SAAS;GAAE,GAAG;GAAO;EAAU,CAAC;EACrC,OAAO,KAAK,SAAS;CACvB,GAAG;EAAC;EAAM;EAAO;EAAM;EAAO;EAAe;EAAqB;CAAS,CACS,CAAC;CAmBrF,OAAO,oBAAC,qBAAD;EAAqB,OAjBP,eACZ;GACL;GACA;GACA,QAAQ;GACR;GACA;GACA;GACA,cAAc;GACd;GACA;GACA;GACA;EACF,IACA;GAAC;GAAM;GAAM;GAAY;GAAO;GAAe;GAAmB;GAAW;GAAY;GAAU;EAAS,CAGhE;EAAI;CAA8B,CAAA;AAClF"}
|
|
@@ -1,54 +1,101 @@
|
|
|
1
1
|
import { usePlayer } from "../../player/context.js";
|
|
2
2
|
import { renderElement } from "../../utils/use-render.js";
|
|
3
|
-
import { selectPlayback } from "@videojs/core/dom";
|
|
3
|
+
import { selectMetadata, selectPlayback } from "@videojs/core/dom";
|
|
4
4
|
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
|
5
5
|
import { PosterCore, PosterDataAttrs } from "@videojs/core";
|
|
6
6
|
//#region src/ui/poster/poster.tsx
|
|
7
7
|
/**
|
|
8
8
|
* Displays the video poster image. Shows before playback starts, hides after.
|
|
9
9
|
*
|
|
10
|
+
* Renders an `<img>`, so `srcset`, `sizes`, `loading`, and the rest of the
|
|
11
|
+
* image attributes are yours. Leave the source off and the player's resolved
|
|
12
|
+
* `poster` fills it in.
|
|
13
|
+
*
|
|
14
|
+
* The image is decorative unless you say otherwise. Describe a poster that
|
|
15
|
+
* carries meaning by passing your own `alt`.
|
|
16
|
+
*
|
|
10
17
|
* @example
|
|
11
18
|
* ```tsx
|
|
12
|
-
* <
|
|
19
|
+
* <VideoPlayer poster="poster.jpg">
|
|
20
|
+
* <Poster />
|
|
21
|
+
* </VideoPlayer>
|
|
22
|
+
*
|
|
23
|
+
* <Poster srcSet="poster-480.jpg 480w, poster-1080.jpg 1080w" sizes="100vw" />
|
|
13
24
|
*
|
|
14
25
|
* <Poster
|
|
15
|
-
* src
|
|
16
|
-
*
|
|
17
|
-
*
|
|
26
|
+
* render={({ src, ...props }: ComponentProps<'img'>) =>
|
|
27
|
+
* src ? <Image {...props} src={src} alt="" fill /> : null
|
|
28
|
+
* }
|
|
18
29
|
* />
|
|
19
30
|
* ```
|
|
20
31
|
*/
|
|
21
32
|
const Poster = forwardRef(function Poster(componentProps, forwardedRef) {
|
|
22
33
|
const { render, className, style, ...elementProps } = componentProps;
|
|
23
34
|
const playback = usePlayer(selectPlayback);
|
|
35
|
+
const metadata = usePlayer(selectMetadata);
|
|
24
36
|
const [core] = useState(() => new PosterCore());
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
if (playback) core.setMedia({
|
|
38
|
+
started: playback.started,
|
|
39
|
+
poster: metadata?.poster ?? ""
|
|
40
|
+
});
|
|
41
|
+
const { src: authoredSrc, srcSet: authoredSrcSet } = elementProps;
|
|
42
|
+
const src = authoredSrc ?? (authoredSrcSet === void 0 && playback ? core.getState().src : "");
|
|
43
|
+
const initialLoadState = !src && authoredSrcSet === void 0 ? "none" : "loading";
|
|
44
|
+
const [request, setRequest] = useState(() => ({
|
|
45
|
+
src,
|
|
46
|
+
srcSet: authoredSrcSet,
|
|
47
|
+
state: initialLoadState
|
|
48
|
+
}));
|
|
28
49
|
const imgRef = useRef(null);
|
|
50
|
+
const matchesRequest = request.src === src && request.srcSet === authoredSrcSet;
|
|
51
|
+
if (!matchesRequest) setRequest({
|
|
52
|
+
src,
|
|
53
|
+
srcSet: authoredSrcSet,
|
|
54
|
+
state: initialLoadState
|
|
55
|
+
});
|
|
56
|
+
const loadState = matchesRequest ? request.state : initialLoadState;
|
|
57
|
+
if (playback) core.setImageLoadState(loadState);
|
|
58
|
+
const state = playback ? core.getState() : null;
|
|
29
59
|
useEffect(() => {
|
|
30
60
|
const img = imgRef.current;
|
|
31
|
-
if (img
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
61
|
+
if (!img) return;
|
|
62
|
+
if (img.naturalWidth > 0) setRequest({
|
|
63
|
+
src,
|
|
64
|
+
srcSet: authoredSrcSet,
|
|
65
|
+
state: "loaded"
|
|
66
|
+
});
|
|
67
|
+
else if (img.complete && (img.getAttribute("src") || img.hasAttribute("srcset"))) setRequest({
|
|
68
|
+
src,
|
|
69
|
+
srcSet: authoredSrcSet,
|
|
70
|
+
state: "error"
|
|
71
|
+
});
|
|
35
72
|
}, []);
|
|
36
|
-
|
|
37
|
-
|
|
73
|
+
const handleLoad = useCallback(() => setRequest({
|
|
74
|
+
src,
|
|
75
|
+
srcSet: authoredSrcSet,
|
|
76
|
+
state: "loaded"
|
|
77
|
+
}), [src, authoredSrcSet]);
|
|
78
|
+
const handleError = useCallback(() => setRequest({
|
|
79
|
+
src,
|
|
80
|
+
srcSet: authoredSrcSet,
|
|
81
|
+
state: "error"
|
|
82
|
+
}), [src, authoredSrcSet]);
|
|
83
|
+
if (!playback || !state) return null;
|
|
38
84
|
return renderElement("img", {
|
|
39
85
|
render,
|
|
40
86
|
className,
|
|
41
87
|
style
|
|
42
88
|
}, {
|
|
43
|
-
state
|
|
89
|
+
state,
|
|
44
90
|
stateAttrMap: PosterDataAttrs,
|
|
45
91
|
ref: [forwardedRef, imgRef],
|
|
46
92
|
props: [
|
|
47
93
|
{ alt: "" },
|
|
48
94
|
elementProps,
|
|
49
95
|
{
|
|
50
|
-
|
|
51
|
-
onLoad: handleLoad
|
|
96
|
+
src: src || void 0,
|
|
97
|
+
onLoad: handleLoad,
|
|
98
|
+
onError: handleError
|
|
52
99
|
}
|
|
53
100
|
]
|
|
54
101
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poster.js","names":[],"sources":["../../../../src/ui/poster/poster.tsx"],"sourcesContent":["import { PosterCore, PosterDataAttrs } from '@videojs/core';\nimport { logMissingFeature, selectPlayback } from '@videojs/core/dom';\nimport type { ForwardedRef
|
|
1
|
+
{"version":3,"file":"poster.js","names":[],"sources":["../../../../src/ui/poster/poster.tsx"],"sourcesContent":["import { PosterCore, PosterDataAttrs, type PosterImageLoadState } from '@videojs/core';\nimport { logMissingFeature, selectMetadata, selectPlayback } from '@videojs/core/dom';\nimport type { ForwardedRef } from 'react';\nimport { forwardRef, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { usePlayer } from '../../player/context';\nimport type { UIComponentProps } from '../../utils/types';\nimport { renderElement } from '../../utils/use-render';\n\nexport interface PosterProps extends UIComponentProps<'img', PosterCore.State> {}\n\n/** The source currently requested from the image, and how it is faring. */\ninterface ImageRequest {\n src: string;\n srcSet: string | undefined;\n state: PosterImageLoadState;\n}\n\n/**\n * Displays the video poster image. Shows before playback starts, hides after.\n *\n * Renders an `<img>`, so `srcset`, `sizes`, `loading`, and the rest of the\n * image attributes are yours. Leave the source off and the player's resolved\n * `poster` fills it in.\n *\n * The image is decorative unless you say otherwise. Describe a poster that\n * carries meaning by passing your own `alt`.\n *\n * @example\n * ```tsx\n * <VideoPlayer poster=\"poster.jpg\">\n * <Poster />\n * </VideoPlayer>\n *\n * <Poster srcSet=\"poster-480.jpg 480w, poster-1080.jpg 1080w\" sizes=\"100vw\" />\n *\n * <Poster\n * render={({ src, ...props }: ComponentProps<'img'>) =>\n * src ? <Image {...props} src={src} alt=\"\" fill /> : null\n * }\n * />\n * ```\n */\nexport const Poster = forwardRef(function Poster(\n componentProps: PosterProps,\n forwardedRef: ForwardedRef<HTMLImageElement>\n) {\n const { render, className, style, ...elementProps } = componentProps;\n\n const playback = usePlayer(selectPlayback);\n const metadata = usePlayer(selectMetadata);\n\n const [core] = useState(() => new PosterCore());\n\n // The metadata feature is optional: without it nothing resolves a URL, and\n // this stays a visibility wrapper around whatever `src` was passed.\n if (playback) {\n core.setMedia({\n started: playback.started,\n poster: metadata?.poster ?? '',\n });\n }\n\n const { src: authoredSrc, srcSet: authoredSrcSet } = elementProps as { src?: string; srcSet?: string };\n\n // Either authored source makes the image yours, matching `hasSource` in the\n // HTML element. Filling `src` alongside a `srcset` would inject the player's\n // poster into your candidate set as the 1x entry.\n const src = authoredSrc ?? (authoredSrcSet === undefined && playback ? core.getState().src : '');\n\n const initialLoadState: PosterImageLoadState = !src && authoredSrcSet === undefined ? 'none' : 'loading';\n const [request, setRequest] = useState<ImageRequest>(() => ({\n src,\n srcSet: authoredSrcSet,\n state: initialLoadState,\n }));\n const imgRef = useRef<HTMLImageElement | null>(null);\n\n // Keep only the active request. Retaining a settled source by value would\n // resurrect its old state when the image moved A -> B -> A, even though the\n // second A is a new request. `srcSet` is part of the identity because `src`\n // stays empty when it is the only source.\n const matchesRequest = request.src === src && request.srcSet === authoredSrcSet;\n if (!matchesRequest) setRequest({ src, srcSet: authoredSrcSet, state: initialLoadState });\n const loadState = matchesRequest ? request.state : initialLoadState;\n\n if (playback) core.setImageLoadState(loadState);\n\n const state = playback ? core.getState() : null;\n\n // An image can already be settled when we first see it — hydrated from server\n // markup, say — in which case neither `load` nor `error` ever fires. Decoded\n // pixels stand on their own; the absence of them only means failure once\n // `complete` can be trusted, which takes a source on the image itself, since one\n // sourced by a `<picture>` an override wrapped it in is `complete` regardless.\n //\n // Only when we first see it. A later source change leaves the previous request's\n // pixels in place until the new one settles, so reading them again would call\n // the new source loaded while it is still fetching. `load` and `error` cover\n // every source after this one, the way the HTML element reads an image once.\n // biome-ignore lint/correctness/useExhaustiveDependencies: reads the first source only, at mount\n useEffect(() => {\n const img = imgRef.current;\n if (!img) return;\n\n if (img.naturalWidth > 0) setRequest({ src, srcSet: authoredSrcSet, state: 'loaded' });\n else if (img.complete && (img.getAttribute('src') || img.hasAttribute('srcset'))) {\n setRequest({ src, srcSet: authoredSrcSet, state: 'error' });\n }\n }, []);\n\n // Recorded against the source this render asked for, not the one on the\n // element: a `render` override is free to rewrite it.\n const handleLoad = useCallback(\n () => setRequest({ src, srcSet: authoredSrcSet, state: 'loaded' }),\n [src, authoredSrcSet]\n );\n const handleError = useCallback(\n () => setRequest({ src, srcSet: authoredSrcSet, state: 'error' }),\n [src, authoredSrcSet]\n );\n\n if (!playback || !state) {\n if (__DEV__) logMissingFeature('Poster', 'playback');\n return null;\n }\n\n return renderElement(\n 'img',\n { render, className, style },\n {\n state,\n stateAttrMap: PosterDataAttrs,\n ref: [forwardedRef, imgRef],\n props: [\n { alt: '' },\n elementProps,\n {\n // An empty `src` requests the document URL, so leave the attribute off.\n src: src || undefined,\n onLoad: handleLoad,\n onError: handleError,\n },\n ],\n }\n );\n});\n\nexport namespace Poster {\n export type Props = PosterProps;\n export type State = PosterCore.State;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,SAAS,WAAW,SAAS,OACxC,gBACA,cACA;CACA,MAAM,EAAE,QAAQ,WAAW,OAAO,GAAG,iBAAiB;CAEtD,MAAM,WAAW,UAAU,cAAc;CACzC,MAAM,WAAW,UAAU,cAAc;CAEzC,MAAM,CAAC,QAAQ,eAAe,IAAI,WAAW,CAAC;CAI9C,IAAI,UACF,KAAK,SAAS;EACZ,SAAS,SAAS;EAClB,QAAQ,UAAU,UAAU;CAC9B,CAAC;CAGH,MAAM,EAAE,KAAK,aAAa,QAAQ,mBAAmB;CAKrD,MAAM,MAAM,gBAAgB,mBAAmB,KAAA,KAAa,WAAW,KAAK,SAAS,CAAC,CAAC,MAAM;CAE7F,MAAM,mBAAyC,CAAC,OAAO,mBAAmB,KAAA,IAAY,SAAS;CAC/F,MAAM,CAAC,SAAS,cAAc,gBAA8B;EAC1D;EACA,QAAQ;EACR,OAAO;CACT,EAAE;CACF,MAAM,SAAS,OAAgC,IAAI;CAMnD,MAAM,iBAAiB,QAAQ,QAAQ,OAAO,QAAQ,WAAW;CACjE,IAAI,CAAC,gBAAgB,WAAW;EAAE;EAAK,QAAQ;EAAgB,OAAO;CAAiB,CAAC;CACxF,MAAM,YAAY,iBAAiB,QAAQ,QAAQ;CAEnD,IAAI,UAAU,KAAK,kBAAkB,SAAS;CAE9C,MAAM,QAAQ,WAAW,KAAK,SAAS,IAAI;CAa3C,gBAAgB;EACd,MAAM,MAAM,OAAO;EACnB,IAAI,CAAC,KAAK;EAEV,IAAI,IAAI,eAAe,GAAG,WAAW;GAAE;GAAK,QAAQ;GAAgB,OAAO;EAAS,CAAC;OAChF,IAAI,IAAI,aAAa,IAAI,aAAa,KAAK,KAAK,IAAI,aAAa,QAAQ,IAC5E,WAAW;GAAE;GAAK,QAAQ;GAAgB,OAAO;EAAQ,CAAC;CAE9D,GAAG,CAAC,CAAC;CAIL,MAAM,aAAa,kBACX,WAAW;EAAE;EAAK,QAAQ;EAAgB,OAAO;CAAS,CAAC,GACjE,CAAC,KAAK,cAAc,CACtB;CACA,MAAM,cAAc,kBACZ,WAAW;EAAE;EAAK,QAAQ;EAAgB,OAAO;CAAQ,CAAC,GAChE,CAAC,KAAK,cAAc,CACtB;CAEA,IAAI,CAAC,YAAY,CAAC,OAEhB,OAAO;CAGT,OAAO,cACL,OACA;EAAE;EAAQ;EAAW;CAAM,GAC3B;EACE;EACA,cAAc;EACd,KAAK,CAAC,cAAc,MAAM;EAC1B,OAAO;GACL,EAAE,KAAK,GAAG;GACV;GACA;IAEE,KAAK,OAAO,KAAA;IACZ,QAAQ;IACR,SAAS;GACX;EACF;CACF,CACF;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider-preview.js","names":[],"sources":["../../../../src/ui/slider/slider-preview.tsx"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"slider-preview.js","names":[],"sources":["../../../../src/ui/slider/slider-preview.tsx"],"sourcesContent":["import type { SliderPreviewProps as CoreSliderPreviewProps, SliderState } from '@videojs/core';\nimport { getSliderPreviewStyle } from '@videojs/core/dom';\nimport { observeResize } from '@videojs/utils/dom';\nimport type { ForwardedRef } from 'react';\nimport { forwardRef, useEffect, useRef, useState } from 'react';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { renderElement } from '../../utils/use-render';\nimport { useSliderContext } from './context';\n\nexport interface SliderPreviewProps extends CoreSliderPreviewProps, UIComponentProps<'div', SliderState> {}\n\n/** Positioning container for preview content that tracks the pointer along the slider. */\nexport const SliderPreview = forwardRef(function SliderPreview(\n componentProps: SliderPreviewProps,\n forwardedRef: ForwardedRef<HTMLDivElement>\n) {\n const { render, className, style, overflow = 'clamp', ...elementProps } = componentProps;\n\n const context = useSliderContext();\n const { state } = context;\n\n const measureRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n\n useEffect(() => {\n const el = measureRef.current;\n if (!el) return;\n\n return observeResize(el, ([entry]) => {\n setWidth(entry!.contentRect.width);\n });\n }, []);\n\n const positionStyle = getSliderPreviewStyle(width, overflow);\n\n return renderElement(\n 'div',\n { render, className, style },\n {\n state,\n stateAttrMap: context.stateAttrMap,\n ref: [forwardedRef, measureRef],\n props: [{ style: positionStyle }, elementProps],\n }\n );\n});\n\nexport namespace SliderPreview {\n export type Props = SliderPreviewProps;\n}\n"],"mappings":";;;;;;;AAaA,MAAa,gBAAgB,WAAW,SAAS,cAC/C,gBACA,cACA;CACA,MAAM,EAAE,QAAQ,WAAW,OAAO,WAAW,SAAS,GAAG,iBAAiB;CAE1E,MAAM,UAAU,iBAAiB;CACjC,MAAM,EAAE,UAAU;CAElB,MAAM,aAAa,OAAuB,IAAI;CAC9C,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CAEpC,gBAAgB;EACd,MAAM,KAAK,WAAW;EACtB,IAAI,CAAC,IAAI;EAET,OAAO,cAAc,KAAK,CAAC,WAAW;GACpC,SAAS,MAAO,YAAY,KAAK;EACnC,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,gBAAgB,sBAAsB,OAAO,QAAQ;CAE3D,OAAO,cACL,OACA;EAAE;EAAQ;EAAW;CAAM,GAC3B;EACE;EACA,cAAc,QAAQ;EACtB,KAAK,CAAC,cAAc,UAAU;EAC9B,OAAO,CAAC,EAAE,OAAO,cAAc,GAAG,YAAY;CAChD,CACF;AACF,CAAC"}
|
|
@@ -3,14 +3,8 @@ import { mergeProps } from "./merge-props.js";
|
|
|
3
3
|
import { getStateDataAttrs } from "@videojs/core/dom";
|
|
4
4
|
import { cloneElement, createElement, isValidElement } from "react";
|
|
5
5
|
import { isFunction } from "@videojs/utils/predicate";
|
|
6
|
+
import { resolveClassName } from "@videojs/utils/style";
|
|
6
7
|
//#region src/utils/use-render.tsx
|
|
7
|
-
/** Check if a value is a render prop (function or React element). */
|
|
8
|
-
function isRenderProp(value) {
|
|
9
|
-
return isFunction(value) || isValidElement(value);
|
|
10
|
-
}
|
|
11
|
-
function resolveClassName(className, state) {
|
|
12
|
-
return isFunction(className) ? className(state) : className;
|
|
13
|
-
}
|
|
14
8
|
function resolveStyle(style, state) {
|
|
15
9
|
return isFunction(style) ? style(state) : style;
|
|
16
10
|
}
|
|
@@ -67,6 +61,6 @@ function renderElement(element, componentProps, params) {
|
|
|
67
61
|
return createElement(element, mergedProps);
|
|
68
62
|
}
|
|
69
63
|
//#endregion
|
|
70
|
-
export {
|
|
64
|
+
export { renderElement };
|
|
71
65
|
|
|
72
66
|
//# sourceMappingURL=use-render.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-render.js","names":[],"sources":["../../../src/utils/use-render.tsx"],"sourcesContent":["import { getStateDataAttrs, type StateAttrMap } from '@videojs/core/dom';\nimport { isFunction } from '@videojs/utils/predicate';\nimport type { CSSProperties, ReactElement, Ref } from 'react';\nimport { cloneElement, createElement, isValidElement } from 'react';\nimport { mergeProps } from './merge-props';\nimport type { HTMLProps, RenderProp } from './types';\nimport { composeRefs } from './use-composed-refs';\n\n/** Check if a value is a render prop (function or React element). */\nexport function isRenderProp(value: unknown): value is RenderProp<unknown> {\n return isFunction(value) || isValidElement(value);\n}\n\ntype IntrinsicTagName = keyof React.JSX.IntrinsicElements;\n\nexport interface UseRenderComponentProps<State> {\n className?: string | ((state: State) => string | undefined) | undefined;\n style?: CSSProperties | ((state: State) => CSSProperties | undefined) | undefined;\n render?: RenderProp<State> | undefined;\n}\n\nexport interface UseRenderParameters<State, RenderedElementType extends Element> {\n state: State;\n ref?: Ref<RenderedElementType> | Ref<RenderedElementType>[] | undefined;\n props?: object | object[] | undefined;\n stateAttrMap?: StateAttrMap<State> | undefined;\n}\n\nfunction
|
|
1
|
+
{"version":3,"file":"use-render.js","names":[],"sources":["../../../src/utils/use-render.tsx"],"sourcesContent":["import { getStateDataAttrs, type StateAttrMap } from '@videojs/core/dom';\nimport { isFunction } from '@videojs/utils/predicate';\nimport { resolveClassName } from '@videojs/utils/style';\nimport type { CSSProperties, ReactElement, Ref } from 'react';\nimport { cloneElement, createElement, isValidElement } from 'react';\nimport { mergeProps } from './merge-props';\nimport type { HTMLProps, RenderProp } from './types';\nimport { composeRefs } from './use-composed-refs';\n\n/** Check if a value is a render prop (function or React element). */\nexport function isRenderProp(value: unknown): value is RenderProp<unknown> {\n return isFunction(value) || isValidElement(value);\n}\n\ntype IntrinsicTagName = keyof React.JSX.IntrinsicElements;\n\nexport interface UseRenderComponentProps<State> {\n className?: string | ((state: State) => string | undefined) | undefined;\n style?: CSSProperties | ((state: State) => CSSProperties | undefined) | undefined;\n render?: RenderProp<State> | undefined;\n}\n\nexport interface UseRenderParameters<State, RenderedElementType extends Element> {\n state: State;\n ref?: Ref<RenderedElementType> | Ref<RenderedElementType>[] | undefined;\n props?: object | object[] | undefined;\n stateAttrMap?: StateAttrMap<State> | undefined;\n}\n\nfunction resolveStyle<State>(\n style: CSSProperties | ((state: State) => CSSProperties | undefined) | undefined,\n state: State\n): CSSProperties | undefined {\n return isFunction(style) ? style(state) : style;\n}\n\nfunction getElementRef(element: ReactElement): Ref<unknown> | undefined {\n // React 19+ uses element.props.ref, older versions use element.ref\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const elementAny = element as any;\n return elementAny.ref ?? elementAny.props?.ref;\n}\n\n/**\n * Render a UI component element.\n *\n * Handles:\n * - Default tag rendering\n * - Render prop (element or function)\n * - Props merging (event handlers chained, className concatenated, style merged)\n * - Ref composition\n * - className/style as functions of state\n *\n * @public\n * @example\n * ```tsx\n * return renderElement('button', componentProps, {\n * state,\n * ref: [forwardedRef, buttonRef],\n * props: [{ type: 'button' }, elementProps, getButtonProps],\n * });\n * ```\n */\nexport function renderElement<\n State extends object,\n RenderedElementType extends Element,\n TagName extends IntrinsicTagName,\n>(\n element: TagName,\n componentProps: UseRenderComponentProps<State>,\n params: UseRenderParameters<State, RenderedElementType>\n): ReactElement | null {\n const { className: classNameProp, style: styleProp, render } = componentProps;\n const { state, ref, props, stateAttrMap } = params;\n\n // Resolve className and style if they're functions\n const className = resolveClassName(classNameProp, state);\n const style = resolveStyle(styleProp, state);\n\n // Generate data attributes only when a component explicitly opts in with a\n // mapping. State is still passed to render/className/style callbacks.\n const stateDataAttrs = stateAttrMap ? getStateDataAttrs(state, stateAttrMap) : {};\n\n // Merge: state data attrs first, then props (so props can override)\n const propsArray = Array.isArray(props) ? props : props ? [props] : [];\n const mergedProps = mergeProps(stateDataAttrs, ...(propsArray as Record<string, unknown>[]));\n\n if (className !== undefined) {\n // Add resolved className and style\n mergedProps.className = mergedProps.className ? `${mergedProps.className} ${className}` : className;\n }\n\n if (style !== undefined) {\n mergedProps.style = mergedProps.style ? { ...(mergedProps.style as CSSProperties), ...style } : style;\n }\n\n if (isFunction(render)) {\n // Render function: call with props and state\n const mergedRef = composeRefs(ref, mergedProps.ref);\n return render({ ...mergedProps, ref: mergedRef } as HTMLProps, state);\n }\n\n if (isValidElement(render)) {\n const elementRef = getElementRef(render);\n\n const mergedRef = composeRefs(ref, mergedProps.ref, elementRef);\n\n const elementProps = mergeProps(mergedProps, render.props as Record<string, unknown>);\n elementProps.ref = mergedRef;\n\n return cloneElement(render, elementProps);\n }\n\n // Default tag\n const mergedRef = composeRefs(ref, mergedProps.ref);\n mergedProps.ref = mergedRef;\n\n return createElement(element, mergedProps);\n}\n\nexport namespace renderElement {\n export type ComponentProps<State> = UseRenderComponentProps<State>;\n export type Parameters<State, RenderedElementType extends Element> = UseRenderParameters<State, RenderedElementType>;\n}\n"],"mappings":";;;;;;;AA6BA,SAAS,aACP,OACA,OAC2B;CAC3B,OAAO,WAAW,KAAK,IAAI,MAAM,KAAK,IAAI;AAC5C;AAEA,SAAS,cAAc,SAAiD;CAGtE,MAAM,aAAa;CACnB,OAAO,WAAW,OAAO,WAAW,OAAO;AAC7C;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,cAKd,SACA,gBACA,QACqB;CACrB,MAAM,EAAE,WAAW,eAAe,OAAO,WAAW,WAAW;CAC/D,MAAM,EAAE,OAAO,KAAK,OAAO,iBAAiB;CAG5C,MAAM,YAAY,iBAAiB,eAAe,KAAK;CACvD,MAAM,QAAQ,aAAa,WAAW,KAAK;CAQ3C,MAAM,cAAc,WAJG,eAAe,kBAAkB,OAAO,YAAY,IAAI,CAAC,GAIjC,GAD5B,MAAM,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC,KAAK,IAAI,CAAC,CACsB;CAE3F,IAAI,cAAc,KAAA,GAEhB,YAAY,YAAY,YAAY,YAAY,GAAG,YAAY,UAAU,GAAG,cAAc;CAG5F,IAAI,UAAU,KAAA,GACZ,YAAY,QAAQ,YAAY,QAAQ;EAAE,GAAI,YAAY;EAAyB,GAAG;CAAM,IAAI;CAGlG,IAAI,WAAW,MAAM,GAAG;EAEtB,MAAM,YAAY,YAAY,KAAK,YAAY,GAAG;EAClD,OAAO,OAAO;GAAE,GAAG;GAAa,KAAK;EAAU,GAAgB,KAAK;CACtE;CAEA,IAAI,eAAe,MAAM,GAAG;EAC1B,MAAM,aAAa,cAAc,MAAM;EAEvC,MAAM,YAAY,YAAY,KAAK,YAAY,KAAK,UAAU;EAE9D,MAAM,eAAe,WAAW,aAAa,OAAO,KAAgC;EACpF,aAAa,MAAM;EAEnB,OAAO,aAAa,QAAQ,YAAY;CAC1C;CAIA,YAAY,MADM,YAAY,KAAK,YAAY,GACrB;CAE1B,OAAO,cAAc,SAAS,WAAW;AAC3C"}
|