@videojs/react 10.0.0-beta.30 → 10.0.0-beta.31

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.
Files changed (130) hide show
  1. package/dist/default/i18n/context.js.map +1 -1
  2. package/dist/default/i18n/create-i18n.js +3 -1
  3. package/dist/default/i18n/create-i18n.js.map +1 -1
  4. package/dist/default/i18n/get-provider-root-props.js +4 -2
  5. package/dist/default/i18n/get-provider-root-props.js.map +1 -1
  6. package/dist/default/player/container.js +16 -7
  7. package/dist/default/player/container.js.map +1 -1
  8. package/dist/default/presets/audio/minimal-skin.css +39 -7
  9. package/dist/default/presets/audio/skin.css +31 -7
  10. package/dist/default/presets/live-audio/minimal-skin.css +39 -7
  11. package/dist/default/presets/live-audio/skin.css +31 -7
  12. package/dist/default/presets/live-video/minimal-skin.css +39 -7
  13. package/dist/default/presets/live-video/minimal-skin.js +4 -1
  14. package/dist/default/presets/live-video/minimal-skin.js.map +1 -1
  15. package/dist/default/presets/live-video/minimal-skin.tailwind.js +4 -1
  16. package/dist/default/presets/live-video/minimal-skin.tailwind.js.map +1 -1
  17. package/dist/default/presets/live-video/skin.css +31 -7
  18. package/dist/default/presets/live-video/skin.js +4 -1
  19. package/dist/default/presets/live-video/skin.js.map +1 -1
  20. package/dist/default/presets/live-video/skin.tailwind.js +4 -1
  21. package/dist/default/presets/live-video/skin.tailwind.js.map +1 -1
  22. package/dist/default/presets/video/minimal-skin.css +39 -7
  23. package/dist/default/presets/video/minimal-skin.js +27 -11
  24. package/dist/default/presets/video/minimal-skin.js.map +1 -1
  25. package/dist/default/presets/video/minimal-skin.tailwind.js +28 -12
  26. package/dist/default/presets/video/minimal-skin.tailwind.js.map +1 -1
  27. package/dist/default/presets/video/skin.css +31 -7
  28. package/dist/default/presets/video/skin.js +27 -11
  29. package/dist/default/presets/video/skin.js.map +1 -1
  30. package/dist/default/presets/video/skin.tailwind.js +28 -12
  31. package/dist/default/presets/video/skin.tailwind.js.map +1 -1
  32. package/dist/default/skins/dist/default/default/tailwind/components/button-group.js +1 -1
  33. package/dist/default/skins/dist/default/default/tailwind/components/button-group.js.map +1 -1
  34. package/dist/default/skins/dist/default/default/tailwind/components/controls.js +1 -1
  35. package/dist/default/skins/dist/default/default/tailwind/components/controls.js.map +1 -1
  36. package/dist/default/skins/dist/default/default/tailwind/components/menu.js +8 -7
  37. package/dist/default/skins/dist/default/default/tailwind/components/menu.js.map +1 -1
  38. package/dist/default/skins/dist/default/default/tailwind/components/time.js +1 -1
  39. package/dist/default/skins/dist/default/default/tailwind/components/time.js.map +1 -1
  40. package/dist/default/skins/dist/default/minimal/tailwind/components/button-group.js +1 -1
  41. package/dist/default/skins/dist/default/minimal/tailwind/components/button-group.js.map +1 -1
  42. package/dist/default/skins/dist/default/minimal/tailwind/components/controls.js +1 -1
  43. package/dist/default/skins/dist/default/minimal/tailwind/components/controls.js.map +1 -1
  44. package/dist/default/skins/dist/default/minimal/tailwind/components/menu.js +8 -7
  45. package/dist/default/skins/dist/default/minimal/tailwind/components/menu.js.map +1 -1
  46. package/dist/default/skins/dist/default/minimal/tailwind/components/time.js +2 -2
  47. package/dist/default/skins/dist/default/minimal/tailwind/components/time.js.map +1 -1
  48. package/dist/default/ui/hooks/use-slider.js +1 -2
  49. package/dist/default/ui/hooks/use-slider.js.map +1 -1
  50. package/dist/dev/i18n/context.d.ts +3 -1
  51. package/dist/dev/i18n/context.d.ts.map +1 -1
  52. package/dist/dev/i18n/context.js.map +1 -1
  53. package/dist/dev/i18n/create-i18n.d.ts.map +1 -1
  54. package/dist/dev/i18n/create-i18n.js +3 -1
  55. package/dist/dev/i18n/create-i18n.js.map +1 -1
  56. package/dist/dev/i18n/get-provider-root-props.js +4 -2
  57. package/dist/dev/i18n/get-provider-root-props.js.map +1 -1
  58. package/dist/dev/player/container.d.ts.map +1 -1
  59. package/dist/dev/player/container.js +16 -7
  60. package/dist/dev/player/container.js.map +1 -1
  61. package/dist/dev/presets/audio/minimal-skin.css +39 -7
  62. package/dist/dev/presets/audio/skin.css +31 -7
  63. package/dist/dev/presets/live-audio/minimal-skin.css +39 -7
  64. package/dist/dev/presets/live-audio/skin.css +31 -7
  65. package/dist/dev/presets/live-video/minimal-skin.css +39 -7
  66. package/dist/dev/presets/live-video/minimal-skin.js +4 -1
  67. package/dist/dev/presets/live-video/minimal-skin.js.map +1 -1
  68. package/dist/dev/presets/live-video/minimal-skin.tailwind.js +4 -1
  69. package/dist/dev/presets/live-video/minimal-skin.tailwind.js.map +1 -1
  70. package/dist/dev/presets/live-video/skin.css +31 -7
  71. package/dist/dev/presets/live-video/skin.js +4 -1
  72. package/dist/dev/presets/live-video/skin.js.map +1 -1
  73. package/dist/dev/presets/live-video/skin.tailwind.js +4 -1
  74. package/dist/dev/presets/live-video/skin.tailwind.js.map +1 -1
  75. package/dist/dev/presets/video/minimal-skin.css +39 -7
  76. package/dist/dev/presets/video/minimal-skin.d.ts.map +1 -1
  77. package/dist/dev/presets/video/minimal-skin.js +27 -11
  78. package/dist/dev/presets/video/minimal-skin.js.map +1 -1
  79. package/dist/dev/presets/video/minimal-skin.tailwind.d.ts.map +1 -1
  80. package/dist/dev/presets/video/minimal-skin.tailwind.js +28 -12
  81. package/dist/dev/presets/video/minimal-skin.tailwind.js.map +1 -1
  82. package/dist/dev/presets/video/skin.css +31 -7
  83. package/dist/dev/presets/video/skin.d.ts.map +1 -1
  84. package/dist/dev/presets/video/skin.js +27 -11
  85. package/dist/dev/presets/video/skin.js.map +1 -1
  86. package/dist/dev/presets/video/skin.tailwind.d.ts.map +1 -1
  87. package/dist/dev/presets/video/skin.tailwind.js +28 -12
  88. package/dist/dev/presets/video/skin.tailwind.js.map +1 -1
  89. package/dist/dev/skins/dist/default/default/tailwind/components/button-group.js +1 -1
  90. package/dist/dev/skins/dist/default/default/tailwind/components/button-group.js.map +1 -1
  91. package/dist/dev/skins/dist/default/default/tailwind/components/controls.js +1 -1
  92. package/dist/dev/skins/dist/default/default/tailwind/components/controls.js.map +1 -1
  93. package/dist/dev/skins/dist/default/default/tailwind/components/menu.js +8 -7
  94. package/dist/dev/skins/dist/default/default/tailwind/components/menu.js.map +1 -1
  95. package/dist/dev/skins/dist/default/default/tailwind/components/time.js +1 -1
  96. package/dist/dev/skins/dist/default/default/tailwind/components/time.js.map +1 -1
  97. package/dist/dev/skins/dist/default/minimal/tailwind/components/button-group.js +1 -1
  98. package/dist/dev/skins/dist/default/minimal/tailwind/components/button-group.js.map +1 -1
  99. package/dist/dev/skins/dist/default/minimal/tailwind/components/controls.js +1 -1
  100. package/dist/dev/skins/dist/default/minimal/tailwind/components/controls.js.map +1 -1
  101. package/dist/dev/skins/dist/default/minimal/tailwind/components/menu.js +8 -7
  102. package/dist/dev/skins/dist/default/minimal/tailwind/components/menu.js.map +1 -1
  103. package/dist/dev/skins/dist/default/minimal/tailwind/components/time.js +2 -2
  104. package/dist/dev/skins/dist/default/minimal/tailwind/components/time.js.map +1 -1
  105. package/dist/dev/ui/hooks/use-slider.d.ts.map +1 -1
  106. package/dist/dev/ui/hooks/use-slider.js +1 -2
  107. package/dist/dev/ui/hooks/use-slider.js.map +1 -1
  108. package/docs/README.md +1 -1
  109. package/docs/concepts/media-sources.md +26 -2
  110. package/docs/concepts/skins.md +48 -16
  111. package/docs/how-to/customize-skins.md +7933 -50
  112. package/docs/how-to/i18n-switch-locale.md +27 -0
  113. package/docs/how-to/installation.md +4 -4
  114. package/docs/how-to/migrate-from-plyr.md +1 -1
  115. package/docs/llms.txt +7 -0
  116. package/docs/reference/cloudflare-video.md +223 -0
  117. package/docs/reference/dash-video.md +55 -0
  118. package/docs/reference/feature-metadata.md +3 -1
  119. package/docs/reference/hls-audio.md +27 -1
  120. package/docs/reference/hls-video.md +39 -1
  121. package/docs/reference/hlsjs-video.md +627 -0
  122. package/docs/reference/native-hls-video.md +41 -0
  123. package/docs/reference/shaka-video.md +359 -0
  124. package/docs/reference/spotify-audio.md +188 -0
  125. package/docs/reference/tiktok-video.md +280 -0
  126. package/docs/reference/title.md +1 -1
  127. package/docs/reference/twitch-video.md +211 -0
  128. package/docs/reference/vimeo-video.md +736 -0
  129. package/docs/reference/youtube-video.md +339 -0
  130. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../../../src/i18n/context.tsx"],"sourcesContent":["import {\n createTranslator,\n DEFAULT_LOCALE,\n getI18nTranslations,\n type Locale,\n onI18nRegistryChange,\n type Translations,\n type Translator,\n} from '@videojs/core/i18n';\nimport { createContext, useContext, useEffect, useMemo, useReducer } from 'react';\n\nexport type AddLocaleRoot = () => () => void;\n\nexport interface I18nContextValue {\n translator: Translator;\n locale: Locale;\n /** True when a provider received an explicit locale prop. */\n localeFromProp: boolean;\n /** Overrides passed to this provider. */\n translations?: Partial<Translations>;\n /** Callback inherited by nested locale roots. */\n onActiveLocaleChange?: (locale: Locale) => void;\n}\n\n/** React context carrying the active translator and locale. @public */\nexport const I18nContext = createContext<I18nContextValue | null>(null);\n\nexport const LocaleRootContext = createContext<AddLocaleRoot | undefined>(undefined);\n\n/**\n * Returns the translator for the nearest `I18nProvider`, or English defaults when none is mounted.\n *\n * @public\n */\nexport function useTranslator(): Translator {\n const ctx = useContext(I18nContext);\n const [registryEpoch, invalidateRegistry] = useReducer((epoch: number) => epoch + 1, 0);\n\n useEffect(() => {\n return onI18nRegistryChange(() => invalidateRegistry());\n }, []);\n\n const fallback = useMemo(() => {\n void registryEpoch;\n return createTranslator(getI18nTranslations(DEFAULT_LOCALE), DEFAULT_LOCALE);\n }, [registryEpoch]);\n\n if (!ctx) {\n return fallback;\n }\n return ctx.translator;\n}\n\n/**\n * Returns the active BCP 47 locale tag from the nearest `I18nProvider`, or `'en'` when none is mounted.\n *\n * @public\n */\nexport function useLocale(): Locale {\n const ctx = useContext(I18nContext);\n return ctx?.locale ?? DEFAULT_LOCALE;\n}\n"],"mappings":";;;;AAyBA,MAAa,cAAc,cAAuC,IAAI;AAEtE,MAAa,oBAAoB,cAAyC,KAAA,CAAS;;;;;;AAOnF,SAAgB,gBAA4B;CAC1C,MAAM,MAAM,WAAW,WAAW;CAClC,MAAM,CAAC,eAAe,sBAAsB,YAAY,UAAkB,QAAQ,GAAG,CAAC;CAEtF,gBAAgB;EACd,OAAO,2BAA2B,mBAAmB,CAAC;CACxD,GAAG,CAAC,CAAC;CAEL,MAAM,WAAW,cAAc;EAE7B,OAAO,iBAAiB,oBAAoB,cAAc,GAAG,cAAc;CAC7E,GAAG,CAAC,aAAa,CAAC;CAElB,IAAI,CAAC,KACH,OAAO;CAET,OAAO,IAAI;AACb;;;;;;AAOA,SAAgB,YAAoB;CAElC,OADY,WAAW,WACd,CAAC,EAAE,UAAU;AACxB"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../../src/i18n/context.tsx"],"sourcesContent":["import {\n createTranslator,\n DEFAULT_LOCALE,\n getI18nTranslations,\n type Locale,\n onI18nRegistryChange,\n type Translations,\n type Translator,\n} from '@videojs/core/i18n';\nimport { createContext, useContext, useEffect, useMemo, useReducer } from 'react';\n\nexport type AddLocaleRoot = () => () => void;\n\nexport interface I18nContextValue {\n translator: Translator;\n locale: Locale;\n /** True when the locale resolves from an explicit provider prop. */\n localeFromProp: boolean;\n /** @internal True when the nearest provider received an explicit locale prop. */\n localeFromOwnProp?: boolean;\n /** Overrides passed to this provider. */\n translations?: Partial<Translations>;\n /** Callback inherited by nested locale roots. */\n onActiveLocaleChange?: (locale: Locale) => void;\n}\n\n/** React context carrying the active translator and locale. @public */\nexport const I18nContext = createContext<I18nContextValue | null>(null);\n\nexport const LocaleRootContext = createContext<AddLocaleRoot | undefined>(undefined);\n\n/**\n * Returns the translator for the nearest `I18nProvider`, or English defaults when none is mounted.\n *\n * @public\n */\nexport function useTranslator(): Translator {\n const ctx = useContext(I18nContext);\n const [registryEpoch, invalidateRegistry] = useReducer((epoch: number) => epoch + 1, 0);\n\n useEffect(() => {\n return onI18nRegistryChange(() => invalidateRegistry());\n }, []);\n\n const fallback = useMemo(() => {\n void registryEpoch;\n return createTranslator(getI18nTranslations(DEFAULT_LOCALE), DEFAULT_LOCALE);\n }, [registryEpoch]);\n\n if (!ctx) {\n return fallback;\n }\n return ctx.translator;\n}\n\n/**\n * Returns the active BCP 47 locale tag from the nearest `I18nProvider`, or `'en'` when none is mounted.\n *\n * @public\n */\nexport function useLocale(): Locale {\n const ctx = useContext(I18nContext);\n return ctx?.locale ?? DEFAULT_LOCALE;\n}\n"],"mappings":";;;;AA2BA,MAAa,cAAc,cAAuC,IAAI;AAEtE,MAAa,oBAAoB,cAAyC,KAAA,CAAS;;;;;;AAOnF,SAAgB,gBAA4B;CAC1C,MAAM,MAAM,WAAW,WAAW;CAClC,MAAM,CAAC,eAAe,sBAAsB,YAAY,UAAkB,QAAQ,GAAG,CAAC;CAEtF,gBAAgB;EACd,OAAO,2BAA2B,mBAAmB,CAAC;CACxD,GAAG,CAAC,CAAC;CAEL,MAAM,WAAW,cAAc;EAE7B,OAAO,iBAAiB,oBAAoB,cAAc,GAAG,cAAc;CAC7E,GAAG,CAAC,aAAa,CAAC;CAElB,IAAI,CAAC,KACH,OAAO;CAET,OAAO,IAAI;AACb;;;;;;AAOA,SAAgB,YAAoB;CAElC,OADY,WAAW,WACd,CAAC,EAAE,UAAU;AACxB"}
