@omerdlw/base-framework 1.0.3 → 1.0.4

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 (204) hide show
  1. package/dist/index.js +5240 -5165
  2. package/dist/index.js.map +1 -1
  3. package/dist/kernel/compose.d.ts.map +1 -1
  4. package/dist/kernel/handlers.d.ts.map +1 -1
  5. package/dist/kernel/hooks.d.ts.map +1 -1
  6. package/dist/kernel/index.js.map +1 -1
  7. package/dist/kernel/operations.d.ts.map +1 -1
  8. package/dist/kernel/schema.d.ts +0 -2
  9. package/dist/kernel/schema.d.ts.map +1 -1
  10. package/dist/kernel/store.d.ts.map +1 -1
  11. package/dist/kernel/types.d.ts.map +1 -1
  12. package/dist/kernel/utils.d.ts +0 -2
  13. package/dist/kernel/utils.d.ts.map +1 -1
  14. package/dist/modules/ambient/color.d.ts +16 -0
  15. package/dist/modules/ambient/color.d.ts.map +1 -0
  16. package/dist/modules/ambient/constants.d.ts +0 -17
  17. package/dist/modules/ambient/constants.d.ts.map +1 -1
  18. package/dist/modules/ambient/context.d.ts +1 -7
  19. package/dist/modules/ambient/context.d.ts.map +1 -1
  20. package/dist/modules/ambient/dom.d.ts +19 -0
  21. package/dist/modules/ambient/dom.d.ts.map +1 -0
  22. package/dist/modules/ambient/extractor.d.ts +5 -0
  23. package/dist/modules/ambient/extractor.d.ts.map +1 -0
  24. package/dist/modules/ambient/hooks.d.ts +9 -0
  25. package/dist/modules/ambient/hooks.d.ts.map +1 -0
  26. package/dist/modules/ambient/index.d.ts +7 -4
  27. package/dist/modules/ambient/index.d.ts.map +1 -1
  28. package/dist/modules/ambient/index.js +66 -60
  29. package/dist/modules/ambient/index.js.map +1 -1
  30. package/dist/modules/ambient/module.d.ts +5 -1
  31. package/dist/modules/ambient/module.d.ts.map +1 -1
  32. package/dist/modules/background/constants.d.ts +1 -10
  33. package/dist/modules/background/constants.d.ts.map +1 -1
  34. package/dist/modules/background/context.d.ts +1 -13
  35. package/dist/modules/background/context.d.ts.map +1 -1
  36. package/dist/modules/background/hooks.d.ts +13 -118
  37. package/dist/modules/background/hooks.d.ts.map +1 -1
  38. package/dist/modules/background/index.d.ts +8 -3
  39. package/dist/modules/background/index.d.ts.map +1 -1
  40. package/dist/modules/background/index.js +975 -991
  41. package/dist/modules/background/index.js.map +1 -1
  42. package/dist/modules/background/module.d.ts +1 -0
  43. package/dist/modules/background/module.d.ts.map +1 -1
  44. package/dist/modules/background/overlay.d.ts +93 -2
  45. package/dist/modules/background/overlay.d.ts.map +1 -1
  46. package/dist/modules/background/playback.d.ts +10 -0
  47. package/dist/modules/background/playback.d.ts.map +1 -0
  48. package/dist/modules/background/state.d.ts +9 -0
  49. package/dist/modules/background/state.d.ts.map +1 -0
  50. package/dist/modules/background/{utils.d.ts → visual.d.ts} +6 -14
  51. package/dist/modules/background/visual.d.ts.map +1 -0
  52. package/dist/modules/background/youtube/player.d.ts +28 -0
  53. package/dist/modules/background/youtube/player.d.ts.map +1 -0
  54. package/dist/modules/context-menu/context.d.ts +1 -10
  55. package/dist/modules/context-menu/context.d.ts.map +1 -1
  56. package/dist/modules/context-menu/dom.d.ts +8 -0
  57. package/dist/modules/context-menu/dom.d.ts.map +1 -0
  58. package/dist/modules/context-menu/hooks.d.ts +11 -11
  59. package/dist/modules/context-menu/hooks.d.ts.map +1 -1
  60. package/dist/modules/context-menu/index.d.ts +8 -3
  61. package/dist/modules/context-menu/index.d.ts.map +1 -1
  62. package/dist/modules/context-menu/index.js +97 -101
  63. package/dist/modules/context-menu/index.js.map +1 -1
  64. package/dist/modules/context-menu/{utils.d.ts → items.d.ts} +2 -9
  65. package/dist/modules/context-menu/items.d.ts.map +1 -0
  66. package/dist/modules/context-menu/module.d.ts.map +1 -1
  67. package/dist/modules/context-menu/overlay.d.ts +13 -1
  68. package/dist/modules/context-menu/overlay.d.ts.map +1 -1
  69. package/dist/modules/context-menu/state.d.ts +1 -0
  70. package/dist/modules/context-menu/state.d.ts.map +1 -1
  71. package/dist/modules/controls/{utils.d.ts → entries.d.ts} +6 -5
  72. package/dist/modules/controls/entries.d.ts.map +1 -0
  73. package/dist/modules/controls/hooks.d.ts +0 -7
  74. package/dist/modules/controls/hooks.d.ts.map +1 -1
  75. package/dist/modules/controls/index.d.ts +5 -3
  76. package/dist/modules/controls/index.d.ts.map +1 -1
  77. package/dist/modules/controls/index.js +66 -61
  78. package/dist/modules/controls/index.js.map +1 -1
  79. package/dist/modules/controls/layout.d.ts +7 -0
  80. package/dist/modules/controls/layout.d.ts.map +1 -0
  81. package/dist/modules/controls/overlay.d.ts +9 -0
  82. package/dist/modules/controls/overlay.d.ts.map +1 -1
  83. package/dist/modules/dock/cards.d.ts.map +1 -1
  84. package/dist/modules/dock/dom.d.ts +24 -0
  85. package/dist/modules/dock/dom.d.ts.map +1 -0
  86. package/dist/modules/dock/helpers.d.ts +25 -0
  87. package/dist/modules/dock/helpers.d.ts.map +1 -0
  88. package/dist/modules/dock/hooks.d.ts +3 -918
  89. package/dist/modules/dock/hooks.d.ts.map +1 -1
  90. package/dist/modules/dock/index.d.ts +3 -2
  91. package/dist/modules/dock/index.d.ts.map +1 -1
  92. package/dist/modules/dock/index.js +3091 -3079
  93. package/dist/modules/dock/index.js.map +1 -1
  94. package/dist/modules/dock/layout.d.ts +26 -0
  95. package/dist/modules/dock/layout.d.ts.map +1 -0
  96. package/dist/modules/dock/module.d.ts.map +1 -1
  97. package/dist/modules/dock/overlay.d.ts.map +1 -1
  98. package/dist/modules/dock/paths.d.ts +10 -0
  99. package/dist/modules/dock/paths.d.ts.map +1 -0
  100. package/dist/modules/dock/provider.d.ts.map +1 -1
  101. package/dist/modules/dock/runtime/display.d.ts.map +1 -1
  102. package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
  103. package/dist/modules/dock/runtime/pipeline.d.ts +32 -0
  104. package/dist/modules/dock/runtime/pipeline.d.ts.map +1 -0
  105. package/dist/modules/dock/status/events.d.ts.map +1 -1
  106. package/dist/modules/dock/styles.d.ts +900 -0
  107. package/dist/modules/dock/styles.d.ts.map +1 -0
  108. package/dist/modules/dock/surface/context.d.ts +1 -2
  109. package/dist/modules/dock/surface/context.d.ts.map +1 -1
  110. package/dist/modules/dock/surface/definition.d.ts.map +1 -1
  111. package/dist/modules/dock/surface/helpers.d.ts +7 -0
  112. package/dist/modules/dock/surface/helpers.d.ts.map +1 -0
  113. package/dist/modules/dock/surface/hooks.d.ts.map +1 -1
  114. package/dist/modules/dock/surface/machine.d.ts.map +1 -1
  115. package/dist/modules/dock/surface/stack.d.ts.map +1 -1
  116. package/dist/modules/dock/surface/view-model.d.ts.map +1 -1
  117. package/dist/modules/dock/types.d.ts.map +1 -1
  118. package/dist/modules/index.js +4861 -4788
  119. package/dist/modules/index.js.map +1 -1
  120. package/dist/modules/loading/context.d.ts +2 -13
  121. package/dist/modules/loading/context.d.ts.map +1 -1
  122. package/dist/modules/loading/hooks.d.ts +15 -2
  123. package/dist/modules/loading/hooks.d.ts.map +1 -1
  124. package/dist/modules/loading/index.d.ts +3 -2
  125. package/dist/modules/loading/index.d.ts.map +1 -1
  126. package/dist/modules/loading/index.js +38 -34
  127. package/dist/modules/loading/index.js.map +1 -1
  128. package/dist/modules/loading/module.d.ts.map +1 -1
  129. package/dist/modules/loading/state.d.ts +6 -0
  130. package/dist/modules/loading/state.d.ts.map +1 -0
  131. package/dist/modules/media/constants.d.ts +0 -1
  132. package/dist/modules/media/constants.d.ts.map +1 -1
  133. package/dist/modules/media/context.d.ts +2 -6
  134. package/dist/modules/media/context.d.ts.map +1 -1
  135. package/dist/modules/media/hooks.d.ts +6 -1
  136. package/dist/modules/media/hooks.d.ts.map +1 -1
  137. package/dist/modules/media/index.d.ts +4 -3
  138. package/dist/modules/media/index.d.ts.map +1 -1
  139. package/dist/modules/media/index.js +100 -98
  140. package/dist/modules/media/index.js.map +1 -1
  141. package/dist/modules/media/module.d.ts.map +1 -1
  142. package/dist/modules/media/overlay.d.ts +0 -5
  143. package/dist/modules/media/overlay.d.ts.map +1 -1
  144. package/dist/modules/media/playback.d.ts +5 -0
  145. package/dist/modules/media/playback.d.ts.map +1 -0
  146. package/dist/modules/media/session.d.ts +8 -0
  147. package/dist/modules/media/session.d.ts.map +1 -0
  148. package/dist/modules/media/types.d.ts +0 -1
  149. package/dist/modules/media/types.d.ts.map +1 -1
  150. package/dist/modules/modal/context.d.ts +1 -12
  151. package/dist/modules/modal/context.d.ts.map +1 -1
  152. package/dist/modules/modal/dom.d.ts +4 -0
  153. package/dist/modules/modal/dom.d.ts.map +1 -0
  154. package/dist/modules/modal/header.d.ts +7 -0
  155. package/dist/modules/modal/header.d.ts.map +1 -0
  156. package/dist/modules/modal/hooks.d.ts +12 -1
  157. package/dist/modules/modal/hooks.d.ts.map +1 -1
  158. package/dist/modules/modal/identity.d.ts +7 -0
  159. package/dist/modules/modal/identity.d.ts.map +1 -0
  160. package/dist/modules/modal/index.d.ts +9 -4
  161. package/dist/modules/modal/index.d.ts.map +1 -1
  162. package/dist/modules/modal/index.js +118 -86
  163. package/dist/modules/modal/index.js.map +1 -1
  164. package/dist/modules/modal/layout.d.ts +13 -0
  165. package/dist/modules/modal/layout.d.ts.map +1 -0
  166. package/dist/modules/modal/module.d.ts.map +1 -1
  167. package/dist/modules/modal/overlay.d.ts.map +1 -1
  168. package/dist/modules/modal/types.d.ts.map +1 -1
  169. package/dist/modules/notification/context.d.ts +2 -8
  170. package/dist/modules/notification/context.d.ts.map +1 -1
  171. package/dist/modules/notification/hooks.d.ts +8 -1
  172. package/dist/modules/notification/hooks.d.ts.map +1 -1
  173. package/dist/modules/notification/index.d.ts +4 -3
  174. package/dist/modules/notification/index.d.ts.map +1 -1
  175. package/dist/modules/notification/index.js +56 -46
  176. package/dist/modules/notification/index.js.map +1 -1
  177. package/dist/modules/notification/state.d.ts +17 -0
  178. package/dist/modules/notification/state.d.ts.map +1 -0
  179. package/dist/provider.js.map +1 -1
  180. package/docs/modules/ambient.md +12 -8
  181. package/docs/modules/background.md +15 -13
  182. package/docs/modules/context-menu.md +13 -13
  183. package/docs/modules/controls.md +4 -3
  184. package/docs/modules/dock.md +8 -2
  185. package/docs/modules/loading.md +11 -11
  186. package/docs/modules/media.md +8 -7
  187. package/docs/modules/modal.md +4 -1
  188. package/docs/modules/notification.md +4 -4
  189. package/package.json +1 -1
  190. package/dist/modules/ambient/utils.d.ts +0 -18
  191. package/dist/modules/ambient/utils.d.ts.map +0 -1
  192. package/dist/modules/background/utils.d.ts.map +0 -1
  193. package/dist/modules/context-menu/utils.d.ts.map +0 -1
  194. package/dist/modules/controls/utils.d.ts.map +0 -1
  195. package/dist/modules/dock/utils.d.ts +0 -93
  196. package/dist/modules/dock/utils.d.ts.map +0 -1
  197. package/dist/modules/loading/utils.d.ts +0 -4
  198. package/dist/modules/loading/utils.d.ts.map +0 -1
  199. package/dist/modules/media/utils.d.ts +0 -17
  200. package/dist/modules/media/utils.d.ts.map +0 -1
  201. package/dist/modules/modal/utils.d.ts +0 -31
  202. package/dist/modules/modal/utils.d.ts.map +0 -1
  203. package/dist/modules/notification/utils.d.ts +0 -9
  204. package/dist/modules/notification/utils.d.ts.map +0 -1
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { memo, createContext, useState, useRef, useEffect, useMemo, useCallback, useInsertionEffect, useContext, useSyncExternalStore, useLayoutEffect, use, useId, isValidElement, cloneElement, Children } from 'react';
2
+ import { memo, createContext, useState, useRef, useEffect, useMemo, useCallback, useContext, useSyncExternalStore, useLayoutEffect, use, useId, isValidElement, cloneElement, Children } from 'react';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
- import { Icon as Icon$1 } from '@iconify-icon/react';
6
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
5
  import { AnimatePresence, motion } from 'motion/react';
6
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
7
  import { usePathname } from 'next/navigation';
8
+ import { Icon as Icon$1 } from '@iconify-icon/react';
9
9
 
10
10
  function cn(...inputs) {
11
11
  return twMerge(clsx(inputs));
@@ -95,41 +95,6 @@ function createStore(initialState, { freezeSnapshots = true } = {}) {
95
95
  }
96
96
  });
97
97
  }
98
- function Icon({
99
- className = "center",
100
- color,
101
- icon,
102
- onClick,
103
- size = 20,
104
- style,
105
- ...props
106
- }) {
107
- return /* @__PURE__ */ jsx(
108
- Icon$1,
109
- {
110
- className,
111
- height: size,
112
- icon,
113
- onClick,
114
- style: { color, ...style },
115
- width: size,
116
- ...props
117
- }
118
- );
119
- }
120
- Icon.displayName = "Icon";
121
- function Spinner({ className = "", size = 15 }) {
122
- return /* @__PURE__ */ jsx(
123
- "div",
124
- {
125
- className,
126
- "aria-label": "Loading",
127
- role: "status",
128
- children: /* @__PURE__ */ jsx(Icon, { icon: "mingcute:loading-3-fill", size })
129
- }
130
- );
131
- }
132
- Spinner.displayName = "Spinner";
133
98
 
134
99
  // src/tokens/motion.ts