@@ -18,7 +18,7 @@ import { jsx } from "react/jsx-runtime";
18
18
  */
19
19
  function createI18n(options) {
20
20
  const loader = options?.loader ?? loadLocale;
21
- function I18nProviderRoot({ locale: localeProp, langRootRef, parentLocale, localeFromProp = localeProp !== void 0, translations: translationsProp, children, onActiveLocaleChange, parentAddLocaleRoot }) {
21
+ function I18nProviderRoot({ locale: localeProp, langRootRef, parentLocale, localeFromProp = localeProp !== void 0, localeFromOwnProp = localeProp !== void 0, translations: translationsProp, children, onActiveLocaleChange, parentAddLocaleRoot }) {
22
22
  const langRootElement = useLangRootElement(langRootRef, parentAddLocaleRoot);
23
23
  const ambientLang = useAmbientLang(langRootRef !== void 0, langRootElement);
24
24
  const resolvedLocale = useMemo(() => effectiveLocale(localeProp, ambientLang ?? parentLocale), [
@@ -33,12 +33,14 @@ function createI18n(options) {
33
33
  translator,
34
34
  locale: resolvedLocale,
35
35
  localeFromProp,
36
+ localeFromOwnProp,
36
37
  ...translationsProp !== void 0 ? { translations: translationsProp } : {},
37
38
  ...onActiveLocaleChange !== void 0 ? { onActiveLocaleChange } : {}
38
39
  }), [
39
40
  translator,
40
41
  resolvedLocale,
41
42
  localeFromProp,
43
+ localeFromOwnProp,
42
44
  translationsProp,
43
45
  onActiveLocaleChange
44
46
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"create-i18n.js","names":["defaultLoader"],"sources":["../../../src/i18n/create-i18n.tsx"],"sourcesContent":["import {\n createTranslator,\n loadLocale as defaultLoader,\n type FlatTranslations,\n type Locale,\n type Translations,\n} from '@videojs/core/i18n';\nimport { effectiveLocale } from '@videojs/utils/dom';\nimport { type Context, type ReactNode, type RefObject, useContext, useMemo } from 'react';\n\nimport { I18nContext, type I18nContextValue, LocaleRootContext, useLocale, useTranslator } from './context';\nimport { getProviderRootProps, type I18nProviderRootProps } from './get-provider-root-props';\nimport { useAmbientLang } from './use-ambient-lang';\nimport { useLangRootElement } from './use-lang-root-element';\nimport { useLazyTranslations } from './use-lazy-translations';\nimport { useLocaleRootNotifications } from './use-locale-root-notifications';\nimport { useMergedTranslations } from './use-merged-translations';\n\nexport interface CreateI18nOptions {\n /** Override lazy loading of shipped locale packs (tests or custom loaders). */\n loader?: (tag: string) => Promise<Partial<FlatTranslations> | undefined>;\n}\n\nexport interface I18nProviderProps {\n /**\n * Forces the active locale. Omit to inherit the nearest non-empty `lang` by walking DOM\n * ancestors from {@link langRootRef} when set, otherwise from `document.documentElement`\n * (typically `<html lang>`). Updates when any `lang` attribute changes anywhere under `<html>`,\n * or when subtree moves alter which ancestor supplies `lang`. For SSR, pass `locale` explicitly.\n */\n locale?: Locale;\n /**\n * Element whose ancestor chain is searched for a non-empty `lang` when {@link locale} is\n * omitted—for example a ref to your player shell `HTMLElement`.\n */\n langRootRef?: RefObject<Element | null>;\n /**\n * Per-locale string overrides merged on top of the global registry and any lazy built-in\n * packs for {@link locale}. Applies to translated\n * `aria-label` values and tooltip copy for skin controls wired through `useTranslator`.\n *\n * @example\n * ```tsx\n * <I18nProvider locale=\"ja\" translations={{ buttons: { play: '再生', pause: '一時停止' } }}>\n * <VideoSkin />\n * </I18nProvider>\n * ```\n */\n translations?: Partial<Translations>;\n children: ReactNode;\n /** Fires when the resolved locale changes (caption selection hooks may use this later). */\n onActiveLocaleChange?: (locale: Locale) => void;\n}\n\nexport type { I18nContextValue } from './context';\n\nexport interface CreateI18nResult {\n I18nContext: Context<I18nContextValue | null>;\n I18nProvider: (props: I18nProviderProps) => ReactNode;\n useTranslator: typeof useTranslator;\n useLocale: typeof useLocale;\n}\n\n/**\n * Creates an i18n provider and hooks for the shared React i18n context.\n *\n * @param options - Optional hooks such as custom built-in locale loading.\n * @public\n */\nexport function createI18n(options?: CreateI18nOptions): CreateI18nResult {\n const loader = options?.loader ?? defaultLoader;\n\n function I18nProviderRoot({\n locale: localeProp,\n langRootRef,\n parentLocale,\n localeFromProp = localeProp !== undefined,\n translations: translationsProp,\n children,\n onActiveLocaleChange,\n parentAddLocaleRoot,\n }: I18nProviderRootProps): ReactNode {\n const langRootElement = useLangRootElement(langRootRef, parentAddLocaleRoot);\n const ambientLang = useAmbientLang(langRootRef !== undefined, langRootElement);\n const resolvedLocale = useMemo(\n () => effectiveLocale<Locale>(localeProp, ambientLang ?? parentLocale),\n [localeProp, ambientLang, parentLocale]\n );\n\n const addLocaleRoot = useLocaleRootNotifications(resolvedLocale, onActiveLocaleChange);\n const lazyLayer = useLazyTranslations(resolvedLocale, loader);\n const translations = useMergedTranslations(resolvedLocale, lazyLayer, translationsProp);\n\n const translator = useMemo(() => createTranslator(translations, resolvedLocale), [translations, resolvedLocale]);\n\n const value = useMemo<I18nContextValue>(\n () => ({\n translator,\n locale: resolvedLocale,\n localeFromProp,\n ...(translationsProp !== undefined ? { translations: translationsProp } : {}),\n ...(onActiveLocaleChange !== undefined ? { onActiveLocaleChange } : {}),\n }),\n [translator, resolvedLocale, localeFromProp, translationsProp, onActiveLocaleChange]\n );\n\n return (\n <LocaleRootContext.Provider value={addLocaleRoot}>\n <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n </LocaleRootContext.Provider>\n );\n }\n\n function I18nProvider(props: I18nProviderProps): ReactNode {\n const parent = useContext(I18nContext);\n const parentAddLocaleRoot = useContext(LocaleRootContext);\n\n const rootProps = getProviderRootProps(props, parent, parentAddLocaleRoot);\n if (!rootProps) return props.children;\n\n return <I18nProviderRoot {...rootProps} />;\n }\n\n return { I18nContext, I18nProvider, useTranslator, useLocale };\n}\n\nconst defaultI18n = createI18n();\n\n/**\n * Resolves locale and supplies a typed translator to descendants. Mount this explicitly for\n * translated controls, forced locales, SSR copy, or locale-aware player roots.\n *\n * @public\n */\nexport const I18nProvider = defaultI18n.I18nProvider;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqEA,SAAgB,WAAW,SAA+C;CACxE,MAAM,SAAS,SAAS,UAAUA;CAElC,SAAS,iBAAiB,EACxB,QAAQ,YACR,aACA,cACA,iBAAiB,eAAe,KAAA,GAChC,cAAc,kBACd,UACA,sBACA,uBACmC;EACnC,MAAM,kBAAkB,mBAAmB,aAAa,mBAAmB;EAC3E,MAAM,cAAc,eAAe,gBAAgB,KAAA,GAAW,eAAe;EAC7E,MAAM,iBAAiB,cACf,gBAAwB,YAAY,eAAe,YAAY,GACrE;GAAC;GAAY;GAAa;EAAY,CACxC;EAEA,MAAM,gBAAgB,2BAA2B,gBAAgB,oBAAoB;EAErF,MAAM,eAAe,sBAAsB,gBADzB,oBAAoB,gBAAgB,MACa,GAAG,gBAAgB;EAEtF,MAAM,aAAa,cAAc,iBAAiB,cAAc,cAAc,GAAG,CAAC,cAAc,cAAc,CAAC;EAE/G,MAAM,QAAQ,eACL;GACL;GACA,QAAQ;GACR;GACA,GAAI,qBAAqB,KAAA,IAAY,EAAE,cAAc,iBAAiB,IAAI,CAAC;GAC3E,GAAI,yBAAyB,KAAA,IAAY,EAAE,qBAAqB,IAAI,CAAC;EACvE,IACA;GAAC;GAAY;GAAgB;GAAgB;GAAkB;EAAoB,CACrF;EAEA,OACE,oBAAC,kBAAkB,UAAnB;GAA4B,OAAO;GACjC,UAAA,oBAAC,YAAY,UAAb;IAA6B;IAAQ;GAA+B,CAAA;EAC1C,CAAA;CAEhC;CAEA,SAAS,aAAa,OAAqC;EAIzD,MAAM,YAAY,qBAAqB,OAHxB,WAAW,WAGyB,GAFvB,WAAW,iBAEiC,CAAC;EACzE,IAAI,CAAC,WAAW,OAAO,MAAM;EAE7B,OAAO,oBAAC,kBAAD,EAAkB,GAAI,UAAY,CAAA;CAC3C;CAEA,OAAO;EAAE;EAAa;EAAc;EAAe;CAAU;AAC/D;;;;;;;AAUA,MAAa,eARO,WAQQ,CAAA,CAAY"}
1
+ {"version":3,"file":"create-i18n.js","names":["defaultLoader"],"sources":["../../../src/i18n/create-i18n.tsx"],"sourcesContent":["import {\n createTranslator,\n loadLocale as defaultLoader,\n type FlatTranslations,\n type Locale,\n type Translations,\n} from '@videojs/core/i18n';\nimport { effectiveLocale } from '@videojs/utils/dom';\nimport { type Context, type ReactNode, type RefObject, useContext, useMemo } from 'react';\n\nimport { I18nContext, type I18nContextValue, LocaleRootContext, useLocale, useTranslator } from './context';\nimport { getProviderRootProps, type I18nProviderRootProps } from './get-provider-root-props';\nimport { useAmbientLang } from './use-ambient-lang';\nimport { useLangRootElement } from './use-lang-root-element';\nimport { useLazyTranslations } from './use-lazy-translations';\nimport { useLocaleRootNotifications } from './use-locale-root-notifications';\nimport { useMergedTranslations } from './use-merged-translations';\n\nexport interface CreateI18nOptions {\n /** Override lazy loading of shipped locale packs (tests or custom loaders). */\n loader?: (tag: string) => Promise<Partial<FlatTranslations> | undefined>;\n}\n\nexport interface I18nProviderProps {\n /**\n * Forces the active locale. Omit to inherit the nearest non-empty `lang` by walking DOM\n * ancestors from {@link langRootRef} when set, otherwise from `document.documentElement`\n * (typically `<html lang>`). Updates when any `lang` attribute changes anywhere under `<html>`,\n * or when subtree moves alter which ancestor supplies `lang`. For SSR, pass `locale` explicitly.\n */\n locale?: Locale;\n /**\n * Element whose ancestor chain is searched for a non-empty `lang` when {@link locale} is\n * omitted—for example a ref to your player shell `HTMLElement`.\n */\n langRootRef?: RefObject<Element | null>;\n /**\n * Per-locale string overrides merged on top of the global registry and any lazy built-in\n * packs for {@link locale}. Applies to translated\n * `aria-label` values and tooltip copy for skin controls wired through `useTranslator`.\n *\n * @example\n * ```tsx\n * <I18nProvider locale=\"ja\" translations={{ buttons: { play: '再生', pause: '一時停止' } }}>\n * <VideoSkin />\n * </I18nProvider>\n * ```\n */\n translations?: Partial<Translations>;\n children: ReactNode;\n /** Fires when the resolved locale changes (caption selection hooks may use this later). */\n onActiveLocaleChange?: (locale: Locale) => void;\n}\n\nexport type { I18nContextValue } from './context';\n\nexport interface CreateI18nResult {\n I18nContext: Context<I18nContextValue | null>;\n I18nProvider: (props: I18nProviderProps) => ReactNode;\n useTranslator: typeof useTranslator;\n useLocale: typeof useLocale;\n}\n\n/**\n * Creates an i18n provider and hooks for the shared React i18n context.\n *\n * @param options - Optional hooks such as custom built-in locale loading.\n * @public\n */\nexport function createI18n(options?: CreateI18nOptions): CreateI18nResult {\n const loader = options?.loader ?? defaultLoader;\n\n function I18nProviderRoot({\n locale: localeProp,\n langRootRef,\n parentLocale,\n localeFromProp = localeProp !== undefined,\n localeFromOwnProp = localeProp !== undefined,\n translations: translationsProp,\n children,\n onActiveLocaleChange,\n parentAddLocaleRoot,\n }: I18nProviderRootProps): ReactNode {\n const langRootElement = useLangRootElement(langRootRef, parentAddLocaleRoot);\n const ambientLang = useAmbientLang(langRootRef !== undefined, langRootElement);\n const resolvedLocale = useMemo(\n () => effectiveLocale<Locale>(localeProp, ambientLang ?? parentLocale),\n [localeProp, ambientLang, parentLocale]\n );\n\n const addLocaleRoot = useLocaleRootNotifications(resolvedLocale, onActiveLocaleChange);\n const lazyLayer = useLazyTranslations(resolvedLocale, loader);\n const translations = useMergedTranslations(resolvedLocale, lazyLayer, translationsProp);\n\n const translator = useMemo(() => createTranslator(translations, resolvedLocale), [translations, resolvedLocale]);\n\n const value = useMemo<I18nContextValue>(\n () => ({\n translator,\n locale: resolvedLocale,\n localeFromProp,\n localeFromOwnProp,\n ...(translationsProp !== undefined ? { translations: translationsProp } : {}),\n ...(onActiveLocaleChange !== undefined ? { onActiveLocaleChange } : {}),\n }),\n [translator, resolvedLocale, localeFromProp, localeFromOwnProp, translationsProp, onActiveLocaleChange]\n );\n\n return (\n <LocaleRootContext.Provider value={addLocaleRoot}>\n <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n </LocaleRootContext.Provider>\n );\n }\n\n function I18nProvider(props: I18nProviderProps): ReactNode {\n const parent = useContext(I18nContext);\n const parentAddLocaleRoot = useContext(LocaleRootContext);\n\n const rootProps = getProviderRootProps(props, parent, parentAddLocaleRoot);\n if (!rootProps) return props.children;\n\n return <I18nProviderRoot {...rootProps} />;\n }\n\n return { I18nContext, I18nProvider, useTranslator, useLocale };\n}\n\nconst defaultI18n = createI18n();\n\n/**\n * Resolves locale and supplies a typed translator to descendants. Mount this explicitly for\n * translated controls, forced locales, SSR copy, or locale-aware player roots.\n *\n * @public\n */\nexport const I18nProvider = defaultI18n.I18nProvider;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqEA,SAAgB,WAAW,SAA+C;CACxE,MAAM,SAAS,SAAS,UAAUA;CAElC,SAAS,iBAAiB,EACxB,QAAQ,YACR,aACA,cACA,iBAAiB,eAAe,KAAA,GAChC,oBAAoB,eAAe,KAAA,GACnC,cAAc,kBACd,UACA,sBACA,uBACmC;EACnC,MAAM,kBAAkB,mBAAmB,aAAa,mBAAmB;EAC3E,MAAM,cAAc,eAAe,gBAAgB,KAAA,GAAW,eAAe;EAC7E,MAAM,iBAAiB,cACf,gBAAwB,YAAY,eAAe,YAAY,GACrE;GAAC;GAAY;GAAa;EAAY,CACxC;EAEA,MAAM,gBAAgB,2BAA2B,gBAAgB,oBAAoB;EAErF,MAAM,eAAe,sBAAsB,gBADzB,oBAAoB,gBAAgB,MACa,GAAG,gBAAgB;EAEtF,MAAM,aAAa,cAAc,iBAAiB,cAAc,cAAc,GAAG,CAAC,cAAc,cAAc,CAAC;EAE/G,MAAM,QAAQ,eACL;GACL;GACA,QAAQ;GACR;GACA;GACA,GAAI,qBAAqB,KAAA,IAAY,EAAE,cAAc,iBAAiB,IAAI,CAAC;GAC3E,GAAI,yBAAyB,KAAA,IAAY,EAAE,qBAAqB,IAAI,CAAC;EACvE,IACA;GAAC;GAAY;GAAgB;GAAgB;GAAmB;GAAkB;EAAoB,CACxG;EAEA,OACE,oBAAC,kBAAkB,UAAnB;GAA4B,OAAO;GACjC,UAAA,oBAAC,YAAY,UAAb;IAA6B;IAAQ;GAA+B,CAAA;EAC1C,CAAA;CAEhC;CAEA,SAAS,aAAa,OAAqC;EAIzD,MAAM,YAAY,qBAAqB,OAHxB,WAAW,WAGyB,GAFvB,WAAW,iBAEiC,CAAC;EACzE,IAAI,CAAC,WAAW,OAAO,MAAM;EAE7B,OAAO,oBAAC,kBAAD,EAAkB,GAAI,UAAY,CAAA;CAC3C;CAEA,OAAO;EAAE;EAAa;EAAc;EAAe;CAAU;AAC/D;;;;;;;AAUA,MAAa,eARO,WAQQ,CAAA,CAAY"}
@@ -19,15 +19,17 @@ function mergeTranslations(parent, child) {
19
19
  function getProviderRootProps(props, parent, parentAddLocaleRoot) {
20
20
  const hasOverrides = props.locale !== void 0 || props.translations !== void 0 || props.onActiveLocaleChange !== void 0;
21
21
  const langRootOnly = props.langRootRef !== void 0 && !hasOverrides;
22
- if (parent && !hasOverrides && (!langRootOnly || parent.localeFromProp)) return;
22
+ if (parent && !hasOverrides && (!langRootOnly || (parent.localeFromOwnProp ?? parent.localeFromProp))) return;
23
23
  const inheritedLocale = props.locale ?? (props.langRootRef === void 0 ? parent?.locale : void 0);
24
24
  const parentLocale = props.langRootRef !== void 0 ? parent?.locale : void 0;
25
25
  const inheritedTranslations = props.translations !== void 0 && parent?.translations !== void 0 ? mergeTranslations(parent.translations, props.translations) : props.translations ?? (langRootOnly ? parent?.translations : void 0);
26
26
  const onActiveLocaleChange = props.onActiveLocaleChange ?? parent?.onActiveLocaleChange;
27
+ const localeFromProp = props.locale !== void 0 || props.langRootRef === void 0 && parent?.localeFromProp === true;
27
28
  return {
28
29
  ...props,
29
30
  ...inheritedLocale !== void 0 ? { locale: inheritedLocale } : {},
30
- localeFromProp: props.locale !== void 0,
31
+ localeFromProp,
32
+ localeFromOwnProp: props.locale !== void 0,
31
33
  ...parentLocale !== void 0 ? { parentLocale } : {},
32
34
  ...inheritedTranslations !== void 0 ? { translations: inheritedTranslations } : {},
33
35
  ...onActiveLocaleChange !== void 0 ? { onActiveLocaleChange } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"get-provider-root-props.js","names":[],"sources":["../../../src/i18n/get-provider-root-props.ts"],"sourcesContent":["import type { AddLocaleRoot, I18nContextValue } from './context';\nimport type { I18nProviderProps } from './create-i18n';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction mergeTranslations(\n parent: I18nProviderProps['translations'],\n child: I18nProviderProps['translations']\n): I18nProviderProps['translations'] {\n return {\n ...parent,\n ...child,\n ...(parent && child\n ? Object.fromEntries(\n Object.keys(parent)\n .filter((key) => isRecord(parent[key]) && isRecord(child[key]))\n .map((key) => {\n const parentValue = parent[key];\n const childValue = child[key];\n return [\n key,\n isRecord(parentValue) && isRecord(childValue) ? { ...parentValue, ...childValue } : childValue,\n ];\n })\n )\n : {}),\n } as I18nProviderProps['translations'];\n}\n\nexport interface I18nProviderRootProps extends I18nProviderProps {\n parentLocale?: I18nContextValue['locale'];\n localeFromProp?: boolean;\n parentAddLocaleRoot?: AddLocaleRoot;\n}\n\nexport function getProviderRootProps(\n props: I18nProviderProps,\n parent: I18nContextValue | null,\n parentAddLocaleRoot?: AddLocaleRoot\n): I18nProviderRootProps | undefined {\n const hasOverrides =\n props.locale !== undefined || props.translations !== undefined || props.onActiveLocaleChange !== undefined;\n const langRootOnly = props.langRootRef !== undefined && !hasOverrides;\n\n // Nested providers without their own locale root or overrides can use the\n // existing parent context instead of mounting another root.\n if (parent && !hasOverrides && (!langRootOnly || parent.localeFromProp)) {\n return undefined;\n }\n\n const inheritedLocale = props.locale ?? (props.langRootRef === undefined ? parent?.locale : undefined);\n const parentLocale = props.langRootRef !== undefined ? parent?.locale : undefined;\n const inheritedTranslations =\n props.translations !== undefined && parent?.translations !== undefined\n ? mergeTranslations(parent.translations, props.translations)\n : (props.translations ?? (langRootOnly ? parent?.translations : undefined));\n const onActiveLocaleChange = props.onActiveLocaleChange ?? parent?.onActiveLocaleChange;\n\n return {\n ...props,\n ...(inheritedLocale !== undefined ? { locale: inheritedLocale } : {}),\n localeFromProp: props.locale !== undefined,\n ...(parentLocale !== undefined ? { parentLocale } : {}),\n ...(inheritedTranslations !== undefined ? { translations: inheritedTranslations } : {}),\n ...(onActiveLocaleChange !== undefined ? { onActiveLocaleChange } : {}),\n ...(parentAddLocaleRoot !== undefined ? { parentAddLocaleRoot } : {}),\n };\n}\n"],"mappings":";AAGA,SAAS,SAAS,OAAkD;CAClE,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,kBACP,QACA,OACmC;CACnC,OAAO;EACL,GAAG;EACH,GAAG;EACH,GAAI,UAAU,QACV,OAAO,YACL,OAAO,KAAK,MAAM,CAAC,CAChB,QAAQ,QAAQ,SAAS,OAAO,IAAI,KAAK,SAAS,MAAM,IAAI,CAAC,CAAC,CAC9D,KAAK,QAAQ;GACZ,MAAM,cAAc,OAAO;GAC3B,MAAM,aAAa,MAAM;GACzB,OAAO,CACL,KACA,SAAS,WAAW,KAAK,SAAS,UAAU,IAAI;IAAE,GAAG;IAAa,GAAG;GAAW,IAAI,UACtF;EACF,CAAC,CACL,IACA,CAAC;CACP;AACF;AAQA,SAAgB,qBACd,OACA,QACA,qBACmC;CACnC,MAAM,eACJ,MAAM,WAAW,KAAA,KAAa,MAAM,iBAAiB,KAAA,KAAa,MAAM,yBAAyB,KAAA;CACnG,MAAM,eAAe,MAAM,gBAAgB,KAAA,KAAa,CAAC;CAIzD,IAAI,UAAU,CAAC,iBAAiB,CAAC,gBAAgB,OAAO,iBACtD;CAGF,MAAM,kBAAkB,MAAM,WAAW,MAAM,gBAAgB,KAAA,IAAY,QAAQ,SAAS,KAAA;CAC5F,MAAM,eAAe,MAAM,gBAAgB,KAAA,IAAY,QAAQ,SAAS,KAAA;CACxE,MAAM,wBACJ,MAAM,iBAAiB,KAAA,KAAa,QAAQ,iBAAiB,KAAA,IACzD,kBAAkB,OAAO,cAAc,MAAM,YAAY,IACxD,MAAM,iBAAiB,eAAe,QAAQ,eAAe,KAAA;CACpE,MAAM,uBAAuB,MAAM,wBAAwB,QAAQ;CAEnE,OAAO;EACL,GAAG;EACH,GAAI,oBAAoB,KAAA,IAAY,EAAE,QAAQ,gBAAgB,IAAI,CAAC;EACnE,gBAAgB,MAAM,WAAW,KAAA;EACjC,GAAI,iBAAiB,KAAA,IAAY,EAAE,aAAa,IAAI,CAAC;EACrD,GAAI,0BAA0B,KAAA,IAAY,EAAE,cAAc,sBAAsB,IAAI,CAAC;EACrF,GAAI,yBAAyB,KAAA,IAAY,EAAE,qBAAqB,IAAI,CAAC;EACrE,GAAI,wBAAwB,KAAA,IAAY,EAAE,oBAAoB,IAAI,CAAC;CACrE;AACF"}
1
+ {"version":3,"file":"get-provider-root-props.js","names":[],"sources":["../../../src/i18n/get-provider-root-props.ts"],"sourcesContent":["import type { AddLocaleRoot, I18nContextValue } from './context';\nimport type { I18nProviderProps } from './create-i18n';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction mergeTranslations(\n parent: I18nProviderProps['translations'],\n child: I18nProviderProps['translations']\n): I18nProviderProps['translations'] {\n return {\n ...parent,\n ...child,\n ...(parent && child\n ? Object.fromEntries(\n Object.keys(parent)\n .filter((key) => isRecord(parent[key]) && isRecord(child[key]))\n .map((key) => {\n const parentValue = parent[key];\n const childValue = child[key];\n return [\n key,\n isRecord(parentValue) && isRecord(childValue) ? { ...parentValue, ...childValue } : childValue,\n ];\n })\n )\n : {}),\n } as I18nProviderProps['translations'];\n}\n\nexport interface I18nProviderRootProps extends I18nProviderProps {\n parentLocale?: I18nContextValue['locale'];\n localeFromProp?: boolean;\n localeFromOwnProp?: boolean;\n parentAddLocaleRoot?: AddLocaleRoot;\n}\n\nexport function getProviderRootProps(\n props: I18nProviderProps,\n parent: I18nContextValue | null,\n parentAddLocaleRoot?: AddLocaleRoot\n): I18nProviderRootProps | undefined {\n const hasOverrides =\n props.locale !== undefined || props.translations !== undefined || props.onActiveLocaleChange !== undefined;\n const langRootOnly = props.langRootRef !== undefined && !hasOverrides;\n\n // Nested providers without their own locale root or overrides can use the\n // existing parent context instead of mounting another root.\n if (parent && !hasOverrides && (!langRootOnly || (parent.localeFromOwnProp ?? parent.localeFromProp))) {\n return undefined;\n }\n\n const inheritedLocale = props.locale ?? (props.langRootRef === undefined ? parent?.locale : undefined);\n const parentLocale = props.langRootRef !== undefined ? parent?.locale : undefined;\n const inheritedTranslations =\n props.translations !== undefined && parent?.translations !== undefined\n ? mergeTranslations(parent.translations, props.translations)\n : (props.translations ?? (langRootOnly ? parent?.translations : undefined));\n const onActiveLocaleChange = props.onActiveLocaleChange ?? parent?.onActiveLocaleChange;\n const localeFromProp =\n props.locale !== undefined || (props.langRootRef === undefined && parent?.localeFromProp === true);\n\n return {\n ...props,\n ...(inheritedLocale !== undefined ? { locale: inheritedLocale } : {}),\n localeFromProp,\n localeFromOwnProp: props.locale !== undefined,\n ...(parentLocale !== undefined ? { parentLocale } : {}),\n ...(inheritedTranslations !== undefined ? { translations: inheritedTranslations } : {}),\n ...(onActiveLocaleChange !== undefined ? { onActiveLocaleChange } : {}),\n ...(parentAddLocaleRoot !== undefined ? { parentAddLocaleRoot } : {}),\n };\n}\n"],"mappings":";AAGA,SAAS,SAAS,OAAkD;CAClE,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,kBACP,QACA,OACmC;CACnC,OAAO;EACL,GAAG;EACH,GAAG;EACH,GAAI,UAAU,QACV,OAAO,YACL,OAAO,KAAK,MAAM,CAAC,CAChB,QAAQ,QAAQ,SAAS,OAAO,IAAI,KAAK,SAAS,MAAM,IAAI,CAAC,CAAC,CAC9D,KAAK,QAAQ;GACZ,MAAM,cAAc,OAAO;GAC3B,MAAM,aAAa,MAAM;GACzB,OAAO,CACL,KACA,SAAS,WAAW,KAAK,SAAS,UAAU,IAAI;IAAE,GAAG;IAAa,GAAG;GAAW,IAAI,UACtF;EACF,CAAC,CACL,IACA,CAAC;CACP;AACF;AASA,SAAgB,qBACd,OACA,QACA,qBACmC;CACnC,MAAM,eACJ,MAAM,WAAW,KAAA,KAAa,MAAM,iBAAiB,KAAA,KAAa,MAAM,yBAAyB,KAAA;CACnG,MAAM,eAAe,MAAM,gBAAgB,KAAA,KAAa,CAAC;CAIzD,IAAI,UAAU,CAAC,iBAAiB,CAAC,iBAAiB,OAAO,qBAAqB,OAAO,kBACnF;CAGF,MAAM,kBAAkB,MAAM,WAAW,MAAM,gBAAgB,KAAA,IAAY,QAAQ,SAAS,KAAA;CAC5F,MAAM,eAAe,MAAM,gBAAgB,KAAA,IAAY,QAAQ,SAAS,KAAA;CACxE,MAAM,wBACJ,MAAM,iBAAiB,KAAA,KAAa,QAAQ,iBAAiB,KAAA,IACzD,kBAAkB,OAAO,cAAc,MAAM,YAAY,IACxD,MAAM,iBAAiB,eAAe,QAAQ,eAAe,KAAA;CACpE,MAAM,uBAAuB,MAAM,wBAAwB,QAAQ;CACnE,MAAM,iBACJ,MAAM,WAAW,KAAA,KAAc,MAAM,gBAAgB,KAAA,KAAa,QAAQ,mBAAmB;CAE/F,OAAO;EACL,GAAG;EACH,GAAI,oBAAoB,KAAA,IAAY,EAAE,QAAQ,gBAAgB,IAAI,CAAC;EACnE;EACA,mBAAmB,MAAM,WAAW,KAAA;EACpC,GAAI,iBAAiB,KAAA,IAAY,EAAE,aAAa,IAAI,CAAC;EACrD,GAAI,0BAA0B,KAAA,IAAY,EAAE,cAAc,sBAAsB,IAAI,CAAC;EACrF,GAAI,yBAAyB,KAAA,IAAY,EAAE,qBAAqB,IAAI,CAAC;EACrE,GAAI,wBAAwB,KAAA,IAAY,EAAE,oBAAoB,IAAI,CAAC;CACrE;AACF"}
@@ -1,15 +1,17 @@
1
- import { useTranslator } from "../i18n/context.js";
1
+ import { I18nContext, useTranslator } from "../i18n/context.js";
2
2
  import { useComposedRefs } from "../utils/use-composed-refs.js";
3
3
  import { useContainerAttach } from "./context.js";
4
4
  import { PopupGroupProvider } from "./popup-group-context.js";
5
5
  import { DEFAULT_CONTAINER_ROLE, DEFAULT_CONTAINER_TAB_INDEX, createPopupGroup, focusContainer } from "@videojs/core/dom";
6
- import { forwardRef, useEffect, useRef, useState } from "react";
6
+ import { forwardRef, useContext, useEffect, useRef, useState } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  import { labelText } from "@videojs/core/i18n/text/container";
9
+ import { getTextDirection } from "@videojs/utils/i18n";
9
10
  //#region src/player/container.tsx
10
- const Container = forwardRef(function Container({ children, tabIndex = DEFAULT_CONTAINER_TAB_INDEX, role = DEFAULT_CONTAINER_ROLE, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }, ref) {
11
+ const Container = forwardRef(function Container({ children, tabIndex = DEFAULT_CONTAINER_TAB_INDEX, role = DEFAULT_CONTAINER_ROLE, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, lang: langProp, dir: dirProp, ...props }, ref) {
11
12
  const setContainer = useContainerAttach();
12
13
  const translator = useTranslator();
14
+ const i18n = useContext(I18nContext);
13
15
  const [popupGroup] = useState(() => createPopupGroup());
14
16
  const internalRef = useRef(null);
15
17
  const composedRef = useComposedRefs(ref, internalRef);
@@ -23,14 +25,21 @@ const Container = forwardRef(function Container({ children, tabIndex = DEFAULT_C
23
25
  if (!el) return;
24
26
  focusContainer(el);
25
27
  };
28
+ const accessibleNameProps = ariaLabel !== void 0 || ariaLabelledBy !== void 0 ? {
29
+ "aria-label": ariaLabel,
30
+ "aria-labelledby": ariaLabelledBy
31
+ } : { "aria-label": translator(labelText) };
32
+ const lang = langProp ?? (i18n?.localeFromProp ? i18n.locale : void 0);
33
+ const localeProps = {
34
+ lang,
35
+ dir: dirProp ?? (lang ? getTextDirection(lang) : void 0)
36
+ };
26
37
  return /* @__PURE__ */ jsx("div", {
27
38
  ref: composedRef,
28
39
  role,
29
40
  tabIndex,
30
- ...ariaLabel !== void 0 || ariaLabelledBy !== void 0 ? {
31
- "aria-label": ariaLabel,
32
- "aria-labelledby": ariaLabelledBy
33
- } : { "aria-label": translator(labelText) },
41
+ ...accessibleNameProps,
42
+ ...localeProps,
34
43
  ...props,
35
44
  onPointerUp: handlePointerUp,
36
45
  children: /* @__PURE__ */ jsx(PopupGroupProvider, {
@@ -1 +1 @@
1
- {"version":3,"file":"container.js","names":[],"sources":["../../../src/player/container.tsx"],"sourcesContent":["import {\n createPopupGroup,\n DEFAULT_CONTAINER_ROLE,\n DEFAULT_CONTAINER_TAB_INDEX,\n focusContainer,\n} from '@videojs/core/dom';\nimport { labelText } from '@videojs/core/i18n/text/container';\nimport {\n forwardRef,\n type HTMLAttributes,\n type PointerEventHandler,\n type ReactNode,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useTranslator } from '../i18n/context';\nimport { useComposedRefs } from '../utils/use-composed-refs';\nimport { useContainerAttach } from './context';\nimport { PopupGroupProvider } from './popup-group-context';\n\nexport interface ContainerProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode;\n}\n\nexport const Container = forwardRef<HTMLDivElement, ContainerProps>(function Container(\n {\n children,\n tabIndex = DEFAULT_CONTAINER_TAB_INDEX,\n role = DEFAULT_CONTAINER_ROLE,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...props\n },\n ref\n) {\n const setContainer = useContainerAttach();\n const translator = useTranslator();\n const [popupGroup] = useState(() => createPopupGroup());\n const internalRef = useRef<HTMLDivElement>(null);\n const composedRef = useComposedRefs(ref, internalRef);\n\n useEffect(() => {\n setContainer?.(internalRef.current);\n return () => setContainer?.(null);\n }, [setContainer]);\n\n const handlePointerUp: PointerEventHandler<HTMLDivElement> = (event) => {\n props.onPointerUp?.(event);\n const el = internalRef.current;\n if (!el) return;\n focusContainer(el);\n };\n\n const accessibleNameProps =\n ariaLabel !== undefined || ariaLabelledBy !== undefined\n ? { 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy }\n : { 'aria-label': translator(labelText) };\n\n return (\n <div\n ref={composedRef}\n role={role}\n tabIndex={tabIndex}\n {...accessibleNameProps}\n {...props}\n onPointerUp={handlePointerUp}\n >\n <PopupGroupProvider value={popupGroup}>{children}</PopupGroupProvider>\n </div>\n );\n});\n\nexport namespace Container {\n export type Props = ContainerProps;\n}\n"],"mappings":";;;;;;;;;AAyBA,MAAa,YAAY,WAA2C,SAAS,UAC3E,EACE,UACA,WAAW,6BACX,OAAO,wBACP,cAAc,WACd,mBAAmB,gBACnB,GAAG,SAEL,KACA;CACA,MAAM,eAAe,mBAAmB;CACxC,MAAM,aAAa,cAAc;CACjC,MAAM,CAAC,cAAc,eAAe,iBAAiB,CAAC;CACtD,MAAM,cAAc,OAAuB,IAAI;CAC/C,MAAM,cAAc,gBAAgB,KAAK,WAAW;CAEpD,gBAAgB;EACd,eAAe,YAAY,OAAO;EAClC,aAAa,eAAe,IAAI;CAClC,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,mBAAwD,UAAU;EACtE,MAAM,cAAc,KAAK;EACzB,MAAM,KAAK,YAAY;EACvB,IAAI,CAAC,IAAI;EACT,eAAe,EAAE;CACnB;CAOA,OACE,oBAAC,OAAD;EACE,KAAK;EACC;EACI;EACV,GATF,cAAc,KAAA,KAAa,mBAAmB,KAAA,IAC1C;GAAE,cAAc;GAAW,mBAAmB;EAAe,IAC7D,EAAE,cAAc,WAAW,SAAS,EAAE;EAQxC,GAAI;EACJ,aAAa;EAEb,UAAA,oBAAC,oBAAD;GAAoB,OAAO;GAAa;EAA6B,CAAA;CAClE,CAAA;AAET,CAAC"}
1
+ {"version":3,"file":"container.js","names":[],"sources":["../../../src/player/container.tsx"],"sourcesContent":["import {\n createPopupGroup,\n DEFAULT_CONTAINER_ROLE,\n DEFAULT_CONTAINER_TAB_INDEX,\n focusContainer,\n} from '@videojs/core/dom';\nimport { labelText } from '@videojs/core/i18n/text/container';\nimport { getTextDirection } from '@videojs/utils/i18n';\nimport {\n forwardRef,\n type HTMLAttributes,\n type PointerEventHandler,\n type ReactNode,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { I18nContext, useTranslator } from '../i18n/context';\nimport { useComposedRefs } from '../utils/use-composed-refs';\nimport { useContainerAttach } from './context';\nimport { PopupGroupProvider } from './popup-group-context';\n\nexport interface ContainerProps extends HTMLAttributes<HTMLDivElement> {\n children?: ReactNode;\n}\n\nexport const Container = forwardRef<HTMLDivElement, ContainerProps>(function Container(\n {\n children,\n tabIndex = DEFAULT_CONTAINER_TAB_INDEX,\n role = DEFAULT_CONTAINER_ROLE,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n lang: langProp,\n dir: dirProp,\n ...props\n },\n ref\n) {\n const setContainer = useContainerAttach();\n const translator = useTranslator();\n const i18n = useContext(I18nContext);\n const [popupGroup] = useState(() => createPopupGroup());\n const internalRef = useRef<HTMLDivElement>(null);\n const composedRef = useComposedRefs(ref, internalRef);\n\n useEffect(() => {\n setContainer?.(internalRef.current);\n return () => setContainer?.(null);\n }, [setContainer]);\n\n const handlePointerUp: PointerEventHandler<HTMLDivElement> = (event) => {\n props.onPointerUp?.(event);\n const el = internalRef.current;\n if (!el) return;\n focusContainer(el);\n };\n\n const accessibleNameProps =\n ariaLabel !== undefined || ariaLabelledBy !== undefined\n ? { 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy }\n : { 'aria-label': translator(labelText) };\n const lang = langProp ?? (i18n?.localeFromProp ? i18n.locale : undefined);\n const localeProps = {\n lang,\n dir: dirProp ?? (lang ? getTextDirection(lang) : undefined),\n };\n\n return (\n <div\n ref={composedRef}\n role={role}\n tabIndex={tabIndex}\n {...accessibleNameProps}\n {...localeProps}\n {...props}\n onPointerUp={handlePointerUp}\n >\n <PopupGroupProvider value={popupGroup}>{children}</PopupGroupProvider>\n </div>\n );\n});\n\nexport namespace Container {\n export type Props = ContainerProps;\n}\n"],"mappings":";;;;;;;;;;AA2BA,MAAa,YAAY,WAA2C,SAAS,UAC3E,EACE,UACA,WAAW,6BACX,OAAO,wBACP,cAAc,WACd,mBAAmB,gBACnB,MAAM,UACN,KAAK,SACL,GAAG,SAEL,KACA;CACA,MAAM,eAAe,mBAAmB;CACxC,MAAM,aAAa,cAAc;CACjC,MAAM,OAAO,WAAW,WAAW;CACnC,MAAM,CAAC,cAAc,eAAe,iBAAiB,CAAC;CACtD,MAAM,cAAc,OAAuB,IAAI;CAC/C,MAAM,cAAc,gBAAgB,KAAK,WAAW;CAEpD,gBAAgB;EACd,eAAe,YAAY,OAAO;EAClC,aAAa,eAAe,IAAI;CAClC,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,mBAAwD,UAAU;EACtE,MAAM,cAAc,KAAK;EACzB,MAAM,KAAK,YAAY;EACvB,IAAI,CAAC,IAAI;EACT,eAAe,EAAE;CACnB;CAEA,MAAM,sBACJ,cAAc,KAAA,KAAa,mBAAmB,KAAA,IAC1C;EAAE,cAAc;EAAW,mBAAmB;CAAe,IAC7D,EAAE,cAAc,WAAW,SAAS,EAAE;CAC5C,MAAM,OAAO,aAAa,MAAM,iBAAiB,KAAK,SAAS,KAAA;CAC/D,MAAM,cAAc;EAClB;EACA,KAAK,YAAY,OAAO,iBAAiB,IAAI,IAAI,KAAA;CACnD;CAEA,OACE,oBAAC,OAAD;EACE,KAAK;EACC;EACI;EACV,GAAI;EACJ,GAAI;EACJ,GAAI;EACJ,aAAa;EAEb,UAAA,oBAAC,oBAAD;GAAoB,OAAO;GAAa;EAA6B,CAAA;CAClE,CAAA;AAET,CAAC"}
@@ -170,6 +170,10 @@
170
170
  text-shadow: 0 1px 0 var(--shadow-current-color);
171
171
  background-color: var(--controls-background-color);
172
172
  backdrop-filter: var(--controls-backdrop-filter);
173
+
174
+ &:dir(rtl) {
175
+ flex-direction: row-reverse;
176
+ }
173
177
  }
174
178
 
175
179
  .media-minimal-skin .media-time-controls {
@@ -179,12 +183,20 @@
179
183
  gap: calc(var(--spacing) * 3);
180
184
  align-items: center;
181
185
  container: media-time-controls / inline-size;
186
+
187
+ &:dir(rtl) {
188
+ flex-direction: row;
189
+ }
182
190
  }
183
191
 
184
192
  .media-minimal-skin .media-time-group {
185
193
  display: flex;
186
194
  gap: calc(var(--spacing) * 1);
187
195
  align-items: center;
196
+
197
+ &:dir(rtl) {
198
+ flex-direction: row-reverse;
199
+ }
188
200
  }
189
201
 
190
202
  .media-minimal-skin .media-time {
@@ -219,6 +231,10 @@
219
231
  @container media-root (width > 42rem) {
220
232
  .media-minimal-skin .media-time-controls {
221
233
  flex-direction: row;
234
+
235
+ &:dir(rtl) {
236
+ flex-direction: row-reverse;
237
+ }
222
238
  }
223
239
 
224
240
  .media-minimal-skin .media-time--duration,
@@ -417,6 +433,10 @@
417
433
  display: flex;
418
434
  gap: 1px;
419
435
  align-items: center;
436
+
437
+ &:dir(rtl) {
438
+ flex-direction: row-reverse;
439
+ }
420
440
  }
421
441
 
422
442
  .media-minimal-skin .media-badge {
@@ -439,10 +459,15 @@
439
459
  width: var(--media-icon-size);
440
460
  height: var(--media-icon-size);
441
461
  }
442
- .media-minimal-skin .media-icon--flipped {
462
+ .media-minimal-skin .media-icon--flipped,
463
+ .media-minimal-skin:dir(rtl) .media-menu__chevron {
443
464
  scale: -1 1;
444
465
  }
445
466
 
467
+ .media-minimal-skin:dir(rtl) .media-menu__chevron.media-icon--flipped {
468
+ scale: 1 1;
469
+ }
470
+
446
471
  .media-minimal-skin .media-slider {
447
472
  --track-size: calc(var(--spacing) * 1);
448
473
  --track-highlighted-size: calc(var(--spacing) * 1.75);
@@ -986,6 +1011,10 @@
986
1011
  filter: blur(8px);
987
1012
  translate: 100% 0;
988
1013
  }
1014
+
1015
+ &:dir(rtl):where([data-starting-style], [data-ending-style]) {
1016
+ translate: -100% 0;
1017
+ }
989
1018
  }
990
1019
 
991
1020
  .media-menu__separator {
@@ -1027,7 +1056,7 @@
1027
1056
  gap: calc(var(--spacing) * 1.5);
1028
1057
  align-items: center;
1029
1058
  padding: calc(var(--spacing) * 1.5) calc(var(--spacing) * 2);
1030
- text-align: left;
1059
+ text-align: start;
1031
1060
  text-shadow: 0 1px 0 var(--shadow-current-color);
1032
1061
  cursor: pointer;
1033
1062
  user-select: none;
@@ -1071,8 +1100,7 @@
1071
1100
 
1072
1101
  .media-menu__indicator {
1073
1102
  flex-shrink: 0;
1074
- margin-right: calc(var(--spacing) * -1);
1075
- margin-left: auto;
1103
+ margin-inline: auto calc(var(--spacing) * -1);
1076
1104
  opacity: 0;
1077
1105
  }
1078
1106
 
@@ -1105,8 +1133,8 @@
1105
1133
  }
1106
1134
 
1107
1135
  .media-menu__tier {
1136
+ padding-inline-start: calc(var(--spacing) * 0.5);
1108
1137
  padding-top: 1px;
1109
- padding-left: calc(var(--spacing) * 0.5);
1110
1138
  font-size: var(--font-size-tiny);
1111
1139
  font-weight: 600;
1112
1140
  line-height: 1;
@@ -1123,8 +1151,8 @@
1123
1151
  gap: calc(var(--spacing) * 1);
1124
1152
  align-items: center;
1125
1153
  min-width: 0;
1126
- padding-left: calc(var(--spacing) * 2);
1127
- margin-left: auto;
1154
+ padding-inline-start: calc(var(--spacing) * 2);
1155
+ margin-inline-start: auto;
1128
1156
  color: oklch(from currentColor l c h / 0.65);
1129
1157
  }
1130
1158
 
@@ -1164,6 +1192,10 @@
1164
1192
  translate: -100% 0;
1165
1193
  }
1166
1194
 
1195
+ &:dir(rtl)[data-submenu-expanded="true"] > :not([data-submenu]) {
1196
+ translate: 100% 0;
1197
+ }
1198
+
1167
1199
  /* WebKit can restart the covered-content transition while the
1168
1200
  anchor-positioned highlight remains active. */
1169
1201
  &[data-submenu-expanded] > :not([data-submenu])::before {
@@ -195,6 +195,10 @@
195
195
  container: media-controls / inline-size;
196
196
  text-shadow: 0 1px 0 var(--shadow-current-color);
197
197
  border-radius: calc(Infinity * 1px);
198
+
199
+ &:dir(rtl) {
200
+ flex-direction: row-reverse;
201
+ }
198
202
  }
199
203
 
200
204
  .media-default-skin .media-time-controls {
@@ -204,6 +208,10 @@
204
208
  align-items: center;
205
209
  container: media-time-controls / inline-size;
206
210
 
211
+ &:dir(rtl) {
212
+ flex-direction: row-reverse;
213
+ }
214
+
207
215
  > .media-time:last-child {
208
216
  @container media-time-controls (width < 16rem) {
209
217
  display: none;
@@ -408,6 +416,10 @@
408
416
  display: flex;
409
417
  gap: 1px;
410
418
  align-items: center;
419
+
420
+ &:dir(rtl) {
421
+ flex-direction: row-reverse;
422
+ }
411
423
  }
412
424
 
413
425
  .media-default-skin .media-badge {
@@ -430,10 +442,15 @@
430
442
  width: var(--media-icon-size);
431
443
  height: var(--media-icon-size);
432
444
  }
433
- .media-default-skin .media-icon--flipped {
445
+ .media-default-skin .media-icon--flipped,
446
+ .media-default-skin:dir(rtl) .media-menu__chevron {
434
447
  scale: -1 1;
435
448
  }
436
449
 
450
+ .media-default-skin:dir(rtl) .media-menu__chevron.media-icon--flipped {
451
+ scale: 1 1;
452
+ }
453
+
437
454
  .media-default-skin .media-slider {
438
455
  --track-size: calc(var(--spacing) * 1);
439
456
  --track-highlighted-size: calc(var(--spacing) * 1.75);
@@ -978,6 +995,10 @@
978
995
  filter: blur(8px);
979
996
  translate: 100% 0;
980
997
  }
998
+
999
+ &:dir(rtl):where([data-starting-style], [data-ending-style]) {
1000
+ translate: -100% 0;
1001
+ }
981
1002
  }
982
1003
 
983
1004
  .media-menu__separator {
@@ -1020,7 +1041,7 @@
1020
1041
  gap: calc(var(--spacing) * 1.5);
1021
1042
  align-items: center;
1022
1043
  padding: calc(var(--spacing) * 1.5) calc(var(--spacing) * 2);
1023
- text-align: left;
1044
+ text-align: start;
1024
1045
  text-shadow: 0 1px 0 var(--shadow-current-color);
1025
1046
  cursor: pointer;
1026
1047
  user-select: none;
@@ -1064,8 +1085,7 @@
1064
1085
 
1065
1086
  .media-menu__indicator {
1066
1087
  flex-shrink: 0;
1067
- margin-right: calc(var(--spacing) * -1);
1068
- margin-left: auto;
1088
+ margin-inline: auto calc(var(--spacing) * -1);
1069
1089
  opacity: 0;
1070
1090
 
1071
1091
  .media-icon {
@@ -1102,8 +1122,8 @@
1102
1122
  }
1103
1123
 
1104
1124
  .media-menu__tier {
1125
+ padding-inline-start: calc(var(--spacing) * 0.5);
1105
1126
  padding-top: 1px;
1106
- padding-left: calc(var(--spacing) * 0.5);
1107
1127
  font-size: var(--font-size-tiny);
1108
1128
  font-weight: 600;
1109
1129
  line-height: 1;
@@ -1120,8 +1140,8 @@
1120
1140
  gap: calc(var(--spacing) * 1);
1121
1141
  align-items: center;
1122
1142
  min-width: 0;
1123
- padding-left: calc(var(--spacing) * 2);
1124
- margin-left: auto;
1143
+ padding-inline-start: calc(var(--spacing) * 2);
1144
+ margin-inline-start: auto;
1125
1145
  color: oklch(from currentColor l c h / 0.65);
1126
1146
  }
1127
1147
 
@@ -1161,6 +1181,10 @@
1161
1181
  translate: -100% 0;
1162
1182
  }
1163
1183
 
1184
+ &:dir(rtl)[data-submenu-expanded="true"] > :not([data-submenu]) {
1185
+ translate: 100% 0;
1186
+ }
1187
+
1164
1188
  /* WebKit can restart the covered-content transition while the
1165
1189
  anchor-positioned highlight remains active. */
1166
1190
  &[data-submenu-expanded] > :not([data-submenu])::before {
@@ -170,6 +170,10 @@
170
170
  text-shadow: 0 1px 0 var(--shadow-current-color);
171
171
  background-color: var(--controls-background-color);
172
172
  backdrop-filter: var(--controls-backdrop-filter);
173
+
174
+ &:dir(rtl) {
175
+ flex-direction: row-reverse;
176
+ }
173
177
  }
174
178
 
175
179
  .media-minimal-skin .media-time-controls {
@@ -179,12 +183,20 @@
179
183
  gap: calc(var(--spacing) * 3);
180
184
  align-items: center;
181
185
  container: media-time-controls / inline-size;
186
+
187
+ &:dir(rtl) {
188
+ flex-direction: row;
189
+ }
182
190
  }
183
191
 
184
192
  .media-minimal-skin .media-time-group {
185
193
  display: flex;
186
194
  gap: calc(var(--spacing) * 1);
187
195
  align-items: center;
196
+
197
+ &:dir(rtl) {
198
+ flex-direction: row-reverse;
199
+ }
188
200
  }
189
201
 
190
202
  .media-minimal-skin .media-time {
@@ -219,6 +231,10 @@
219
231
  @container media-root (width > 42rem) {
220
232
  .media-minimal-skin .media-time-controls {
221
233
  flex-direction: row;
234
+
235
+ &:dir(rtl) {
236
+ flex-direction: row-reverse;
237
+ }
222
238
  }
223
239
 
224
240
  .media-minimal-skin .media-time--duration,
@@ -417,6 +433,10 @@
417
433
  display: flex;
418
434
  gap: 1px;
419
435
  align-items: center;
436
+
437
+ &:dir(rtl) {
438
+ flex-direction: row-reverse;
439
+ }
420
440
  }
421
441
 
422
442
  .media-minimal-skin .media-badge {
@@ -439,10 +459,15 @@
439
459
  width: var(--media-icon-size);
440
460
  height: var(--media-icon-size);
441
461
  }
442
- .media-minimal-skin .media-icon--flipped {
462
+ .media-minimal-skin .media-icon--flipped,
463
+ .media-minimal-skin:dir(rtl) .media-menu__chevron {
443
464
  scale: -1 1;
444
465
  }
445
466
 
467
+ .media-minimal-skin:dir(rtl) .media-menu__chevron.media-icon--flipped {
468
+ scale: 1 1;
469
+ }
470
+
446
471
  .media-minimal-skin .media-slider {
447
472
  --track-size: calc(var(--spacing) * 1);
448
473
  --track-highlighted-size: calc(var(--spacing) * 1.75);
@@ -986,6 +1011,10 @@
986
1011
  filter: blur(8px);
987
1012
  translate: 100% 0;
988
1013
  }
1014
+
1015
+ &:dir(rtl):where([data-starting-style], [data-ending-style]) {
1016
+ translate: -100% 0;
1017
+ }
989
1018
  }
990
1019
 
991
1020
  .media-menu__separator {
@@ -1027,7 +1056,7 @@
1027
1056
  gap: calc(var(--spacing) * 1.5);
1028
1057
  align-items: center;
1029
1058
  padding: calc(var(--spacing) * 1.5) calc(var(--spacing) * 2);
1030
- text-align: left;
1059
+ text-align: start;
1031
1060
  text-shadow: 0 1px 0 var(--shadow-current-color);
1032
1061
  cursor: pointer;
1033
1062
  user-select: none;
@@ -1071,8 +1100,7 @@
1071
1100
 
1072
1101
  .media-menu__indicator {
1073
1102
  flex-shrink: 0;
1074
- margin-right: calc(var(--spacing) * -1);
1075
- margin-left: auto;
1103
+ margin-inline: auto calc(var(--spacing) * -1);
1076
1104
  opacity: 0;
1077
1105
  }
1078
1106
 
@@ -1105,8 +1133,8 @@
1105
1133
  }
1106
1134
 
1107
1135
  .media-menu__tier {
1136
+ padding-inline-start: calc(var(--spacing) * 0.5);
1108
1137
  padding-top: 1px;
1109
- padding-left: calc(var(--spacing) * 0.5);
1110
1138
  font-size: var(--font-size-tiny);
1111
1139
  font-weight: 600;
1112
1140
  line-height: 1;
@@ -1123,8 +1151,8 @@
1123
1151
  gap: calc(var(--spacing) * 1);
1124
1152
  align-items: center;
1125
1153
  min-width: 0;
1126
- padding-left: calc(var(--spacing) * 2);
1127
- margin-left: auto;
1154
+ padding-inline-start: calc(var(--spacing) * 2);
1155
+ margin-inline-start: auto;
1128
1156
  color: oklch(from currentColor l c h / 0.65);
1129
1157
  }
1130
1158
 
@@ -1164,6 +1192,10 @@
1164
1192
  translate: -100% 0;
1165
1193
  }
1166
1194
 
1195
+ &:dir(rtl)[data-submenu-expanded="true"] > :not([data-submenu]) {
1196
+ translate: 100% 0;
1197
+ }
1198
+
1167
1199
  /* WebKit can restart the covered-content transition while the
1168
1200
  anchor-positioned highlight remains active. */
1169
1201
  &[data-submenu-expanded] > :not([data-submenu])::before {
@@ -195,6 +195,10 @@
195
195
  container: media-controls / inline-size;
196
196
  text-shadow: 0 1px 0 var(--shadow-current-color);
197
197
  border-radius: calc(Infinity * 1px);
198
+
199
+ &:dir(rtl) {
200
+ flex-direction: row-reverse;
201
+ }
198
202
  }
199
203
 
200
204
  .media-default-skin .media-time-controls {
@@ -204,6 +208,10 @@
204
208
  align-items: center;
205
209
  container: media-time-controls / inline-size;
206
210
 
211
+ &:dir(rtl) {
212
+ flex-direction: row-reverse;
213
+ }
214
+
207
215
  > .media-time:last-child {
208
216
  @container media-time-controls (width < 16rem) {
209
217
  display: none;
@@ -408,6 +416,10 @@
408
416
  display: flex;
409
417
  gap: 1px;
410
418
  align-items: center;
419
+
420
+ &:dir(rtl) {
421
+ flex-direction: row-reverse;
422
+ }
411
423
  }
412
424
 
413
425
  .media-default-skin .media-badge {
@@ -430,10 +442,15 @@
430
442
  width: var(--media-icon-size);
431
443
  height: var(--media-icon-size);
432
444
  }
433
- .media-default-skin .media-icon--flipped {
445
+ .media-default-skin .media-icon--flipped,
446
+ .media-default-skin:dir(rtl) .media-menu__chevron {
434
447
  scale: -1 1;
435
448
  }
436
449
 
450
+ .media-default-skin:dir(rtl) .media-menu__chevron.media-icon--flipped {
451
+ scale: 1 1;
452
+ }
453
+
437
454
  .media-default-skin .media-slider {
438
455
  --track-size: calc(var(--spacing) * 1);
439
456
  --track-highlighted-size: calc(var(--spacing) * 1.75);
@@ -978,6 +995,10 @@
978
995
  filter: blur(8px);
979
996
  translate: 100% 0;
980
997
  }
998
+
999
+ &:dir(rtl):where([data-starting-style], [data-ending-style]) {
1000
+ translate: -100% 0;
1001
+ }
981
1002
  }
982
1003
 
983
1004
  .media-menu__separator {
@@ -1020,7 +1041,7 @@
1020
1041
  gap: calc(var(--spacing) * 1.5);
1021
1042
  align-items: center;
1022
1043
  padding: calc(var(--spacing) * 1.5) calc(var(--spacing) * 2);
1023
- text-align: left;
1044
+ text-align: start;
1024
1045
  text-shadow: 0 1px 0 var(--shadow-current-color);
1025
1046
  cursor: pointer;
1026
1047
  user-select: none;
@@ -1064,8 +1085,7 @@
1064
1085
 
1065
1086
  .media-menu__indicator {
1066
1087
  flex-shrink: 0;
1067
- margin-right: calc(var(--spacing) * -1);
1068
- margin-left: auto;
1088
+ margin-inline: auto calc(var(--spacing) * -1);
1069
1089
  opacity: 0;
1070
1090
 
1071
1091
  .media-icon {
@@ -1102,8 +1122,8 @@
1102
1122
  }
1103
1123
 
1104
1124
  .media-menu__tier {
1125
+ padding-inline-start: calc(var(--spacing) * 0.5);
1105
1126
  padding-top: 1px;
1106
- padding-left: calc(var(--spacing) * 0.5);
1107
1127
  font-size: var(--font-size-tiny);
1108
1128
  font-weight: 600;
1109
1129
  line-height: 1;
@@ -1120,8 +1140,8 @@
1120
1140
  gap: calc(var(--spacing) * 1);
1121
1141
  align-items: center;
1122
1142
  min-width: 0;
1123
- padding-left: calc(var(--spacing) * 2);
1124
- margin-left: auto;
1143
+ padding-inline-start: calc(var(--spacing) * 2);
1144
+ margin-inline-start: auto;
1125
1145
  color: oklch(from currentColor l c h / 0.65);
1126
1146
  }
1127
1147
 
@@ -1161,6 +1181,10 @@
1161
1181
  translate: -100% 0;
1162
1182
  }
1163
1183
 
1184
+ &:dir(rtl)[data-submenu-expanded="true"] > :not([data-submenu]) {
1185
+ translate: 100% 0;
1186
+ }
1187
+
1164
1188
  /* WebKit can restart the covered-content transition while the
1165
1189
  anchor-positioned highlight remains active. */
1166
1190
  &[data-submenu-expanded] > :not([data-submenu])::before {