135
100
  var DURATION_TOKENS = Object.freeze({
@@ -880,60 +845,11 @@ function useTheme(spec) {
880
845
  }
881
846
 
882
847
  // src/modules/background/constants.ts
883
- var DEFAULT_BACKGROUND = Object.freeze({
884
- animation: null,
885
- className: "",
886
- fadeEdges: null,
887
- fit: null,
888
- image: null,
889
- imageStyle: {},
890
- isPlaying: false,
891
- noiseStyle: {},
892
- overlay: false,
893
- overlayColor: "var(--black)",
894
- overlayOpacity: 0,
895
- position: "center",
896
- video: null,
897
- videoClassName: "",
898
- videoElement: null,
899
- videoOptions: {
900
- autoplay: true,
901
- className: "",
902
- corp: 0,
903
- loop: false,
904
- muted: true,
905
- playbackRate: 1,
906
- width: null
907
- },
908
- videoStyle: {},
909
- width: null
910
- });
911
- var DEFAULT_BACKGROUND_COMPUTED = Object.freeze({
912
- ...DEFAULT_BACKGROUND,
913
- hasBackground: false,
914
- isVideo: false,
915
- isYouTube: false,
916
- posterUrl: null,
917
- youtubeVideoId: null
918
- });
919
- var INERT_BACKGROUND_ACTIONS = Object.freeze({
920
- resetBackground: () => {
921
- },
922
- setBackground: () => {
923
- },
924
- setVideoElement: () => {
925
- },
926
- setVideoMuted: () => {
927
- },
928
- setVideoPlaying: () => {
929
- },
930
- toggleLoop: () => {
931
- },
932
- toggleMute: () => {
933
- },
934
- toggleVideo: () => {
935
- }
936
- });
848
+ var backgroundTheme = defineThemeSpec("background");
849
+ var BACKGROUND_REGISTRY_KEY = "page-background";
850
+ var BACKGROUND_MEDIA_ID = "background";
851
+
852
+ // src/modules/background/visual.ts
937
853
  var objectFit = (value) => ({
938
854
  objectFit: value
939
855
  });
@@ -956,65 +872,313 @@ var BG_TOKEN_TO_OBJECT_STYLE = Object.freeze({
956
872
  "bg-scale-down": objectFit("scale-down"),
957
873
  "bg-top": objectPosition("top")
958
874
  });
959
- var OBJECT_FITS = Object.freeze([
960
- "contain",
961
- "cover",
962
- "fill",
963
- "none",
964
- "scale-down"
965
- ]);
875
+ var OBJECT_FITS = Object.freeze(["contain", "cover", "fill", "none", "scale-down"]);
966
876
  var DEFAULT_COLOR = "var(--black, #000)";
967
- var backgroundTheme = defineThemeSpec("background");
968
- var BACKGROUND_REGISTRY_KEY = "page-background";
969
- var BACKGROUND_MEDIA_ID = "background";
970
-
971
- // src/modules/background/youtube/parse.ts
972
- var YOUTUBE_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/;
973
- function parseYouTubeTimeParam(value) {
974
- if (value === void 0 || value === null || value === "") return 0;
975
- if (typeof value === "number") {
976
- return Number.isFinite(value) && value >= 0 ? value : 0;
977
- }
978
- const trimmed = String(value).trim().toLowerCase();
979
- if (!trimmed) return 0;
980
- if (/^\d+(\.\d+)?$/.test(trimmed)) {
981
- return Math.max(0, parseFloat(trimmed));
982
- }
983
- const hmsMatch = trimmed.match(
984
- /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s?)?$/
985
- );
986
- if (hmsMatch && (hmsMatch[1] || hmsMatch[2] || hmsMatch[3])) {
987
- const hours = parseInt(hmsMatch[1] || "0", 10);
988
- const minutes = parseInt(hmsMatch[2] || "0", 10);
989
- const seconds = parseFloat(hmsMatch[3] || "0");
990
- return Math.max(0, hours * 3600 + minutes * 60 + seconds);
877
+ var WIDTH_CLASS = /^(w-|max-w-|min-w-)/;
878
+ function resolveVideoClassNames(...inputs) {
879
+ const tokens = inputs.flatMap((input) => typeof input === "string" ? input.replace(/,/g, " ").split(/\s+/) : []).filter(Boolean);
880
+ return {
881
+ objectStyle: Object.assign({}, ...tokens.map((token) => BG_TOKEN_TO_OBJECT_STYLE[token])),
882
+ other: tokens.filter((token) => !WIDTH_CLASS.test(token)).join(" "),
883
+ width: tokens.filter((token) => WIDTH_CLASS.test(token)).join(" ")
884
+ };
885
+ }
886
+ function resolveVideoOptions(options = {}) {
887
+ return {
888
+ codec: options.codec || "auto",
889
+ corp: options.corp ?? 0,
890
+ forceIframe: Boolean(options.forceIframe),
891
+ isLoop: options.loop ?? false,
892
+ isMuted: options.muted ?? true,
893
+ playbackRate: options.playbackRate ?? 1,
894
+ quality: options.quality || "1080p",
895
+ shouldAutoPlay: options.autoplay ?? true,
896
+ showPoster: Boolean(options.showPoster),
897
+ showSpinner: options.showSpinner !== false
898
+ };
899
+ }
900
+ var generateBaseGradient = (direction, color) => {
901
+ const to = direction === "left" ? "to right" : "to left";
902
+ return `linear-gradient(${to}, ${color} 0%, color-mix(in srgb, ${color} 85%, transparent) 15%, color-mix(in srgb, ${color} 50%, transparent) 45%, color-mix(in srgb, ${color} 18%, transparent) 75%, transparent 100%)`;
903
+ };
904
+ var generateEdgeGradient = (direction, color) => {
905
+ const to = direction === "left" ? "to right" : "to left";
906
+ return `linear-gradient(${to}, color-mix(in srgb, ${color} 95%, transparent) 0%, color-mix(in srgb, ${color} 70%, transparent) 25%, color-mix(in srgb, ${color} 35%, transparent) 55%, color-mix(in srgb, ${color} 10%, transparent) 80%, transparent 100%)`;
907
+ };
908
+ function getVisualStyle(currentStyle = {}) {
909
+ const { className: _className, leftGradient = 0, rightGradient = 0, ...baseStyle } = currentStyle;
910
+ return {
911
+ baseStyle,
912
+ leftGradient: Number(leftGradient) || 0,
913
+ rightGradient: Number(rightGradient) || 0
914
+ };
915
+ }
916
+ function resolveGradientSettings({
917
+ fadeEdges = null,
918
+ hasWidth = false,
919
+ leftGradient = 0,
920
+ rightGradient = 0
921
+ }) {
922
+ let leftPercent = 0;
923
+ let rightPercent = 0;
924
+ if (leftGradient > 0) leftPercent = Math.min(48, Math.max(12, leftGradient * 7.5));
925
+ else if (hasWidth && fadeEdges !== false) leftPercent = 20;
926
+ if (rightGradient > 0) rightPercent = Math.min(48, Math.max(12, rightGradient * 7.5));
927
+ else if (hasWidth && fadeEdges !== false) rightPercent = 20;
928
+ if (typeof fadeEdges === "number") {
929
+ leftPercent = fadeEdges;
930
+ rightPercent = fadeEdges;
931
+ } else if (typeof fadeEdges === "string") {
932
+ const parsed = parseFloat(fadeEdges);
933
+ if (!Number.isNaN(parsed)) {
934
+ leftPercent = parsed;
935
+ rightPercent = parsed;
936
+ }
937
+ } else if (typeof fadeEdges === "object" && fadeEdges !== null) {
938
+ const edgeObj = fadeEdges;
939
+ if (edgeObj.left !== void 0) leftPercent = parseFloat(String(edgeObj.left)) || 0;
940
+ if (edgeObj.right !== void 0) rightPercent = parseFloat(String(edgeObj.right)) || 0;
941
+ } else if (fadeEdges === false) {
942
+ leftPercent = 0;
943
+ rightPercent = 0;
991
944
  }
992
- return 0;
945
+ const leftOpacity = leftGradient > 0 ? Math.min(1, leftGradient * 0.22) : 0;
946
+ const rightOpacity = rightGradient > 0 ? Math.min(1, rightGradient * 0.22) : 0;
947
+ return {
948
+ enabled: leftPercent > 0 || rightPercent > 0,
949
+ leftOpacity,
950
+ leftPercent,
951
+ rightOpacity,
952
+ rightPercent
953
+ };
993
954
  }
994
- var YOUTUBE_HOST_PATH = /^(?:www\.|m\.|music\.)?(?:youtube\.com|youtu\.be|youtube-nocookie\.com)\//i;
995
- function toUrl(input, { youtubeOnly = false } = {}) {
996
- let candidate = null;
997
- if (/^https?:\/\//.test(input)) candidate = input;
998
- else if (input.startsWith("//")) candidate = `https:${input}`;
999
- else if (!youtubeOnly || YOUTUBE_HOST_PATH.test(input)) {
1000
- candidate = `https://${input}`;
955
+ function generateSmoothstepStops(percent, direction = "in", color = "var(--black, #000)") {
956
+ const steps = [
957
+ { s: 0, t: 0 },
958
+ { s: 0.06, t: 0.15 },
959
+ { s: 0.22, t: 0.35 },
960
+ { s: 0.47, t: 0.55 },
961
+ { s: 0.76, t: 0.75 },
962
+ { s: 0.93, t: 0.9 },
963
+ { s: 1, t: 1 }
964
+ ];
965
+ if (direction === "in") {
966
+ return steps.map(
967
+ ({ s, t }) => s === 0 ? `transparent ${(t * percent).toFixed(1)}%` : s === 1 ? `${color} ${(t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(s * 100)}%, transparent) ${(t * percent).toFixed(1)}%`
968
+ );
1001
969
  }
970
+ return steps.map(({ s, t }) => {
971
+ const alpha = 1 - s;
972
+ return alpha === 0 ? `transparent ${(100 - percent + t * percent).toFixed(1)}%` : alpha === 1 ? `${color} ${(100 - percent + t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent) ${(100 - percent + t * percent).toFixed(1)}%`;
973
+ });
974
+ }
975
+ function getEdgeFadeMask({
976
+ color = "var(--black, #000)",
977
+ leftPercent = 0,
978
+ rightPercent = 0
979
+ }) {
980
+ if (leftPercent <= 0 && rightPercent <= 0) return void 0;
981
+ const leftStops = leftPercent > 0 ? generateSmoothstepStops(leftPercent, "in", color) : [`${color} 0%`];
982
+ const rightStops = rightPercent > 0 ? generateSmoothstepStops(rightPercent, "out", color) : [`${color} 100%`];
983
+ return `linear-gradient(to right, ${leftStops.join(", ")}, ${rightStops.join(", ")})`;
984
+ }
985
+
986
+ // src/modules/background/playback.ts
987
+ function applyVideoPlaybackState({
988
+ isPlaying,
989
+ playbackRate,
990
+ setVideoPlaying,
991
+ videoElement
992
+ }) {
993
+ if (!videoElement) return;
994
+ const numericPlaybackRate = Number(playbackRate);
995
+ const resolvedPlaybackRate = Number.isFinite(numericPlaybackRate) && numericPlaybackRate > 0 ? numericPlaybackRate : 1;
1002
996
  try {
1003
- return candidate ? new URL(candidate) : null;
997
+ if (videoElement.playbackRate !== resolvedPlaybackRate) {
998
+ videoElement.playbackRate = resolvedPlaybackRate;
999
+ }
1004
1000
  } catch {
1005
- return null;
1001
+ return;
1006
1002
  }
1007
- }
1008
- function getIdFromUrl(url) {
1009
- const host = url.hostname.replace(/^(www\.|m\.|music\.)/i, "").toLowerCase();
1010
- const segments = url.pathname.split("/").filter(Boolean);
1011
- if (host === "youtu.be") {
1012
- return YOUTUBE_ID_PATTERN.test(segments[0] ?? "") ? segments[0] : null;
1003
+ if (!isPlaying) {
1004
+ if (!videoElement.paused) videoElement.pause();
1005
+ return;
1013
1006
  }
1014
- if (host !== "youtube.com" && host !== "youtube-nocookie.com" && !host.endsWith(".youtube.com")) {
1015
- return null;
1007
+ if (videoElement.readyState === 0) {
1008
+ return;
1016
1009
  }
1017
- const fromQuery = url.searchParams.get("v") || url.searchParams.get("vi");
1010
+ const playPromise = videoElement.play();
1011
+ if (!playPromise || typeof playPromise.then !== "function") return;
1012
+ playPromise.then(() => setVideoPlaying(true)).catch((error) => {
1013
+ if (error?.name === "AbortError" || videoElement.readyState < 2) {
1014
+ return;
1015
+ }
1016
+ if (error?.name === "NotAllowedError") {
1017
+ videoElement.muted = true;
1018
+ videoElement.play().then(() => setVideoPlaying(true)).catch(() => {
1019
+ });
1020
+ return;
1021
+ }
1022
+ setVideoPlaying(false);
1023
+ });
1024
+ }
1025
+ function triggerVideoPlaybackDirect(videoElement, nextPlaying, configuredMuted) {
1026
+ if (!videoElement) return;
1027
+ if (nextPlaying) {
1028
+ videoElement.muted = configuredMuted;
1029
+ if (!configuredMuted && videoElement.volume === 0) {
1030
+ videoElement.volume = 0.8;
1031
+ }
1032
+ videoElement.play().catch((err) => {
1033
+ if (err?.name === "NotAllowedError") {
1034
+ videoElement.muted = true;
1035
+ videoElement.play().catch(() => {
1036
+ });
1037
+ }
1038
+ });
1039
+ } else {
1040
+ videoElement.pause();
1041
+ }
1042
+ }
1043
+ function syncVideoMutedDirect(videoElement, nextMuted) {
1044
+ if (!videoElement) return;
1045
+ videoElement.muted = nextMuted;
1046
+ if (!nextMuted && videoElement.volume === 0) {
1047
+ videoElement.volume = 0.8;
1048
+ }
1049
+ }
1050
+ function syncVideoLoopDirect(videoElement, nextLoop) {
1051
+ if (!videoElement) return;
1052
+ videoElement.loop = nextLoop;
1053
+ }
1054
+
1055
+ // src/modules/background/motion.ts
1056
+ var DEFAULT_MOTION = Object.freeze({
1057
+ animate: Object.freeze({
1058
+ opacity: 1
1059
+ }),
1060
+ exit: Object.freeze({
1061
+ opacity: 0,
1062
+ transition: Object.freeze({
1063
+ duration: DURATION_TOKENS.SLOW,
1064
+ ease: EASING_CURVES.IN_CUBIC
1065
+ })
1066
+ }),
1067
+ initial: Object.freeze({
1068
+ opacity: 0
1069
+ }),
1070
+ transition: Object.freeze({
1071
+ delay: 0,
1072
+ duration: DURATION_TOKENS.SLOW,
1073
+ ease: EASING_CURVES.OUT_QUART
1074
+ })
1075
+ });
1076
+ function getBackgroundMotionConfig(animation) {
1077
+ return {
1078
+ animate: animation?.animate ?? DEFAULT_MOTION.animate,
1079
+ exit: animation?.exit ?? DEFAULT_MOTION.exit,
1080
+ exitDurationFactor: Number(animation?.exitDurationFactor),
1081
+ initial: animation?.initial ?? DEFAULT_MOTION.initial,
1082
+ transition: animation?.transition ?? DEFAULT_MOTION.transition
1083
+ };
1084
+ }
1085
+ function toCssDuration(seconds) {
1086
+ const value = Number(seconds);
1087
+ return `${Math.max(0, Number.isFinite(value) ? value : DURATION_TOKENS.SLOW) * 1e3}ms`;
1088
+ }
1089
+ function toCssDelay(seconds) {
1090
+ const value = Number(seconds);
1091
+ return `${Math.max(0, Number.isFinite(value) ? value : 0) * 1e3}ms`;
1092
+ }
1093
+ function toCssEasing(easing) {
1094
+ if (Array.isArray(easing)) {
1095
+ return `cubic-bezier(${easing.join(", ")})`;
1096
+ }
1097
+ if (typeof easing === "string" && easing.trim()) {
1098
+ return easing;
1099
+ }
1100
+ return "ease";
1101
+ }
1102
+
1103
+ // src/modules/media/constants.ts
1104
+ var DEFAULT_MEDIA_STATE = Object.freeze({
1105
+ audibleElement: null,
1106
+ element: null,
1107
+ hasMedia: false,
1108
+ isPlaying: false,
1109
+ kind: null,
1110
+ loop: false,
1111
+ sourceId: null
1112
+ });
1113
+ var INERT_MEDIA_ACTIONS = Object.freeze({
1114
+ removeSource: () => {
1115
+ },
1116
+ setMuted: () => {
1117
+ },
1118
+ toggle: () => {
1119
+ },
1120
+ toggleLoop: () => {
1121
+ },
1122
+ upsertSource: () => {
1123
+ }
1124
+ });
1125
+ var MediaContext = getOrCreateGlobalContext(
1126
+ "MediaContext",
1127
+ null
1128
+ );
1129
+ createStore(DEFAULT_MEDIA_STATE);
1130
+ function useOptionalMediaActions() {
1131
+ const ctx = useContext(MediaContext);
1132
+ return ctx?.actions ?? INERT_MEDIA_ACTIONS;
1133
+ }
1134
+
1135
+ // src/modules/background/youtube/parse.ts
1136
+ var YOUTUBE_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/;
1137
+ function parseYouTubeTimeParam(value) {
1138
+ if (value === void 0 || value === null || value === "") return 0;
1139
+ if (typeof value === "number") {
1140
+ return Number.isFinite(value) && value >= 0 ? value : 0;
1141
+ }
1142
+ const trimmed = String(value).trim().toLowerCase();
1143
+ if (!trimmed) return 0;
1144
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
1145
+ return Math.max(0, parseFloat(trimmed));
1146
+ }
1147
+ const hmsMatch = trimmed.match(
1148
+ /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s?)?$/
1149
+ );
1150
+ if (hmsMatch && (hmsMatch[1] || hmsMatch[2] || hmsMatch[3])) {
1151
+ const hours = parseInt(hmsMatch[1] || "0", 10);
1152
+ const minutes = parseInt(hmsMatch[2] || "0", 10);
1153
+ const seconds = parseFloat(hmsMatch[3] || "0");
1154
+ return Math.max(0, hours * 3600 + minutes * 60 + seconds);
1155
+ }
1156
+ return 0;
1157
+ }
1158
+ var YOUTUBE_HOST_PATH = /^(?:www\.|m\.|music\.)?(?:youtube\.com|youtu\.be|youtube-nocookie\.com)\//i;
1159
+ function toUrl(input, { youtubeOnly = false } = {}) {
1160
+ let candidate = null;
1161
+ if (/^https?:\/\//.test(input)) candidate = input;
1162
+ else if (input.startsWith("//")) candidate = `https:${input}`;
1163
+ else if (!youtubeOnly || YOUTUBE_HOST_PATH.test(input)) {
1164
+ candidate = `https://${input}`;
1165
+ }
1166
+ try {
1167
+ return candidate ? new URL(candidate) : null;
1168
+ } catch {
1169
+ return null;
1170
+ }
1171
+ }
1172
+ function getIdFromUrl(url) {
1173
+ const host = url.hostname.replace(/^(www\.|m\.|music\.)/i, "").toLowerCase();
1174
+ const segments = url.pathname.split("/").filter(Boolean);
1175
+ if (host === "youtu.be") {
1176
+ return YOUTUBE_ID_PATTERN.test(segments[0] ?? "") ? segments[0] : null;
1177
+ }
1178
+ if (host !== "youtube.com" && host !== "youtube-nocookie.com" && !host.endsWith(".youtube.com")) {
1179
+ return null;
1180
+ }
1181
+ const fromQuery = url.searchParams.get("v") || url.searchParams.get("vi");
1018
1182
  if (fromQuery && YOUTUBE_ID_PATTERN.test(fromQuery)) return fromQuery;
1019
1183
  const isVideoPath = segments.length >= 2 && ["embed", "shorts", "live", "v", "e", "watch"].includes(
1020
1184
  segments[0].toLowerCase()
@@ -1139,35 +1303,61 @@ function createYouTubeVideoElementProxy(controller) {
1139
1303
  return proxyVideo;
1140
1304
  }
1141
1305
 
1142
- // src/modules/background/utils.ts
1143
- var WIDTH_CLASS = /^(w-|max-w-|min-w-)/;
1144
- function resolveVideoClassNames(...inputs) {
1145
- const tokens = inputs.flatMap(
1146
- (input) => typeof input === "string" ? input.replace(/,/g, " ").split(/\s+/) : []
1147
- ).filter(Boolean);
1148
- return {
1149
- objectStyle: Object.assign(
1150
- {},
1151
- ...tokens.map((token) => BG_TOKEN_TO_OBJECT_STYLE[token])
1152
- ),
1153
- other: tokens.filter((token) => !WIDTH_CLASS.test(token)).join(" "),
1154
- width: tokens.filter((token) => WIDTH_CLASS.test(token)).join(" ")
1155
- };
1156
- }
1157
- function resolveVideoOptions(options = {}) {
1158
- return {
1159
- codec: options.codec || "auto",
1160
- corp: options.corp ?? 0,
1161
- forceIframe: Boolean(options.forceIframe),
1162
- isLoop: options.loop ?? false,
1163
- isMuted: options.muted ?? true,
1164
- playbackRate: options.playbackRate ?? 1,
1165
- quality: options.quality || "1080p",
1166
- shouldAutoPlay: options.autoplay ?? true,
1167
- showPoster: Boolean(options.showPoster),
1168
- showSpinner: options.showSpinner !== false
1169
- };
1170
- }
1306
+ // src/modules/background/state.ts
1307
+ var DEFAULT_BACKGROUND = Object.freeze({
1308
+ animation: null,
1309
+ className: "",
1310
+ fadeEdges: null,
1311
+ fit: null,
1312
+ image: null,
1313
+ imageStyle: {},
1314
+ isPlaying: false,
1315
+ noiseStyle: {},
1316
+ overlay: false,
1317
+ overlayColor: "var(--black)",
1318
+ overlayOpacity: 0,
1319
+ position: "center",
1320
+ video: null,
1321
+ videoClassName: "",
1322
+ videoElement: null,
1323
+ videoOptions: {
1324
+ autoplay: true,
1325
+ className: "",
1326
+ corp: 0,
1327
+ loop: false,
1328
+ muted: true,
1329
+ playbackRate: 1,
1330
+ width: null
1331
+ },
1332
+ videoStyle: {},
1333
+ width: null
1334
+ });
1335
+ var DEFAULT_BACKGROUND_COMPUTED = Object.freeze({
1336
+ ...DEFAULT_BACKGROUND,
1337
+ hasBackground: false,
1338
+ isVideo: false,
1339
+ isYouTube: false,
1340
+ posterUrl: null,
1341
+ youtubeVideoId: null
1342
+ });
1343
+ var INERT_BACKGROUND_ACTIONS = Object.freeze({
1344
+ resetBackground: () => {
1345
+ },
1346
+ setBackground: () => {
1347
+ },
1348
+ setVideoElement: () => {
1349
+ },
1350
+ setVideoMuted: () => {
1351
+ },
1352
+ setVideoPlaying: () => {
1353
+ },
1354
+ toggleLoop: () => {
1355
+ },
1356
+ toggleMute: () => {
1357
+ },
1358
+ toggleVideo: () => {
1359
+ }
1360
+ });
1171
1361
  function normalizeBackgroundInput(patch = {}) {
1172
1362
  if (!patch) return {};
1173
1363
  if (typeof patch === "string") {
@@ -1216,268 +1406,10 @@ function mergeBackgroundState(baseState, patch = {}) {
1216
1406
  }
1217
1407
  };
1218
1408
  }
1219
- function selectPageBackground(background) {
1220
- return background ? normalizeBackgroundInput(background) : null;
1221
- }
1222
- var generateBaseGradient = (direction, color) => {
1223
- const to = direction === "left" ? "to right" : "to left";
1224
- return `linear-gradient(${to}, ${color} 0%, color-mix(in srgb, ${color} 85%, transparent) 15%, color-mix(in srgb, ${color} 50%, transparent) 45%, color-mix(in srgb, ${color} 18%, transparent) 75%, transparent 100%)`;
1225
- };
1226
- var generateEdgeGradient = (direction, color) => {
1227
- const to = direction === "left" ? "to right" : "to left";
1228
- return `linear-gradient(${to}, color-mix(in srgb, ${color} 95%, transparent) 0%, color-mix(in srgb, ${color} 70%, transparent) 25%, color-mix(in srgb, ${color} 35%, transparent) 55%, color-mix(in srgb, ${color} 10%, transparent) 80%, transparent 100%)`;
1229
- };
1230
- function getVisualStyle(currentStyle = {}) {
1231
- const {
1232
- className: _className,
1233
- leftGradient = 0,
1234
- rightGradient = 0,
1235
- ...baseStyle
1236
- } = currentStyle;
1237
- return {
1238
- baseStyle,
1239
- leftGradient: Number(leftGradient) || 0,
1240
- rightGradient: Number(rightGradient) || 0
1241
- };
1242
- }
1243
- function resolveGradientSettings({
1244
- fadeEdges = null,
1245
- hasWidth = false,
1246
- leftGradient = 0,
1247
- rightGradient = 0
1248
- }) {
1249
- let leftPercent = 0;
1250
- let rightPercent = 0;
1251
- if (leftGradient > 0)
1252
- leftPercent = Math.min(48, Math.max(12, leftGradient * 7.5));
1253
- else if (hasWidth && fadeEdges !== false) leftPercent = 20;
1254
- if (rightGradient > 0)
1255
- rightPercent = Math.min(48, Math.max(12, rightGradient * 7.5));
1256
- else if (hasWidth && fadeEdges !== false) rightPercent = 20;
1257
- if (typeof fadeEdges === "number") {
1258
- leftPercent = fadeEdges;
1259
- rightPercent = fadeEdges;
1260
- } else if (typeof fadeEdges === "string") {
1261
- const parsed = parseFloat(fadeEdges);
1262
- if (!Number.isNaN(parsed)) {
1263
- leftPercent = parsed;
1264
- rightPercent = parsed;
1265
- }
1266
- } else if (typeof fadeEdges === "object" && fadeEdges !== null) {
1267
- const edgeObj = fadeEdges;
1268
- if (edgeObj.left !== void 0)
1269
- leftPercent = parseFloat(String(edgeObj.left)) || 0;
1270
- if (edgeObj.right !== void 0)
1271
- rightPercent = parseFloat(String(edgeObj.right)) || 0;
1272
- } else if (fadeEdges === false) {
1273
- leftPercent = 0;
1274
- rightPercent = 0;
1275
- }
1276
- const leftOpacity = leftGradient > 0 ? Math.min(1, leftGradient * 0.22) : 0;
1277
- const rightOpacity = rightGradient > 0 ? Math.min(1, rightGradient * 0.22) : 0;
1278
- return {
1279
- enabled: leftPercent > 0 || rightPercent > 0,
1280
- leftOpacity,
1281
- leftPercent,
1282
- rightOpacity,
1283
- rightPercent
1284
- };
1285
- }
1286
- function generateSmoothstepStops(percent, direction = "in", color = "var(--black, #000)") {
1287
- const steps = [
1288
- { s: 0, t: 0 },
1289
- { s: 0.06, t: 0.15 },
1290
- { s: 0.22, t: 0.35 },
1291
- { s: 0.47, t: 0.55 },
1292
- { s: 0.76, t: 0.75 },
1293
- { s: 0.93, t: 0.9 },
1294
- { s: 1, t: 1 }
1295
- ];
1296
- if (direction === "in") {
1297
- return steps.map(
1298
- ({ s, t }) => s === 0 ? `transparent ${(t * percent).toFixed(1)}%` : s === 1 ? `${color} ${(t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(s * 100)}%, transparent) ${(t * percent).toFixed(1)}%`
1299
- );
1300
- }
1301
- return steps.map(({ s, t }) => {
1302
- const alpha = 1 - s;
1303
- return alpha === 0 ? `transparent ${(100 - percent + t * percent).toFixed(1)}%` : alpha === 1 ? `${color} ${(100 - percent + t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent) ${(100 - percent + t * percent).toFixed(1)}%`;
1304
- });
1305
- }
1306
- function getEdgeFadeMask({
1307
- color = "var(--black, #000)",
1308
- leftPercent = 0,
1309
- rightPercent = 0
1310
- }) {
1311
- if (leftPercent <= 0 && rightPercent <= 0) return void 0;
1312
- const leftStops = leftPercent > 0 ? generateSmoothstepStops(leftPercent, "in", color) : [`${color} 0%`];
1313
- const rightStops = rightPercent > 0 ? generateSmoothstepStops(rightPercent, "out", color) : [`${color} 100%`];
1314
- return `linear-gradient(to right, ${leftStops.join(", ")}, ${rightStops.join(", ")})`;
1315
- }
1316
- function applyVideoPlaybackState({
1317
- isPlaying,
1318
- playbackRate,
1319
- setVideoPlaying,
1320
- videoElement
1321
- }) {
1322
- if (!videoElement) return;
1323
- const numericPlaybackRate = Number(playbackRate);
1324
- const resolvedPlaybackRate = Number.isFinite(numericPlaybackRate) && numericPlaybackRate > 0 ? numericPlaybackRate : 1;
1325
- try {
1326
- if (videoElement.playbackRate !== resolvedPlaybackRate) {
1327
- videoElement.playbackRate = resolvedPlaybackRate;
1328
- }
1329
- } catch {
1330
- return;
1331
- }
1332
- if (!isPlaying) {
1333
- if (!videoElement.paused) videoElement.pause();
1334
- return;
1335
- }
1336
- if (videoElement.readyState === 0) {
1337
- return;
1338
- }
1339
- const playPromise = videoElement.play();
1340
- if (!playPromise || typeof playPromise.then !== "function") return;
1341
- playPromise.then(() => setVideoPlaying(true)).catch((error) => {
1342
- if (error?.name === "AbortError" || videoElement.readyState < 2) {
1343
- return;
1344
- }
1345
- if (error?.name === "NotAllowedError") {
1346
- videoElement.muted = true;
1347
- videoElement.play().then(() => setVideoPlaying(true)).catch(() => {
1348
- });
1349
- return;
1350
- }
1351
- setVideoPlaying(false);
1352
- });
1353
- }
1354
- function triggerVideoPlaybackDirect(videoElement, nextPlaying, configuredMuted) {
1355
- if (!videoElement) return;
1356
- if (nextPlaying) {
1357
- videoElement.muted = configuredMuted;
1358
- if (!configuredMuted && videoElement.volume === 0) {
1359
- videoElement.volume = 0.8;
1360
- }
1361
- videoElement.play().catch((err) => {
1362
- if (err?.name === "NotAllowedError") {
1363
- videoElement.muted = true;
1364
- videoElement.play().catch(() => {
1365
- });
1366
- }
1367
- });
1368
- } else {
1369
- videoElement.pause();
1370
- }
1371
- }
1372
- function syncVideoMutedDirect(videoElement, nextMuted) {
1373
- if (!videoElement) return;
1374
- videoElement.muted = nextMuted;
1375
- if (!nextMuted && videoElement.volume === 0) {
1376
- videoElement.volume = 0.8;
1377
- }
1378
- }
1379
- function syncVideoLoopDirect(videoElement, nextLoop) {
1380
- if (!videoElement) return;
1381
- videoElement.loop = nextLoop;
1382
- }
1383
-
1384
- // src/modules/background/motion.ts
1385
- var DEFAULT_MOTION = Object.freeze({
1386
- animate: Object.freeze({
1387
- opacity: 1
1388
- }),
1389
- exit: Object.freeze({
1390
- opacity: 0,
1391
- transition: Object.freeze({
1392
- duration: DURATION_TOKENS.SLOW,
1393
- ease: EASING_CURVES.IN_CUBIC
1394
- })
1395
- }),
1396
- initial: Object.freeze({
1397
- opacity: 0
1398
- }),
1399
- transition: Object.freeze({
1400
- delay: 0,
1401
- duration: DURATION_TOKENS.SLOW,
1402
- ease: EASING_CURVES.OUT_QUART
1403
- })
1404
- });
1405
- function getBackgroundMotionConfig(animation) {
1406
- return {
1407
- animate: animation?.animate ?? DEFAULT_MOTION.animate,
1408
- exit: animation?.exit ?? DEFAULT_MOTION.exit,
1409
- exitDurationFactor: Number(animation?.exitDurationFactor),
1410
- initial: animation?.initial ?? DEFAULT_MOTION.initial,
1411
- transition: animation?.transition ?? DEFAULT_MOTION.transition
1412
- };
1413
- }
1414
- function toCssDuration(seconds) {
1415
- const value = Number(seconds);
1416
- return `${Math.max(0, Number.isFinite(value) ? value : DURATION_TOKENS.SLOW) * 1e3}ms`;
1417
- }
1418
- function toCssDelay(seconds) {
1419
- const value = Number(seconds);
1420
- return `${Math.max(0, Number.isFinite(value) ? value : 0) * 1e3}ms`;
1421
- }
1422
- function toCssEasing(easing) {
1423
- if (Array.isArray(easing)) {
1424
- return `cubic-bezier(${easing.join(", ")})`;
1425
- }
1426
- if (typeof easing === "string" && easing.trim()) {
1427
- return easing;
1428
- }
1429
- return "ease";
1430
- }
1431
-
1432
- // src/modules/media/constants.ts
1433
- var DEFAULT_MEDIA_STATE = Object.freeze({
1434
- audibleElement: null,
1435
- element: null,
1436
- hasMedia: false,
1437
- isPlaying: false,
1438
- kind: null,
1439
- loop: false,
1440
- sourceId: null
1441
- });
1442
- var INERT_MEDIA_ACTIONS = Object.freeze({
1443
- removeSource: () => {
1444
- },
1445
- setMuted: () => {
1446
- },
1447
- toggle: () => {
1448
- },
1449
- toggleLoop: () => {
1450
- },
1451
- upsertSource: () => {
1452
- }
1453
- });
1454
- var MediaContext = getOrCreateGlobalContext(
1455
- "MediaContext",
1456
- null
1457
- );
1458
- createStore(DEFAULT_MEDIA_STATE);
1459
- function useOptionalMediaActions() {
1460
- const ctx = useContext(MediaContext);
1461
- return ctx?.actions ?? INERT_MEDIA_ACTIONS;
1462
- }
1463
- var BackgroundContext = getOrCreateGlobalContext(
1464
- "BackgroundContext",
1465
- null
1466
- );
1467
- function useBackgroundRegistration(config, options) {
1468
- useModuleRegistration("background", config, options);
1469
- }
1470
- function useSafePathname() {
1471
- try {
1472
- return usePathname();
1473
- } catch {
1474
- return null;
1475
- }
1476
- }
1477
- function resolveBackgroundState(registryBackground, override, pathname) {
1478
- const base = registryBackground ? mergeBackgroundState(DEFAULT_BACKGROUND, registryBackground) : DEFAULT_BACKGROUND;
1479
- const patch = override.pathname === pathname ? override.patch : null;
1480
- return patch ? mergeBackgroundState(base, patch) : base;
1409
+ function resolveBackgroundState(registryBackground, override, pathname) {
1410
+ const base = registryBackground ? mergeBackgroundState(DEFAULT_BACKGROUND, registryBackground) : DEFAULT_BACKGROUND;
1411
+ const patch = override.pathname === pathname ? override.patch : null;
1412
+ return patch ? mergeBackgroundState(base, patch) : base;
1481
1413
  }
1482
1414
  function computeBackgroundState(background) {
1483
1415
  const youtubeVideoId = extractYouTubeVideoId(background.video);
@@ -1494,6 +1426,17 @@ function computeBackgroundState(background) {
1494
1426
  youtubeVideoId
1495
1427
  };
1496
1428
  }
1429
+ var BackgroundContext = getOrCreateGlobalContext(
1430
+ "BackgroundContext",
1431
+ null
1432
+ );
1433
+ function useSafePathname() {
1434
+ try {
1435
+ return usePathname();
1436
+ } catch {
1437
+ return null;
1438
+ }
1439
+ }
1497
1440
  function BackgroundProvider({ children }) {
1498
1441
  const pathname = useSafePathname();
1499
1442
  const registryBackground = useRegistryValue(
@@ -1508,7 +1451,7 @@ function BackgroundProvider({ children }) {
1508
1451
  );
1509
1452
  const scopedOverride = useStore(overrideStore);
1510
1453
  const inputsRef = useRef({ pathname, registryBackground });
1511
- useInsertionEffect(() => {
1454
+ useIsomorphicLayoutEffect(() => {
1512
1455
  inputsRef.current = { pathname, registryBackground };
1513
1456
  }, [pathname, registryBackground]);
1514
1457
  const videoElementRef = useRef(null);
@@ -1648,6 +1591,14 @@ function BackgroundProvider({ children }) {
1648
1591
  );
1649
1592
  return /* @__PURE__ */ jsx(BackgroundContext, { value, children });
1650
1593
  }
1594
+
1595
+ // src/modules/background/hooks.ts
1596
+ var NOOP_BACKGROUND_STORE = createStore(
1597
+ DEFAULT_BACKGROUND_COMPUTED
1598
+ );
1599
+ function useBackgroundRegistration(config, options) {
1600
+ useModuleRegistration("background", config, options);
1601
+ }
1651
1602
  function useBackgroundState() {
1652
1603
  const { store } = useRequiredContext(
1653
1604
  BackgroundContext,
@@ -1669,9 +1620,6 @@ function useBackground(config, options) {
1669
1620
  const state = useBackgroundState();
1670
1621
  return useMemo(() => ({ ...state, ...actions }), [actions, state]);
1671
1622
  }
1672
- var NOOP_BACKGROUND_STORE = createStore(
1673
- DEFAULT_BACKGROUND_COMPUTED
1674
- );
1675
1623
  function useOptionalBackgroundState(selector, isEqual) {
1676
1624
  const ctx = useContext(BackgroundContext);
1677
1625
  return useStore(
@@ -1684,6 +1632,41 @@ function useOptionalBackgroundActions() {
1684
1632
  const ctx = useContext(BackgroundContext);
1685
1633
  return ctx?.actions ?? INERT_BACKGROUND_ACTIONS;
1686
1634
  }
1635
+ function Icon({
1636
+ className = "center",
1637
+ color,
1638
+ icon,
1639
+ onClick,
1640
+ size = 20,
1641
+ style,
1642
+ ...props
1643
+ }) {
1644
+ return /* @__PURE__ */ jsx(
1645
+ Icon$1,
1646
+ {
1647
+ className,
1648
+ height: size,
1649
+ icon,
1650
+ onClick,
1651
+ style: { color, ...style },
1652
+ width: size,
1653
+ ...props
1654
+ }
1655
+ );
1656
+ }
1657
+ Icon.displayName = "Icon";
1658
+ function Spinner({ className = "", size = 15 }) {
1659
+ return /* @__PURE__ */ jsx(
1660
+ "div",
1661
+ {
1662
+ className,
1663
+ "aria-label": "Loading",
1664
+ role: "status",
1665
+ children: /* @__PURE__ */ jsx(Icon, { icon: "mingcute:loading-3-fill", size })
1666
+ }
1667
+ );
1668
+ }
1669
+ Spinner.displayName = "Spinner";
1687
1670
  var PLAYER_STATE = { ENDED: 0, PLAYING: 1, PAUSED: 2, BUFFERING: 3 };
1688
1671
  var apiPromise = null;
1689
1672
  function loadYouTubeIframeApi() {
@@ -1952,273 +1935,53 @@ function useYouTubeIframePlayer({
1952
1935
  }
1953
1936
  }, [enabled, isMuted, isPlaying, playbackRate]);
1954
1937
  }
1955
-
1956
- // src/modules/background/hooks.ts
1957
- function useBackgroundOverlayModel() {
1958
- const {
1959
- animation,
1960
- className,
1961
- fadeEdges,
1962
- fit,
1963
- hasBackground,
1964
- image,
1965
- imageStyle,
1966
- isPlaying,
1967
- isVideo,
1968
- isYouTube,
1969
- leftGradient: configuredLeftGradient,
1970
- noiseStyle,
1971
- overlay,
1972
- overlayColor,
1973
- overlayOpacity,
1974
- position,
1975
- rightGradient: configuredRightGradient,
1976
- video,
1977
- videoClassName,
1978
- videoOptions,
1979
- videoStyle,
1980
- width
1981
- } = useBackgroundState();
1982
- const { setVideoElement, setVideoPlaying } = useBackgroundActions();
1983
- const options = resolveVideoOptions(videoOptions);
1984
- const { corp, isMuted, playbackRate } = options;
1985
- const youtubeConfig = useMemo(
1986
- () => isYouTube ? parseYouTubeUrlConfig(video) : null,
1987
- [isYouTube, video]
1988
- );
1989
- const startTime = videoOptions?.startTime ?? youtubeConfig?.startTime ?? 0;
1990
- const endTime = videoOptions?.endTime ?? youtubeConfig?.endTime ?? 0;
1991
- const backgroundKey = isVideo ? youtubeConfig ? `youtube:${youtubeConfig.videoId}` : video : image;
1992
- const motionConfig = useMemo(
1993
- () => getBackgroundMotionConfig(animation),
1994
- [animation]
1995
- );
1996
- const {
1997
- baseStyle,
1998
- leftGradient: styleLeft,
1999
- rightGradient: styleRight
2000
- } = useMemo(
2001
- () => getVisualStyle((isVideo ? videoStyle : imageStyle) || {}),
2002
- [imageStyle, isVideo, videoStyle]
2003
- );
2004
- const leftGradient = configuredLeftGradient ?? styleLeft;
2005
- const rightGradient = configuredRightGradient ?? styleRight;
2006
- const {
2007
- opacity: noiseOpacity,
2008
- mixBlendMode: noiseBlendMode,
2009
- ...noiseInlineStyle
2010
- } = noiseStyle || {};
2011
- const overlayTransitionStyle = useMemo(
2012
- () => ({
2013
- transitionDelay: toCssDelay(motionConfig.transition.delay),
2014
- transitionDuration: toCssDuration(motionConfig.transition.duration),
2015
- transitionProperty: "opacity",
2016
- transitionTimingFunction: toCssEasing(motionConfig.transition.ease)
2017
- }),
2018
- [motionConfig.transition]
2019
- );
2020
- const rawWidth = width ?? videoOptions?.width ?? videoStyle?.width;
2021
- const resolvedWidth = rawWidth === void 0 || rawWidth === null || rawWidth === "" ? void 0 : typeof rawWidth === "number" ? `${rawWidth}px` : String(rawWidth);
2022
- const rawFit = fit ?? videoOptions?.fit ?? videoOptions?.objectFit;
2023
- const theme = useTheme(backgroundTheme);
2024
- const fitStyle = useMemo(
2025
- () => rawFit && OBJECT_FITS.includes(rawFit) ? { objectFit: rawFit } : {},
2026
- [rawFit]
2027
- );
2028
- const classNames = resolveVideoClassNames(
2029
- videoClassName,
2030
- className,
2031
- videoOptions?.videoClassName,
2032
- videoOptions?.className,
2033
- videoStyle?.className
2034
- );
2035
- const hasCustomWidth = Boolean(resolvedWidth || classNames.width);
2036
- const gradientSettings = useMemo(
2037
- () => resolveGradientSettings({
2038
- fadeEdges,
2039
- hasWidth: hasCustomWidth,
2040
- leftGradient,
2041
- rightGradient
2042
- }),
2043
- [fadeEdges, hasCustomWidth, leftGradient, rightGradient]
2044
- );
2045
- const maskImage = useMemo(
2046
- () => gradientSettings.enabled ? getEdgeFadeMask({
2047
- color: overlayColor || DEFAULT_COLOR,
2048
- leftPercent: gradientSettings.leftPercent,
2049
- rightPercent: gradientSettings.rightPercent
2050
- }) : void 0,
2051
- [gradientSettings, overlayColor]
2052
- );
2053
- const framePosition = position === "left" || position === "right" ? position : "center";
2054
- const videoClasses = cn(theme.slots.video, classNames.other);
2055
- const objectPosition2 = baseStyle.objectPosition || position || void 0;
2056
- const sharedVideoStyle = useMemo(
2057
- () => ({
2058
- ...classNames.objectStyle,
2059
- ...fitStyle,
2060
- ...objectPosition2 ? { objectPosition: objectPosition2 } : {},
2061
- ...maskImage ? { WebkitMaskImage: maskImage, maskImage } : {},
2062
- ...baseStyle
2063
- }),
2064
- [baseStyle, classNames.objectStyle, fitStyle, maskImage, objectPosition2]
2065
- );
2066
- const exitDurationFactor = Number.isFinite(motionConfig.exitDurationFactor) ? Math.max(0, motionConfig.exitDurationFactor) : 0.6;
2067
- const exitTransition = motionConfig.exit.transition;
2068
- return {
2069
- className,
2070
- hasBackground,
2071
- image,
2072
- isPlaying,
2073
- isVideo,
2074
- overlay,
2075
- overlayColor,
2076
- overlayOpacity,
2077
- position,
2078
- video,
2079
- videoStyle,
2080
- width,
2081
- setVideoElement,
2082
- setVideoPlaying,
2083
- options,
2084
- corp,
2085
- isMuted,
2086
- playbackRate,
2087
- youtubeConfig,
2088
- startTime,
2089
- endTime,
2090
- backgroundKey,
2091
- motionConfig,
2092
- baseStyle,
2093
- leftGradient,
2094
- rightGradient,
2095
- noiseOpacity,
2096
- noiseBlendMode,
2097
- noiseInlineStyle,
2098
- overlayTransitionStyle,
2099
- resolvedWidth,
2100
- classNames,
2101
- hasCustomWidth,
2102
- gradientSettings,
2103
- maskImage,
2104
- framePosition,
2105
- videoClasses,
2106
- sharedVideoStyle,
2107
- exitDurationFactor,
2108
- exitTransition,
2109
- theme
1938
+ var AUDIO_SYNC_EVENTS = [
1939
+ "play",
1940
+ "playing",
1941
+ "pause",
1942
+ "waiting",
1943
+ "volumechange",
1944
+ "ratechange"
1945
+ ];
1946
+ function setElementMuted(video, muted) {
1947
+ video.muted = muted;
1948
+ if (!muted && video.volume === 0) video.volume = 0.8;
1949
+ }
1950
+ function unlockAudioOnGesture(unlock) {
1951
+ const handler = () => {
1952
+ unlock();
1953
+ window.removeEventListener("pointerdown", handler);
1954
+ window.removeEventListener("keydown", handler);
2110
1955
  };
1956
+ window.addEventListener("pointerdown", handler, { once: true });
1957
+ window.addEventListener("keydown", handler, { once: true });
2111
1958
  }
2112
- function useNativeVideoModel({
2113
- corp,
2114
- isLoop,
2115
- isMuted,
2116
- isPlaying,
2117
- playbackRate,
1959
+ function useYouTubeBackgroundPlayerModel({
1960
+ codec = "auto",
1961
+ corp = 0,
1962
+ endTime = 0,
1963
+ forceIframe = false,
1964
+ isLoop = false,
1965
+ isMuted = true,
1966
+ isPlaying = true,
1967
+ playbackRate = 1,
1968
+ posterUrl = null,
1969
+ quality = "1080p",
2118
1970
  setVideoElement,
2119
1971
  setVideoPlaying,
2120
- shouldAutoPlay,
2121
- src,
2122
- style,
2123
- className
1972
+ shouldAutoPlay = true,
1973
+ showPoster = false,
1974
+ showSpinner = true,
1975
+ startTime = 0,
1976
+ videoClasses: _videoClasses,
1977
+ videoId,
1978
+ videoStyle: _videoStyle
2124
1979
  }) {
2125
- const videoRef = useRef(null);
2126
- const handleEnded = useCallback(() => {
2127
- const video = videoRef.current;
2128
- if (!video) return;
2129
- if (video.loop) {
2130
- video.currentTime = 0;
2131
- video.play().catch((error) => report("Background loop play", error, "warn"));
2132
- return;
2133
- }
2134
- video.pause();
2135
- setVideoPlaying(false);
2136
- }, [setVideoPlaying]);
2137
- const handleTimeUpdate = useCallback(() => {
2138
- const video = videoRef.current;
2139
- if (video?.duration && corp > 0 && video.currentTime >= video.duration - corp) {
2140
- handleEnded();
2141
- }
2142
- }, [corp, handleEnded]);
2143
- const handleLoadedData = () => {
2144
- const video = videoRef.current;
2145
- if (!video) return;
2146
- video.playbackRate = playbackRate;
2147
- if (!shouldAutoPlay) return;
2148
- if (isMuted) video.muted = true;
2149
- video.play().then(() => setVideoPlaying(true)).catch((error) => {
2150
- report("Background autoplay", error, "warn");
2151
- setVideoPlaying(false);
2152
- });
2153
- };
2154
- useEffect(() => {
2155
- const video = videoRef.current;
2156
- setVideoElement(video);
2157
- return () => {
2158
- try {
2159
- video?.pause();
2160
- } catch {
2161
- }
2162
- };
2163
- }, [src, setVideoElement]);
2164
- useEffect(() => () => setVideoElement(null), [setVideoElement]);
2165
- useEffect(() => {
2166
- applyVideoPlaybackState({
2167
- isPlaying,
2168
- playbackRate,
2169
- setVideoPlaying,
2170
- videoElement: videoRef.current
2171
- });
2172
- }, [isPlaying, playbackRate, setVideoPlaying]);
2173
- return { videoRef, handleEnded, handleTimeUpdate, handleLoadedData };
2174
- }
2175
- var AUDIO_SYNC_EVENTS = [
2176
- "play",
2177
- "playing",
2178
- "pause",
2179
- "waiting",
2180
- "volumechange",
2181
- "ratechange"
2182
- ];
2183
- function setElementMuted(video, muted) {
2184
- video.muted = muted;
2185
- if (!muted && video.volume === 0) video.volume = 0.8;
2186
- }
2187
- function unlockAudioOnGesture(unlock) {
2188
- const handler = () => {
2189
- unlock();
2190
- window.removeEventListener("pointerdown", handler);
2191
- window.removeEventListener("keydown", handler);
2192
- };
2193
- window.addEventListener("pointerdown", handler, { once: true });
2194
- window.addEventListener("keydown", handler, { once: true });
2195
- }
2196
- function useYouTubeBackgroundPlayerModel({
2197
- codec = "auto",
2198
- corp = 0,
2199
- endTime = 0,
2200
- forceIframe = false,
2201
- isLoop = false,
2202
- isMuted = true,
2203
- isPlaying = true,
2204
- playbackRate = 1,
2205
- posterUrl = null,
2206
- quality = "1080p",
2207
- setVideoElement,
2208
- setVideoPlaying,
2209
- shouldAutoPlay = true,
2210
- showPoster = false,
2211
- showSpinner = true,
2212
- startTime = 0,
2213
- videoClasses,
2214
- videoId,
2215
- videoStyle
2216
- }) {
2217
- const [useIframeFallback, setUseIframeFallback] = useState(
2218
- Boolean(forceIframe)
2219
- );
2220
- const [isFrameReady, setIsFrameReady] = useState(false);
2221
- const [isBuffering, setIsBuffering] = useState(true);
1980
+ const [useIframeFallback, setUseIframeFallback] = useState(
1981
+ Boolean(forceIframe)
1982
+ );
1983
+ const [isFrameReady, setIsFrameReady] = useState(false);
1984
+ const [isBuffering, setIsBuffering] = useState(true);
2222
1985
  const videoRef = useRef(null);
2223
1986
  const audioRef = useRef(null);
2224
1987
  const iframeHostRef = useRef(null);
@@ -2439,138 +2202,341 @@ function useYouTubeBackgroundPlayerModel({
2439
2202
  };
2440
2203
  const handleError = () => {
2441
2204
  const video = videoRef.current;
2442
- if (video && hasLoadedVideoRef.current) {
2443
- const resumeTime = video.currentTime || 0;
2444
- scheduleRetry(() => {
2445
- video.load();
2446
- video.currentTime = resumeTime;
2447
- if (live.current.isPlaying) video.play().catch(() => {
2448
- });
2449
- }, 150);
2205
+ if (video && hasLoadedVideoRef.current) {
2206
+ const resumeTime = video.currentTime || 0;
2207
+ scheduleRetry(() => {
2208
+ video.load();
2209
+ video.currentTime = resumeTime;
2210
+ if (live.current.isPlaying) video.play().catch(() => {
2211
+ });
2212
+ }, 150);
2213
+ return;
2214
+ }
2215
+ errorRetryCountRef.current += 1;
2216
+ if (video && errorRetryCountRef.current <= 1) {
2217
+ scheduleRetry(() => video.load(), 200);
2218
+ return;
2219
+ }
2220
+ setUseIframeFallback(true);
2221
+ };
2222
+ const handleAudioError = useCallback(() => {
2223
+ const audio = audioRef.current;
2224
+ if (!audio) return;
2225
+ audioErrorRetryCountRef.current += 1;
2226
+ if (audioErrorRetryCountRef.current <= 1) {
2227
+ scheduleRetry(() => {
2228
+ audio.load();
2229
+ if (videoRef.current) {
2230
+ audio.currentTime = videoRef.current.currentTime || 0;
2231
+ }
2232
+ }, 200);
2233
+ return;
2234
+ }
2235
+ if (!live.current.isMuted) {
2236
+ setUseIframeFallback(true);
2237
+ }
2238
+ }, []);
2239
+ useEffect(() => {
2240
+ if (useIframeFallback) return void 0;
2241
+ const video = videoRef.current;
2242
+ const audio = audioRef.current;
2243
+ const retryTimerIds = retryTimerIdsRef.current;
2244
+ if (!video) {
2245
+ setVideoElement(null);
2246
+ return void 0;
2247
+ }
2248
+ setVideoElement(video);
2249
+ const onSync = () => syncCompanionAudio(false);
2250
+ const onSeeked = () => syncCompanionAudio(true);
2251
+ for (const event of AUDIO_SYNC_EVENTS) {
2252
+ video.addEventListener(event, onSync);
2253
+ }
2254
+ video.addEventListener("seeked", onSeeked);
2255
+ const syncTimer = window.setInterval(onSync, 1e3);
2256
+ return () => {
2257
+ window.clearInterval(syncTimer);
2258
+ retryTimerIds.forEach((timerId) => window.clearTimeout(timerId));
2259
+ retryTimerIds.clear();
2260
+ for (const event of AUDIO_SYNC_EVENTS) {
2261
+ video.removeEventListener(event, onSync);
2262
+ }
2263
+ video.removeEventListener("seeked", onSeeked);
2264
+ try {
2265
+ video.pause();
2266
+ audio?.pause();
2267
+ } catch {
2268
+ }
2269
+ };
2270
+ }, [setVideoElement, syncCompanionAudio, useIframeFallback, videoStreamUrl]);
2271
+ useEffect(() => {
2272
+ const video = videoRef.current;
2273
+ if (useIframeFallback || !video) return;
2274
+ applyVideoPlaybackState({
2275
+ isPlaying,
2276
+ playbackRate,
2277
+ setVideoPlaying,
2278
+ videoElement: video
2279
+ });
2280
+ syncCompanionAudio();
2281
+ }, [
2282
+ isPlaying,
2283
+ playbackRate,
2284
+ setVideoPlaying,
2285
+ syncCompanionAudio,
2286
+ useIframeFallback
2287
+ ]);
2288
+ useEffect(() => {
2289
+ const video = videoRef.current;
2290
+ if (useIframeFallback || !video) return;
2291
+ if (video.muted !== isMuted) setElementMuted(video, isMuted);
2292
+ syncCompanionAudio(true);
2293
+ }, [isMuted, syncCompanionAudio, useIframeFallback]);
2294
+ useYouTubeIframePlayer({
2295
+ enabled: useIframeFallback,
2296
+ hostRef: iframeHostRef,
2297
+ isLoop,
2298
+ isMuted,
2299
+ isPlaying,
2300
+ live,
2301
+ playbackRate,
2302
+ setIsBuffering,
2303
+ setIsFrameReady,
2304
+ setVideoElement,
2305
+ setVideoPlaying,
2306
+ shouldAutoPlay,
2307
+ startTime,
2308
+ videoId
2309
+ });
2310
+ const isCovered = !isFrameReady || useIframeFallback && !isPlaying;
2311
+ const showSpinnerOverlay = showSpinner && (!isFrameReady || isBuffering);
2312
+ return {
2313
+ useIframeFallback,
2314
+ isFrameReady,
2315
+ setIsBuffering,
2316
+ videoRef,
2317
+ audioRef,
2318
+ iframeHostRef,
2319
+ videoStreamUrl,
2320
+ audioStreamUrl,
2321
+ resolvedPoster,
2322
+ syncCompanionAudio,
2323
+ handleEnded,
2324
+ handleTimeUpdate,
2325
+ handlePlay,
2326
+ handlePlaying,
2327
+ handlePause,
2328
+ handleSeeked,
2329
+ handleCanPlay,
2330
+ handleLoadedMetadata,
2331
+ handleLoadedData,
2332
+ handleError,
2333
+ handleAudioError,
2334
+ isCovered,
2335
+ showSpinnerOverlay
2336
+ };
2337
+ }
2338
+ var YouTubeBackgroundPlayer = memo(function YouTubeBackgroundPlayer2({
2339
+ codec = "auto",
2340
+ corp = 0,
2341
+ endTime = 0,
2342
+ forceIframe = false,
2343
+ isLoop = false,
2344
+ isMuted = true,
2345
+ isPlaying = true,
2346
+ playbackRate = 1,
2347
+ posterUrl = null,
2348
+ quality = "1080p",
2349
+ setVideoElement,
2350
+ setVideoPlaying,
2351
+ shouldAutoPlay = true,
2352
+ showPoster = false,
2353
+ showSpinner = true,
2354
+ startTime = 0,
2355
+ theme,
2356
+ videoClasses,
2357
+ videoId,
2358
+ videoStyle
2359
+ }) {
2360
+ const {
2361
+ useIframeFallback,
2362
+ isFrameReady,
2363
+ setIsBuffering: _setIsBuffering,
2364
+ videoRef,
2365
+ audioRef,
2366
+ iframeHostRef,
2367
+ videoStreamUrl,
2368
+ audioStreamUrl,
2369
+ resolvedPoster,
2370
+ syncCompanionAudio: _syncCompanionAudio,
2371
+ handleEnded,
2372
+ handleTimeUpdate,
2373
+ handlePlay,
2374
+ handlePlaying,
2375
+ handlePause,
2376
+ handleSeeked,
2377
+ handleCanPlay,
2378
+ handleLoadedMetadata,
2379
+ handleLoadedData,
2380
+ handleError,
2381
+ handleAudioError,
2382
+ isCovered,
2383
+ showSpinnerOverlay
2384
+ } = useYouTubeBackgroundPlayerModel({
2385
+ codec,
2386
+ corp,
2387
+ endTime,
2388
+ forceIframe,
2389
+ isLoop,
2390
+ isMuted,
2391
+ isPlaying,
2392
+ playbackRate,
2393
+ posterUrl,
2394
+ quality,
2395
+ setVideoElement,
2396
+ setVideoPlaying,
2397
+ shouldAutoPlay,
2398
+ showPoster,
2399
+ showSpinner,
2400
+ startTime,
2401
+ videoClasses,
2402
+ videoId,
2403
+ videoStyle
2404
+ });
2405
+ return /* @__PURE__ */ jsxs("div", { className: theme.slots.youtube, children: [
2406
+ /* @__PURE__ */ jsx("div", { "data-visible": isCovered, className: theme.slots.youtubeCover }),
2407
+ /* @__PURE__ */ jsx(
2408
+ "div",
2409
+ {
2410
+ "data-visible": showSpinnerOverlay,
2411
+ className: theme.slots.youtubeSpinner,
2412
+ children: showSpinner ? /* @__PURE__ */ jsx(Spinner, { size: 30, className: theme.slots.youtubeSpinnerIcon }) : null
2413
+ }
2414
+ ),
2415
+ resolvedPoster ? /* @__PURE__ */ jsx(
2416
+ "div",
2417
+ {
2418
+ "data-visible": isCovered,
2419
+ className: theme.slots.youtubePoster,
2420
+ style: {
2421
+ backgroundImage: `url(${resolvedPoster})`,
2422
+ ...videoStyle
2423
+ }
2424
+ }
2425
+ ) : null,
2426
+ useIframeFallback && !isPlaying ? /* @__PURE__ */ jsx("div", { className: theme.slots.youtubeBlackout }) : null,
2427
+ useIframeFallback ? /* @__PURE__ */ jsx(
2428
+ "div",
2429
+ {
2430
+ "data-visible": isFrameReady,
2431
+ className: theme.slots.youtubeFrame,
2432
+ style: videoStyle,
2433
+ children: /* @__PURE__ */ jsx("div", { ref: iframeHostRef, className: theme.slots.youtubeHost })
2434
+ }
2435
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2436
+ /* @__PURE__ */ jsx(
2437
+ "video",
2438
+ {
2439
+ ref: videoRef,
2440
+ src: videoStreamUrl,
2441
+ "data-visible": isFrameReady,
2442
+ className: cn(videoClasses, theme.slots.youtubeVideo),
2443
+ preload: "auto",
2444
+ muted: isMuted,
2445
+ loop: isLoop,
2446
+ playsInline: true,
2447
+ style: videoStyle,
2448
+ onTimeUpdate: handleTimeUpdate,
2449
+ onEnded: handleEnded,
2450
+ onPlay: handlePlay,
2451
+ onWaiting: () => {
2452
+ _setIsBuffering(true);
2453
+ _syncCompanionAudio(false);
2454
+ },
2455
+ onPlaying: handlePlaying,
2456
+ onPause: handlePause,
2457
+ onSeeking: () => _setIsBuffering(true),
2458
+ onSeeked: handleSeeked,
2459
+ onCanPlay: handleCanPlay,
2460
+ onLoadedMetadata: handleLoadedMetadata,
2461
+ onLoadedData: handleLoadedData,
2462
+ onError: handleError
2463
+ }
2464
+ ),
2465
+ /* @__PURE__ */ jsx(
2466
+ "audio",
2467
+ {
2468
+ ref: audioRef,
2469
+ src: audioStreamUrl,
2470
+ preload: "auto",
2471
+ onCanPlay: () => _syncCompanionAudio(true),
2472
+ onError: handleAudioError
2473
+ }
2474
+ )
2475
+ ] })
2476
+ ] });
2477
+ });
2478
+ function useNativeVideoModel({
2479
+ corp,
2480
+ isLoop,
2481
+ isMuted,
2482
+ isPlaying,
2483
+ playbackRate,
2484
+ setVideoElement,
2485
+ setVideoPlaying,
2486
+ shouldAutoPlay,
2487
+ src,
2488
+ style: _style,
2489
+ className: _className
2490
+ }) {
2491
+ const videoRef = useRef(null);
2492
+ const handleEnded = useCallback(() => {
2493
+ const video = videoRef.current;
2494
+ if (!video) return;
2495
+ if (video.loop) {
2496
+ video.currentTime = 0;
2497
+ video.play().catch((error) => report("Background loop play", error, "warn"));
2450
2498
  return;
2451
2499
  }
2452
- errorRetryCountRef.current += 1;
2453
- if (video && errorRetryCountRef.current <= 1) {
2454
- scheduleRetry(() => video.load(), 200);
2455
- return;
2500
+ video.pause();
2501
+ setVideoPlaying(false);
2502
+ }, [setVideoPlaying]);
2503
+ const handleTimeUpdate = useCallback(() => {
2504
+ const video = videoRef.current;
2505
+ if (video?.duration && corp > 0 && video.currentTime >= video.duration - corp) {
2506
+ handleEnded();
2456
2507
  }
2457
- setUseIframeFallback(true);
2508
+ }, [corp, handleEnded]);
2509
+ const handleLoadedData = () => {
2510
+ const video = videoRef.current;
2511
+ if (!video) return;
2512
+ video.playbackRate = playbackRate;
2513
+ if (!shouldAutoPlay) return;
2514
+ if (isMuted) video.muted = true;
2515
+ video.play().then(() => setVideoPlaying(true)).catch((error) => {
2516
+ report("Background autoplay", error, "warn");
2517
+ setVideoPlaying(false);
2518
+ });
2458
2519
  };
2459
- const handleAudioError = useCallback(() => {
2460
- const audio = audioRef.current;
2461
- if (!audio) return;
2462
- audioErrorRetryCountRef.current += 1;
2463
- if (audioErrorRetryCountRef.current <= 1) {
2464
- scheduleRetry(() => {
2465
- audio.load();
2466
- if (videoRef.current) {
2467
- audio.currentTime = videoRef.current.currentTime || 0;
2468
- }
2469
- }, 200);
2470
- return;
2471
- }
2472
- if (!live.current.isMuted) {
2473
- setUseIframeFallback(true);
2474
- }
2475
- }, []);
2476
2520
  useEffect(() => {
2477
- if (useIframeFallback) return void 0;
2478
2521
  const video = videoRef.current;
2479
- const audio = audioRef.current;
2480
- const retryTimerIds = retryTimerIdsRef.current;
2481
- if (!video) {
2482
- setVideoElement(null);
2483
- return void 0;
2484
- }
2485
2522
  setVideoElement(video);
2486
- const onSync = () => syncCompanionAudio(false);
2487
- const onSeeked = () => syncCompanionAudio(true);
2488
- for (const event of AUDIO_SYNC_EVENTS) {
2489
- video.addEventListener(event, onSync);
2490
- }
2491
- video.addEventListener("seeked", onSeeked);
2492
- const syncTimer = window.setInterval(onSync, 1e3);
2493
2523
  return () => {
2494
- window.clearInterval(syncTimer);
2495
- retryTimerIds.forEach((timerId) => window.clearTimeout(timerId));
2496
- retryTimerIds.clear();
2497
- for (const event of AUDIO_SYNC_EVENTS) {
2498
- video.removeEventListener(event, onSync);
2499
- }
2500
- video.removeEventListener("seeked", onSeeked);
2501
2524
  try {
2502
- video.pause();
2503
- audio?.pause();
2525
+ video?.pause();
2504
2526
  } catch {
2505
2527
  }
2506
2528
  };
2507
- }, [setVideoElement, syncCompanionAudio, useIframeFallback, videoStreamUrl]);
2529
+ }, [src, setVideoElement]);
2530
+ useEffect(() => () => setVideoElement(null), [setVideoElement]);
2508
2531
  useEffect(() => {
2509
- const video = videoRef.current;
2510
- if (useIframeFallback || !video) return;
2511
2532
  applyVideoPlaybackState({
2512
2533
  isPlaying,
2513
2534
  playbackRate,
2514
2535
  setVideoPlaying,
2515
- videoElement: video
2536
+ videoElement: videoRef.current
2516
2537
  });
2517
- syncCompanionAudio();
2518
- }, [
2519
- isPlaying,
2520
- playbackRate,
2521
- setVideoPlaying,
2522
- syncCompanionAudio,
2523
- useIframeFallback
2524
- ]);
2525
- useEffect(() => {
2526
- const video = videoRef.current;
2527
- if (useIframeFallback || !video) return;
2528
- if (video.muted !== isMuted) setElementMuted(video, isMuted);
2529
- syncCompanionAudio(true);
2530
- }, [isMuted, syncCompanionAudio, useIframeFallback]);
2531
- useYouTubeIframePlayer({
2532
- enabled: useIframeFallback,
2533
- hostRef: iframeHostRef,
2534
- isLoop,
2535
- isMuted,
2536
- isPlaying,
2537
- live,
2538
- playbackRate,
2539
- setIsBuffering,
2540
- setIsFrameReady,
2541
- setVideoElement,
2542
- setVideoPlaying,
2543
- shouldAutoPlay,
2544
- startTime,
2545
- videoId
2546
- });
2547
- const isCovered = !isFrameReady || useIframeFallback && !isPlaying;
2548
- const showSpinnerOverlay = showSpinner && (!isFrameReady || isBuffering);
2549
- return {
2550
- useIframeFallback,
2551
- isFrameReady,
2552
- setIsBuffering,
2553
- videoRef,
2554
- audioRef,
2555
- iframeHostRef,
2556
- videoStreamUrl,
2557
- audioStreamUrl,
2558
- resolvedPoster,
2559
- syncCompanionAudio,
2560
- handleEnded,
2561
- handleTimeUpdate,
2562
- handlePlay,
2563
- handlePlaying,
2564
- handlePause,
2565
- handleSeeked,
2566
- handleCanPlay,
2567
- handleLoadedMetadata,
2568
- handleLoadedData,
2569
- handleError,
2570
- handleAudioError,
2571
- isCovered,
2572
- showSpinnerOverlay
2573
- };
2538
+ }, [isPlaying, playbackRate, setVideoPlaying]);
2539
+ return { videoRef, handleEnded, handleTimeUpdate, handleLoadedData };
2574
2540
  }
2575
2541
  function NativeVideo({
2576
2542
  corp,
@@ -2656,190 +2622,205 @@ var EdgeGradient = memo(function EdgeGradient2({
2656
2622
  }
2657
2623
  }
2658
2624
  );
2659
- });
2660
- var NoiseOverlay = memo(function NoiseOverlay2({
2661
- opacity,
2662
- blendMode,
2663
- inlineStyle,
2664
- maskImage,
2665
- isFixed,
2666
- theme
2667
- }) {
2668
- return /* @__PURE__ */ jsx(
2669
- "div",
2670
- {
2671
- "data-position": isFixed ? "fixed" : "absolute",
2672
- className: theme.slots.noise,
2673
- style: {
2674
- ...theme.styles.noise,
2675
- ...typeof opacity === "number" ? { opacity } : {},
2676
- ...typeof blendMode === "string" && blendMode.trim() ? { mixBlendMode: blendMode } : {},
2677
- ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
2678
- ...inlineStyle
2679
- }
2680
- }
2625
+ });
2626
+ var NoiseOverlay = memo(function NoiseOverlay2({
2627
+ opacity,
2628
+ blendMode,
2629
+ inlineStyle,
2630
+ maskImage,
2631
+ isFixed,
2632
+ theme
2633
+ }) {
2634
+ return /* @__PURE__ */ jsx(
2635
+ "div",
2636
+ {
2637
+ "data-position": isFixed ? "fixed" : "absolute",
2638
+ className: theme.slots.noise,
2639
+ style: {
2640
+ ...theme.styles.noise,
2641
+ ...typeof opacity === "number" ? { opacity } : {},
2642
+ ...typeof blendMode === "string" && blendMode.trim() ? { mixBlendMode: blendMode } : {},
2643
+ ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
2644
+ ...inlineStyle
2645
+ }
2646
+ }
2647
+ );
2648
+ });
2649
+ var SolidOverlay = memo(function SolidOverlay2({
2650
+ opacity = 0,
2651
+ color,
2652
+ transitionStyle,
2653
+ maskImage,
2654
+ theme
2655
+ }) {
2656
+ return /* @__PURE__ */ jsx(
2657
+ "div",
2658
+ {
2659
+ className: theme.slots.solid,
2660
+ style: {
2661
+ opacity,
2662
+ backgroundColor: color,
2663
+ ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
2664
+ ...transitionStyle
2665
+ }
2666
+ }
2667
+ );
2668
+ });
2669
+ function useBackgroundOverlayModel() {
2670
+ const {
2671
+ animation,
2672
+ className,
2673
+ fadeEdges,
2674
+ fit,
2675
+ hasBackground,
2676
+ image,
2677
+ imageStyle,
2678
+ isPlaying,
2679
+ isVideo,
2680
+ isYouTube,
2681
+ leftGradient: configuredLeftGradient,
2682
+ noiseStyle,
2683
+ overlay,
2684
+ overlayColor,
2685
+ overlayOpacity,
2686
+ position,
2687
+ rightGradient: configuredRightGradient,
2688
+ video,
2689
+ videoClassName,
2690
+ videoOptions,
2691
+ videoStyle,
2692
+ width
2693
+ } = useBackgroundState();
2694
+ const { setVideoElement, setVideoPlaying } = useBackgroundActions();
2695
+ const options = resolveVideoOptions(videoOptions);
2696
+ const { corp, isMuted, playbackRate } = options;
2697
+ const youtubeConfig = useMemo(
2698
+ () => isYouTube ? parseYouTubeUrlConfig(video) : null,
2699
+ [isYouTube, video]
2700
+ );
2701
+ const startTime = videoOptions?.startTime ?? youtubeConfig?.startTime ?? 0;
2702
+ const endTime = videoOptions?.endTime ?? youtubeConfig?.endTime ?? 0;
2703
+ const backgroundKey = isVideo ? youtubeConfig ? `youtube:${youtubeConfig.videoId}` : video : image;
2704
+ const motionConfig = useMemo(
2705
+ () => getBackgroundMotionConfig(animation),
2706
+ [animation]
2707
+ );
2708
+ const {
2709
+ baseStyle,
2710
+ leftGradient: styleLeft,
2711
+ rightGradient: styleRight
2712
+ } = useMemo(
2713
+ () => getVisualStyle((isVideo ? videoStyle : imageStyle) || {}),
2714
+ [imageStyle, isVideo, videoStyle]
2715
+ );
2716
+ const leftGradient = configuredLeftGradient ?? styleLeft;
2717
+ const rightGradient = configuredRightGradient ?? styleRight;
2718
+ const {
2719
+ opacity: noiseOpacity,
2720
+ mixBlendMode: noiseBlendMode,
2721
+ ...noiseInlineStyle
2722
+ } = noiseStyle || {};
2723
+ const overlayTransitionStyle = useMemo(
2724
+ () => ({
2725
+ transitionDelay: toCssDelay(motionConfig.transition.delay),
2726
+ transitionDuration: toCssDuration(motionConfig.transition.duration),
2727
+ transitionProperty: "opacity",
2728
+ transitionTimingFunction: toCssEasing(motionConfig.transition.ease)
2729
+ }),
2730
+ [motionConfig.transition]
2731
+ );
2732
+ const rawWidth = width ?? videoOptions?.width ?? videoStyle?.width;
2733
+ const resolvedWidth = rawWidth === void 0 || rawWidth === null || rawWidth === "" ? void 0 : typeof rawWidth === "number" ? `${rawWidth}px` : String(rawWidth);
2734
+ const rawFit = fit ?? videoOptions?.fit ?? videoOptions?.objectFit;
2735
+ const theme = useTheme(backgroundTheme);
2736
+ const fitStyle = useMemo(
2737
+ () => rawFit && OBJECT_FITS.includes(rawFit) ? { objectFit: rawFit } : {},
2738
+ [rawFit]
2739
+ );
2740
+ const classNames = resolveVideoClassNames(
2741
+ videoClassName,
2742
+ className,
2743
+ videoOptions?.videoClassName,
2744
+ videoOptions?.className,
2745
+ videoStyle?.className
2681
2746
  );
2682
- });
2683
- var SolidOverlay = memo(function SolidOverlay2({
2684
- opacity = 0,
2685
- color,
2686
- transitionStyle,
2687
- maskImage,
2688
- theme
2689
- }) {
2690
- return /* @__PURE__ */ jsx(
2691
- "div",
2692
- {
2693
- className: theme.slots.solid,
2694
- style: {
2695
- opacity,
2696
- backgroundColor: color,
2697
- ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
2698
- ...transitionStyle
2699
- }
2700
- }
2747
+ const hasCustomWidth = Boolean(resolvedWidth || classNames.width);
2748
+ const gradientSettings = useMemo(
2749
+ () => resolveGradientSettings({
2750
+ fadeEdges,
2751
+ hasWidth: hasCustomWidth,
2752
+ leftGradient,
2753
+ rightGradient
2754
+ }),
2755
+ [fadeEdges, hasCustomWidth, leftGradient, rightGradient]
2701
2756
  );
2702
- });
2703
- var YouTubeBackgroundPlayer = memo(function YouTubeBackgroundPlayer2({
2704
- codec = "auto",
2705
- corp = 0,
2706
- endTime = 0,
2707
- forceIframe = false,
2708
- isLoop = false,
2709
- isMuted = true,
2710
- isPlaying = true,
2711
- playbackRate = 1,
2712
- posterUrl = null,
2713
- quality = "1080p",
2714
- setVideoElement,
2715
- setVideoPlaying,
2716
- shouldAutoPlay = true,
2717
- showPoster = false,
2718
- showSpinner = true,
2719
- startTime = 0,
2720
- theme,
2721
- videoClasses,
2722
- videoId,
2723
- videoStyle
2724
- }) {
2725
- const {
2726
- useIframeFallback,
2727
- isFrameReady,
2728
- setIsBuffering,
2729
- videoRef,
2730
- audioRef,
2731
- iframeHostRef,
2732
- videoStreamUrl,
2733
- audioStreamUrl,
2734
- resolvedPoster,
2735
- syncCompanionAudio,
2736
- handleEnded,
2737
- handleTimeUpdate,
2738
- handlePlay,
2739
- handlePlaying,
2740
- handlePause,
2741
- handleSeeked,
2742
- handleCanPlay,
2743
- handleLoadedMetadata,
2744
- handleLoadedData,
2745
- handleError,
2746
- handleAudioError,
2747
- isCovered,
2748
- showSpinnerOverlay
2749
- } = useYouTubeBackgroundPlayerModel({
2750
- codec,
2751
- corp,
2752
- endTime,
2753
- forceIframe,
2754
- isLoop,
2755
- isMuted,
2757
+ const maskImage = useMemo(
2758
+ () => gradientSettings.enabled ? getEdgeFadeMask({
2759
+ color: overlayColor || DEFAULT_COLOR,
2760
+ leftPercent: gradientSettings.leftPercent,
2761
+ rightPercent: gradientSettings.rightPercent
2762
+ }) : void 0,
2763
+ [gradientSettings, overlayColor]
2764
+ );
2765
+ const framePosition = position === "left" || position === "right" ? position : "center";
2766
+ const videoClasses = cn(theme.slots.video, classNames.other);
2767
+ const objectPosition2 = baseStyle.objectPosition || position || void 0;
2768
+ const sharedVideoStyle = useMemo(
2769
+ () => ({
2770
+ ...classNames.objectStyle,
2771
+ ...fitStyle,
2772
+ ...objectPosition2 ? { objectPosition: objectPosition2 } : {},
2773
+ ...maskImage ? { WebkitMaskImage: maskImage, maskImage } : {},
2774
+ ...baseStyle
2775
+ }),
2776
+ [baseStyle, classNames.objectStyle, fitStyle, maskImage, objectPosition2]
2777
+ );
2778
+ const exitDurationFactor = Number.isFinite(motionConfig.exitDurationFactor) ? Math.max(0, motionConfig.exitDurationFactor) : 0.6;
2779
+ const exitTransition = motionConfig.exit.transition;
2780
+ return {
2781
+ className,
2782
+ hasBackground,
2783
+ image,
2756
2784
  isPlaying,
2757
- playbackRate,
2758
- posterUrl,
2759
- quality,
2785
+ isVideo,
2786
+ overlay,
2787
+ overlayColor,
2788
+ overlayOpacity,
2789
+ position,
2790
+ video,
2791
+ videoStyle,
2792
+ width,
2760
2793
  setVideoElement,
2761
2794
  setVideoPlaying,
2762
- shouldAutoPlay,
2763
- showPoster,
2764
- showSpinner,
2795
+ options,
2796
+ corp,
2797
+ isMuted,
2798
+ playbackRate,
2799
+ youtubeConfig,
2765
2800
  startTime,
2801
+ endTime,
2802
+ backgroundKey,
2803
+ motionConfig,
2804
+ baseStyle,
2805
+ leftGradient,
2806
+ rightGradient,
2807
+ noiseOpacity,
2808
+ noiseBlendMode,
2809
+ noiseInlineStyle,
2810
+ overlayTransitionStyle,
2811
+ resolvedWidth,
2812
+ classNames,
2813
+ hasCustomWidth,
2814
+ gradientSettings,
2815
+ maskImage,
2816
+ framePosition,
2766
2817
  videoClasses,
2767
- videoId,
2768
- videoStyle
2769
- });
2770
- return /* @__PURE__ */ jsxs("div", { className: theme.slots.youtube, children: [
2771
- /* @__PURE__ */ jsx("div", { "data-visible": isCovered, className: theme.slots.youtubeCover }),
2772
- /* @__PURE__ */ jsx(
2773
- "div",
2774
- {
2775
- "data-visible": showSpinnerOverlay,
2776
- className: theme.slots.youtubeSpinner,
2777
- children: showSpinner ? /* @__PURE__ */ jsx(Spinner, { size: 30, className: theme.slots.youtubeSpinnerIcon }) : null
2778
- }
2779
- ),
2780
- resolvedPoster ? /* @__PURE__ */ jsx(
2781
- "div",
2782
- {
2783
- "data-visible": isCovered,
2784
- className: theme.slots.youtubePoster,
2785
- style: {
2786
- backgroundImage: `url(${resolvedPoster})`,
2787
- ...videoStyle
2788
- }
2789
- }
2790
- ) : null,
2791
- useIframeFallback && !isPlaying ? /* @__PURE__ */ jsx("div", { className: theme.slots.youtubeBlackout }) : null,
2792
- useIframeFallback ? /* @__PURE__ */ jsx(
2793
- "div",
2794
- {
2795
- "data-visible": isFrameReady,
2796
- className: theme.slots.youtubeFrame,
2797
- style: videoStyle,
2798
- children: /* @__PURE__ */ jsx("div", { ref: iframeHostRef, className: theme.slots.youtubeHost })
2799
- }
2800
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2801
- /* @__PURE__ */ jsx(
2802
- "video",
2803
- {
2804
- ref: videoRef,
2805
- src: videoStreamUrl,
2806
- "data-visible": isFrameReady,
2807
- className: cn(videoClasses, theme.slots.youtubeVideo),
2808
- preload: "auto",
2809
- muted: isMuted,
2810
- loop: isLoop,
2811
- playsInline: true,
2812
- style: videoStyle,
2813
- onTimeUpdate: handleTimeUpdate,
2814
- onEnded: handleEnded,
2815
- onPlay: handlePlay,
2816
- onWaiting: () => {
2817
- setIsBuffering(true);
2818
- syncCompanionAudio(false);
2819
- },
2820
- onPlaying: handlePlaying,
2821
- onPause: handlePause,
2822
- onSeeking: () => setIsBuffering(true),
2823
- onSeeked: handleSeeked,
2824
- onCanPlay: handleCanPlay,
2825
- onLoadedMetadata: handleLoadedMetadata,
2826
- onLoadedData: handleLoadedData,
2827
- onError: handleError
2828
- }
2829
- ),
2830
- /* @__PURE__ */ jsx(
2831
- "audio",
2832
- {
2833
- ref: audioRef,
2834
- src: audioStreamUrl,
2835
- preload: "auto",
2836
- onCanPlay: () => syncCompanionAudio(true),
2837
- onError: handleAudioError
2838
- }
2839
- )
2840
- ] })
2841
- ] });
2842
- });
2818
+ sharedVideoStyle,
2819
+ exitDurationFactor,
2820
+ exitTransition,
2821
+ theme
2822
+ };
2823
+ }
2843
2824
  function BackgroundOverlay() {
2844
2825
  const {
2845
2826
  hasBackground,
@@ -3050,6 +3031,9 @@ function BackgroundOverlay() {
3050
3031
  backgroundKey
3051
3032
  ) });
3052
3033
  }
3034
+ function selectPageBackground(background) {
3035
+ return background ? normalizeBackgroundInput(background) : null;
3036
+ }
3053
3037
  function useBackgroundPage(_slice, page) {
3054
3038
  const actions = useBackgroundActions();
3055
3039
  return useMemo(
@@ -3092,6 +3076,6 @@ function defineBackground(definition = {}) {
3092
3076
  });
3093
3077
  }
3094
3078
 
3095
- export { BACKGROUND_MEDIA_ID, BackgroundContext, BackgroundOverlay, BackgroundProvider, DEFAULT_BACKGROUND, DEFAULT_BACKGROUND_COMPUTED, INERT_BACKGROUND_ACTIONS, backgroundModule, backgroundTheme, defineBackground, extractYouTubeVideoId, getYouTubeStreamUrl, getYouTubeThumbnailUrl, isDirectVideoUrl, isYouTubeUrl, parseYouTubeUrlConfig, useBackground, useBackgroundActions, useBackgroundRegistration, useBackgroundState, useOptionalBackgroundActions, useOptionalBackgroundState };
3079
+ export { BACKGROUND_MEDIA_ID, BACKGROUND_REGISTRY_KEY, BG_TOKEN_TO_OBJECT_STYLE, BackgroundContext, BackgroundOverlay, BackgroundProvider, DEFAULT_BACKGROUND, DEFAULT_BACKGROUND_COMPUTED, DEFAULT_COLOR, INERT_BACKGROUND_ACTIONS, OBJECT_FITS, YouTubeBackgroundPlayer, applyVideoPlaybackState, backgroundModule, backgroundTheme, computeBackgroundState, defineBackground, extractYouTubeVideoId, generateBaseGradient, generateEdgeGradient, getEdgeFadeMask, getYouTubeStreamUrl, getYouTubeThumbnailUrl, isDirectVideoUrl, isYouTubeUrl, mergeBackgroundState, normalizeBackgroundInput, parseYouTubeUrlConfig, resolveBackgroundState, resolveVideoClassNames, resolveVideoOptions, selectPageBackground, syncVideoLoopDirect, syncVideoMutedDirect, triggerVideoPlaybackDirect, useBackground, useBackgroundActions, useBackgroundRegistration, useBackgroundState, useOptionalBackgroundActions, useOptionalBackgroundState };
3096
3080
  //# sourceMappingURL=index.js.map
3097
3081
  //# sourceMappingURL=index.js.map