@omerdlw/base-framework 1.0.6 → 2.0.1

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 (234) hide show
  1. package/dist/atoms/index.js +1 -103
  2. package/dist/atoms/index.js.map +1 -1
  3. package/dist/chunk-3BUP64Q6.js +105 -0
  4. package/dist/chunk-3BUP64Q6.js.map +1 -0
  5. package/dist/chunk-4GMQKD6F.js +353 -0
  6. package/dist/chunk-4GMQKD6F.js.map +1 -0
  7. package/dist/chunk-6SG7V77J.js +577 -0
  8. package/dist/chunk-6SG7V77J.js.map +1 -0
  9. package/dist/chunk-6ZJVLUBE.js +26 -0
  10. package/dist/chunk-6ZJVLUBE.js.map +1 -0
  11. package/dist/chunk-7HQMXTNP.js +419 -0
  12. package/dist/chunk-7HQMXTNP.js.map +1 -0
  13. package/dist/chunk-7TAVYJ3A.js +371 -0
  14. package/dist/chunk-7TAVYJ3A.js.map +1 -0
  15. package/dist/chunk-A5RE3F6O.js +9905 -0
  16. package/dist/chunk-A5RE3F6O.js.map +1 -0
  17. package/dist/chunk-AQ4BNXA2.js +349 -0
  18. package/dist/chunk-AQ4BNXA2.js.map +1 -0
  19. package/dist/chunk-CGHZSSFR.js +2166 -0
  20. package/dist/chunk-CGHZSSFR.js.map +1 -0
  21. package/dist/chunk-DGCQWQLZ.js +61 -0
  22. package/dist/chunk-DGCQWQLZ.js.map +1 -0
  23. package/dist/chunk-FIMPHODX.js +67 -0
  24. package/dist/chunk-FIMPHODX.js.map +1 -0
  25. package/dist/chunk-GF7TUX5I.js +1889 -0
  26. package/dist/chunk-GF7TUX5I.js.map +1 -0
  27. package/dist/chunk-JELG4JLT.js +454 -0
  28. package/dist/chunk-JELG4JLT.js.map +1 -0
  29. package/dist/chunk-K676GL7Z.js +51 -0
  30. package/dist/chunk-K676GL7Z.js.map +1 -0
  31. package/dist/chunk-QI3ALLIB.js +38 -0
  32. package/dist/chunk-QI3ALLIB.js.map +1 -0
  33. package/dist/chunk-QXR55VVS.js +1139 -0
  34. package/dist/chunk-QXR55VVS.js.map +1 -0
  35. package/dist/chunk-R2YGFJDJ.js +408 -0
  36. package/dist/chunk-R2YGFJDJ.js.map +1 -0
  37. package/dist/chunk-RFZQWLC5.js +27 -0
  38. package/dist/chunk-RFZQWLC5.js.map +1 -0
  39. package/dist/chunk-SKBITB5X.js +888 -0
  40. package/dist/chunk-SKBITB5X.js.map +1 -0
  41. package/dist/chunk-SYAVGTOX.js +521 -0
  42. package/dist/chunk-SYAVGTOX.js.map +1 -0
  43. package/dist/chunk-TV3WEF5G.js +784 -0
  44. package/dist/chunk-TV3WEF5G.js.map +1 -0
  45. package/dist/chunk-XASQT4CQ.js +280 -0
  46. package/dist/chunk-XASQT4CQ.js.map +1 -0
  47. package/dist/error/index.js +5 -682
  48. package/dist/error/index.js.map +1 -1
  49. package/dist/error/reporter.d.ts.map +1 -1
  50. package/dist/error/theme.d.ts +1 -1
  51. package/dist/error/theme.d.ts.map +1 -1
  52. package/dist/events.js +1 -7
  53. package/dist/events.js.map +1 -1
  54. package/dist/hooks/index.js +1 -358
  55. package/dist/hooks/index.js.map +1 -1
  56. package/dist/hooks/use-global-event.d.ts +1 -1
  57. package/dist/index.js +18 -20029
  58. package/dist/index.js.map +1 -1
  59. package/dist/kernel/index.js +2 -2035
  60. package/dist/kernel/index.js.map +1 -1
  61. package/dist/kernel/types.d.ts +1 -1
  62. package/dist/modules/ambient/analyze.d.ts +46 -0
  63. package/dist/modules/ambient/analyze.d.ts.map +1 -0
  64. package/dist/modules/ambient/constants.d.ts +1 -5
  65. package/dist/modules/ambient/constants.d.ts.map +1 -1
  66. package/dist/modules/ambient/context.d.ts.map +1 -1
  67. package/dist/modules/ambient/dom.d.ts +11 -12
  68. package/dist/modules/ambient/dom.d.ts.map +1 -1
  69. package/dist/modules/ambient/extractor.d.ts +10 -10
  70. package/dist/modules/ambient/extractor.d.ts.map +1 -1
  71. package/dist/modules/ambient/hooks.d.ts +1 -1
  72. package/dist/modules/ambient/hooks.d.ts.map +1 -1
  73. package/dist/modules/ambient/index.d.ts +6 -4
  74. package/dist/modules/ambient/index.d.ts.map +1 -1
  75. package/dist/modules/ambient/index.js +7 -762
  76. package/dist/modules/ambient/index.js.map +1 -1
  77. package/dist/modules/ambient/module.d.ts +1 -1
  78. package/dist/modules/ambient/module.d.ts.map +1 -1
  79. package/dist/modules/ambient/oklab.d.ts +36 -0
  80. package/dist/modules/ambient/oklab.d.ts.map +1 -0
  81. package/dist/modules/ambient/pipeline.d.ts +28 -0
  82. package/dist/modules/ambient/pipeline.d.ts.map +1 -0
  83. package/dist/modules/ambient/quantize.d.ts +22 -0
  84. package/dist/modules/ambient/quantize.d.ts.map +1 -0
  85. package/dist/modules/ambient/server/address.d.ts +8 -0
  86. package/dist/modules/ambient/server/address.d.ts.map +1 -0
  87. package/dist/modules/ambient/server/index.d.ts +53 -0
  88. package/dist/modules/ambient/server/index.d.ts.map +1 -0
  89. package/dist/modules/ambient/server/index.js +221 -0
  90. package/dist/modules/ambient/server/index.js.map +1 -0
  91. package/dist/modules/ambient/settings.d.ts +19 -0
  92. package/dist/modules/ambient/settings.d.ts.map +1 -0
  93. package/dist/modules/ambient/types.d.ts +105 -9
  94. package/dist/modules/ambient/types.d.ts.map +1 -1
  95. package/dist/modules/ambient/worker/index.d.ts +15 -0
  96. package/dist/modules/ambient/worker/index.d.ts.map +1 -0
  97. package/dist/modules/ambient/worker/index.js +114 -0
  98. package/dist/modules/ambient/worker/index.js.map +1 -0
  99. package/dist/modules/background/constants.d.ts +2 -2
  100. package/dist/modules/background/constants.d.ts.map +1 -1
  101. package/dist/modules/background/hooks.d.ts +1 -1
  102. package/dist/modules/background/index.js +6 -3078
  103. package/dist/modules/background/index.js.map +1 -1
  104. package/dist/modules/background/motion.d.ts +9 -7
  105. package/dist/modules/background/motion.d.ts.map +1 -1
  106. package/dist/modules/background/overlay.d.ts +3 -8
  107. package/dist/modules/background/overlay.d.ts.map +1 -1
  108. package/dist/modules/background/types.d.ts +16 -2
  109. package/dist/modules/background/types.d.ts.map +1 -1
  110. package/dist/modules/context-menu/constants.d.ts +2 -2
  111. package/dist/modules/context-menu/constants.d.ts.map +1 -1
  112. package/dist/modules/context-menu/hooks.d.ts +1 -1
  113. package/dist/modules/context-menu/index.js +10 -1896
  114. package/dist/modules/context-menu/index.js.map +1 -1
  115. package/dist/modules/context-menu/motion.d.ts +1 -8
  116. package/dist/modules/context-menu/motion.d.ts.map +1 -1
  117. package/dist/modules/context-menu/overlay.d.ts.map +1 -1
  118. package/dist/modules/context-menu/types.d.ts +16 -2
  119. package/dist/modules/context-menu/types.d.ts.map +1 -1
  120. package/dist/modules/controls/constants.d.ts +1 -1
  121. package/dist/modules/controls/constants.d.ts.map +1 -1
  122. package/dist/modules/controls/entries.d.ts +1 -1
  123. package/dist/modules/controls/hooks.d.ts +1 -1
  124. package/dist/modules/controls/index.js +4 -1110
  125. package/dist/modules/controls/index.js.map +1 -1
  126. package/dist/modules/controls/overlay.d.ts +1 -1
  127. package/dist/modules/controls/types.d.ts +2 -2
  128. package/dist/modules/dock/cards.d.ts +711 -24
  129. package/dist/modules/dock/cards.d.ts.map +1 -1
  130. package/dist/modules/dock/constants.d.ts +2 -2
  131. package/dist/modules/dock/constants.d.ts.map +1 -1
  132. package/dist/modules/dock/helpers.d.ts +2 -2
  133. package/dist/modules/dock/hooks.d.ts +2 -2
  134. package/dist/modules/dock/index.d.ts +1 -1
  135. package/dist/modules/dock/index.d.ts.map +1 -1
  136. package/dist/modules/dock/index.js +9 -12132
  137. package/dist/modules/dock/index.js.map +1 -1
  138. package/dist/modules/dock/layout.d.ts.map +1 -1
  139. package/dist/modules/dock/module.d.ts +1 -1
  140. package/dist/modules/dock/motion.d.ts +44 -912
  141. package/dist/modules/dock/motion.d.ts.map +1 -1
  142. package/dist/modules/dock/overlay.d.ts +1 -1
  143. package/dist/modules/dock/overlay.d.ts.map +1 -1
  144. package/dist/modules/dock/runtime/dock.d.ts +1 -23
  145. package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
  146. package/dist/modules/dock/styles.d.ts +4 -4
  147. package/dist/modules/dock/surface/hooks.d.ts +5 -20
  148. package/dist/modules/dock/surface/hooks.d.ts.map +1 -1
  149. package/dist/modules/dock/surface/machine.d.ts +4 -3
  150. package/dist/modules/dock/surface/machine.d.ts.map +1 -1
  151. package/dist/modules/dock/surface/stack.d.ts.map +1 -1
  152. package/dist/modules/dock/surface/view-model.d.ts.map +1 -1
  153. package/dist/modules/dock/types.d.ts +162 -3
  154. package/dist/modules/dock/types.d.ts.map +1 -1
  155. package/dist/modules/index.js +16 -17883
  156. package/dist/modules/index.js.map +1 -1
  157. package/dist/modules/loading/constants.d.ts +1 -1
  158. package/dist/modules/loading/constants.d.ts.map +1 -1
  159. package/dist/modules/loading/context.d.ts +1 -1
  160. package/dist/modules/loading/hooks.d.ts +1 -1
  161. package/dist/modules/loading/index.js +5 -1153
  162. package/dist/modules/loading/index.js.map +1 -1
  163. package/dist/modules/loading/types.d.ts +2 -2
  164. package/dist/modules/media/context.d.ts +1 -1
  165. package/dist/modules/media/index.js +3 -570
  166. package/dist/modules/media/index.js.map +1 -1
  167. package/dist/modules/media/types.d.ts +2 -2
  168. package/dist/modules/modal/constants.d.ts +2 -2
  169. package/dist/modules/modal/constants.d.ts.map +1 -1
  170. package/dist/modules/modal/context.d.ts +1 -1
  171. package/dist/modules/modal/hooks.d.ts +3 -3
  172. package/dist/modules/modal/index.js +8 -2355
  173. package/dist/modules/modal/index.js.map +1 -1
  174. package/dist/modules/modal/motion.d.ts +3 -8
  175. package/dist/modules/modal/motion.d.ts.map +1 -1
  176. package/dist/modules/modal/overlay.d.ts.map +1 -1
  177. package/dist/modules/modal/types.d.ts +21 -0
  178. package/dist/modules/modal/types.d.ts.map +1 -1
  179. package/dist/modules/notification/constants.d.ts +2 -2
  180. package/dist/modules/notification/constants.d.ts.map +1 -1
  181. package/dist/modules/notification/context.d.ts +1 -1
  182. package/dist/modules/notification/hooks.d.ts +1 -1
  183. package/dist/modules/notification/index.js +4 -828
  184. package/dist/modules/notification/index.js.map +1 -1
  185. package/dist/modules/notification/motion.d.ts +1 -7
  186. package/dist/modules/notification/motion.d.ts.map +1 -1
  187. package/dist/modules/notification/overlay.d.ts.map +1 -1
  188. package/dist/modules/notification/types.d.ts +9 -1
  189. package/dist/modules/notification/types.d.ts.map +1 -1
  190. package/dist/overlay-TZ6L52A5.js +9 -0
  191. package/dist/overlay-TZ6L52A5.js.map +1 -0
  192. package/dist/provider.d.ts +1 -1
  193. package/dist/provider.d.ts.map +1 -1
  194. package/dist/provider.js +6 -1968
  195. package/dist/provider.js.map +1 -1
  196. package/dist/result.js +2 -63
  197. package/dist/result.js.map +1 -1
  198. package/dist/theme.d.ts +45 -8
  199. package/dist/theme.d.ts.map +1 -1
  200. package/dist/theme.js +3 -41
  201. package/dist/theme.js.map +1 -1
  202. package/dist/tokens/index.d.ts +1 -0
  203. package/dist/tokens/index.d.ts.map +1 -1
  204. package/dist/tokens/index.js +126 -155
  205. package/dist/tokens/index.js.map +1 -1
  206. package/dist/tokens/motion-config.d.ts +44 -0
  207. package/dist/tokens/motion-config.d.ts.map +1 -0
  208. package/dist/tokens/motion.d.ts +23 -174
  209. package/dist/tokens/motion.d.ts.map +1 -1
  210. package/dist/utils/index.js +4 -82
  211. package/dist/utils/index.js.map +1 -1
  212. package/dist/utils/report.d.ts.map +1 -1
  213. package/docs/README.md +1 -0
  214. package/docs/architecture-and-rules.md +4 -3
  215. package/docs/core-engine.md +7 -10
  216. package/docs/getting-started.md +4 -2
  217. package/docs/modules/ambient.md +194 -80
  218. package/docs/modules/background.md +3 -3
  219. package/docs/modules/context-menu.md +2 -2
  220. package/docs/modules/dock.md +9 -6
  221. package/docs/modules/modal.md +2 -2
  222. package/docs/modules/notification.md +2 -2
  223. package/docs/theming.md +81 -9
  224. package/package.json +22 -5
  225. package/templates/AGENTS.md +1 -1
  226. package/templates/motion/background.ts +17 -0
  227. package/templates/motion/context-menu.ts +63 -0
  228. package/templates/motion/dock.ts +327 -0
  229. package/templates/motion/modal.ts +79 -0
  230. package/templates/motion/notification.ts +27 -0
  231. package/templates/motion/tokens.ts +47 -0
  232. package/templates/tsconfig.json +7 -0
  233. package/dist/modules/ambient/color.d.ts +0 -21
  234. package/dist/modules/ambient/color.d.ts.map +0 -1
@@ -0,0 +1,2166 @@
1
+ import { useOptionalMediaActions } from './chunk-R2YGFJDJ.js';
2
+ import { defineThemeSpec, useMotionTokens, retime, useTheme, useModuleMotion, cssEasing } from './chunk-7TAVYJ3A.js';
3
+ import { getOrCreateGlobalContext, defineModule, useRegistryValue, useModuleRegistration } from './chunk-GF7TUX5I.js';
4
+ import { createStore, cn, useStore, useIsomorphicLayoutEffect, useRequiredContext, report } from './chunk-TV3WEF5G.js';
5
+ import { Spinner } from './chunk-3BUP64Q6.js';
6
+ import { memo, useState, useRef, useEffect, useMemo, useCallback, useContext } from 'react';
7
+ import { AnimatePresence, motion } from 'motion/react';
8
+ import { usePathname } from 'next/navigation';
9
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
+
11
+ // src/modules/background/constants.ts
12
+ var backgroundTheme = defineThemeSpec("background");
13
+ var BACKGROUND_REGISTRY_KEY = "page-background";
14
+ var BACKGROUND_MEDIA_ID = "background";
15
+
16
+ // src/modules/background/visual.ts
17
+ var objectFit = (value) => ({
18
+ objectFit: value
19
+ });
20
+ var objectPosition = (value) => ({
21
+ objectPosition: value
22
+ });
23
+ var BG_TOKEN_TO_OBJECT_STYLE = Object.freeze({
24
+ "bg-bottom": objectPosition("bottom"),
25
+ "bg-center": objectPosition("center"),
26
+ "bg-contain": objectFit("contain"),
27
+ "bg-cover": objectFit("cover"),
28
+ "bg-fill": objectFit("fill"),
29
+ "bg-left": objectPosition("left"),
30
+ "bg-left-bottom": objectPosition("left bottom"),
31
+ "bg-left-top": objectPosition("left top"),
32
+ "bg-none": objectFit("none"),
33
+ "bg-right": objectPosition("right"),
34
+ "bg-right-bottom": objectPosition("right bottom"),
35
+ "bg-right-top": objectPosition("right top"),
36
+ "bg-scale-down": objectFit("scale-down"),
37
+ "bg-top": objectPosition("top")
38
+ });
39
+ var OBJECT_FITS = Object.freeze(["contain", "cover", "fill", "none", "scale-down"]);
40
+ var DEFAULT_COLOR = "var(--black, #000)";
41
+ var WIDTH_CLASS = /^(w-|max-w-|min-w-)/;
42
+ function resolveVideoClassNames(...inputs) {
43
+ const tokens = inputs.flatMap((input) => typeof input === "string" ? input.replace(/,/g, " ").split(/\s+/) : []).filter(Boolean);
44
+ return {
45
+ objectStyle: Object.assign({}, ...tokens.map((token) => BG_TOKEN_TO_OBJECT_STYLE[token])),
46
+ other: tokens.filter((token) => !WIDTH_CLASS.test(token)).join(" "),
47
+ width: tokens.filter((token) => WIDTH_CLASS.test(token)).join(" ")
48
+ };
49
+ }
50
+ function resolveVideoOptions(options = {}) {
51
+ return {
52
+ codec: options.codec || "auto",
53
+ corp: options.corp ?? 0,
54
+ forceIframe: Boolean(options.forceIframe),
55
+ isLoop: options.loop ?? false,
56
+ isMuted: options.muted ?? true,
57
+ playbackRate: options.playbackRate ?? 1,
58
+ quality: options.quality || "1080p",
59
+ shouldAutoPlay: options.autoplay ?? true,
60
+ showPoster: Boolean(options.showPoster),
61
+ showSpinner: options.showSpinner !== false
62
+ };
63
+ }
64
+ var generateBaseGradient = (direction, color) => {
65
+ const to = direction === "left" ? "to right" : "to left";
66
+ 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%)`;
67
+ };
68
+ var generateEdgeGradient = (direction, color) => {
69
+ const to = direction === "left" ? "to right" : "to left";
70
+ 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%)`;
71
+ };
72
+ function getVisualStyle(currentStyle = {}) {
73
+ const { className: _className, leftGradient = 0, rightGradient = 0, ...baseStyle } = currentStyle;
74
+ return {
75
+ baseStyle,
76
+ leftGradient: Number(leftGradient) || 0,
77
+ rightGradient: Number(rightGradient) || 0
78
+ };
79
+ }
80
+ function resolveGradientSettings({
81
+ fadeEdges = null,
82
+ hasWidth = false,
83
+ leftGradient = 0,
84
+ rightGradient = 0
85
+ }) {
86
+ let leftPercent = 0;
87
+ let rightPercent = 0;
88
+ if (leftGradient > 0) leftPercent = Math.min(48, Math.max(12, leftGradient * 7.5));
89
+ else if (hasWidth && fadeEdges !== false) leftPercent = 20;
90
+ if (rightGradient > 0) rightPercent = Math.min(48, Math.max(12, rightGradient * 7.5));
91
+ else if (hasWidth && fadeEdges !== false) rightPercent = 20;
92
+ if (typeof fadeEdges === "number") {
93
+ leftPercent = fadeEdges;
94
+ rightPercent = fadeEdges;
95
+ } else if (typeof fadeEdges === "string") {
96
+ const parsed = parseFloat(fadeEdges);
97
+ if (!Number.isNaN(parsed)) {
98
+ leftPercent = parsed;
99
+ rightPercent = parsed;
100
+ }
101
+ } else if (typeof fadeEdges === "object" && fadeEdges !== null) {
102
+ const edgeObj = fadeEdges;
103
+ if (edgeObj.left !== void 0) leftPercent = parseFloat(String(edgeObj.left)) || 0;
104
+ if (edgeObj.right !== void 0) rightPercent = parseFloat(String(edgeObj.right)) || 0;
105
+ } else if (fadeEdges === false) {
106
+ leftPercent = 0;
107
+ rightPercent = 0;
108
+ }
109
+ const leftOpacity = leftGradient > 0 ? Math.min(1, leftGradient * 0.22) : 0;
110
+ const rightOpacity = rightGradient > 0 ? Math.min(1, rightGradient * 0.22) : 0;
111
+ return {
112
+ enabled: leftPercent > 0 || rightPercent > 0,
113
+ leftOpacity,
114
+ leftPercent,
115
+ rightOpacity,
116
+ rightPercent
117
+ };
118
+ }
119
+ function generateSmoothstepStops(percent, direction = "in", color = "var(--black, #000)") {
120
+ const steps = [
121
+ { s: 0, t: 0 },
122
+ { s: 0.06, t: 0.15 },
123
+ { s: 0.22, t: 0.35 },
124
+ { s: 0.47, t: 0.55 },
125
+ { s: 0.76, t: 0.75 },
126
+ { s: 0.93, t: 0.9 },
127
+ { s: 1, t: 1 }
128
+ ];
129
+ if (direction === "in") {
130
+ return steps.map(
131
+ ({ 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)}%`
132
+ );
133
+ }
134
+ return steps.map(({ s, t }) => {
135
+ const alpha = 1 - s;
136
+ 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)}%`;
137
+ });
138
+ }
139
+ function getEdgeFadeMask({
140
+ color = "var(--black, #000)",
141
+ leftPercent = 0,
142
+ rightPercent = 0
143
+ }) {
144
+ if (leftPercent <= 0 && rightPercent <= 0) return void 0;
145
+ const leftStops = leftPercent > 0 ? generateSmoothstepStops(leftPercent, "in", color) : [`${color} 0%`];
146
+ const rightStops = rightPercent > 0 ? generateSmoothstepStops(rightPercent, "out", color) : [`${color} 100%`];
147
+ return `linear-gradient(to right, ${leftStops.join(", ")}, ${rightStops.join(", ")})`;
148
+ }
149
+
150
+ // src/modules/background/playback.ts
151
+ function applyVideoPlaybackState({
152
+ isPlaying,
153
+ playbackRate,
154
+ setVideoPlaying,
155
+ videoElement
156
+ }) {
157
+ if (!videoElement) return;
158
+ const numericPlaybackRate = Number(playbackRate);
159
+ const resolvedPlaybackRate = Number.isFinite(numericPlaybackRate) && numericPlaybackRate > 0 ? numericPlaybackRate : 1;
160
+ try {
161
+ if (videoElement.playbackRate !== resolvedPlaybackRate) {
162
+ videoElement.playbackRate = resolvedPlaybackRate;
163
+ }
164
+ } catch {
165
+ return;
166
+ }
167
+ if (!isPlaying) {
168
+ if (!videoElement.paused) videoElement.pause();
169
+ return;
170
+ }
171
+ if (videoElement.readyState === 0) {
172
+ return;
173
+ }
174
+ const playPromise = videoElement.play();
175
+ if (!playPromise || typeof playPromise.then !== "function") return;
176
+ playPromise.then(() => setVideoPlaying(true)).catch((error) => {
177
+ if (error?.name === "AbortError" || videoElement.readyState < 2) {
178
+ return;
179
+ }
180
+ if (error?.name === "NotAllowedError") {
181
+ videoElement.muted = true;
182
+ videoElement.play().then(() => setVideoPlaying(true)).catch(() => {
183
+ });
184
+ return;
185
+ }
186
+ setVideoPlaying(false);
187
+ });
188
+ }
189
+ function triggerVideoPlaybackDirect(videoElement, nextPlaying, configuredMuted) {
190
+ if (!videoElement) return;
191
+ if (nextPlaying) {
192
+ videoElement.muted = configuredMuted;
193
+ if (!configuredMuted && videoElement.volume === 0) {
194
+ videoElement.volume = 0.8;
195
+ }
196
+ videoElement.play().catch((err) => {
197
+ if (err?.name === "NotAllowedError") {
198
+ videoElement.muted = true;
199
+ videoElement.play().catch(() => {
200
+ });
201
+ }
202
+ });
203
+ } else {
204
+ videoElement.pause();
205
+ }
206
+ }
207
+ function syncVideoMutedDirect(videoElement, nextMuted) {
208
+ if (!videoElement) return;
209
+ videoElement.muted = nextMuted;
210
+ if (!nextMuted && videoElement.volume === 0) {
211
+ videoElement.volume = 0.8;
212
+ }
213
+ }
214
+ function syncVideoLoopDirect(videoElement, nextLoop) {
215
+ if (!videoElement) return;
216
+ videoElement.loop = nextLoop;
217
+ }
218
+
219
+ // src/modules/background/motion.ts
220
+ function useBackgroundMotion() {
221
+ return useModuleMotion(backgroundTheme);
222
+ }
223
+ function getBackgroundMotionConfig(motion2, animation) {
224
+ return {
225
+ animate: animation?.animate ?? motion2.animate,
226
+ exit: animation?.exit ?? motion2.exit,
227
+ exitDurationFactor: Number(animation?.exitDurationFactor),
228
+ initial: animation?.initial ?? motion2.initial,
229
+ transition: animation?.transition ?? motion2.transition
230
+ };
231
+ }
232
+ function getBackgroundExitTransition(motion2, config) {
233
+ const own = config.exit.transition;
234
+ const fallback = motion2.exit.transition;
235
+ const factor = Number.isFinite(config.exitDurationFactor) ? Math.max(0, config.exitDurationFactor) : motion2.exitDurationFactor;
236
+ return {
237
+ ...config.transition,
238
+ delay: 0,
239
+ duration: own?.duration ?? (config.transition.duration ?? motion2.transition.duration ?? 0) * factor,
240
+ ease: own?.ease ?? fallback?.ease
241
+ };
242
+ }
243
+ function toCssDuration(seconds, fallback = 0) {
244
+ const value = Number(seconds);
245
+ return `${Math.max(0, Number.isFinite(value) ? value : fallback) * 1e3}ms`;
246
+ }
247
+ function toCssDelay(seconds) {
248
+ const value = Number(seconds);
249
+ return `${Math.max(0, Number.isFinite(value) ? value : 0) * 1e3}ms`;
250
+ }
251
+ function toCssEasing(easing) {
252
+ return cssEasing(easing);
253
+ }
254
+
255
+ // src/modules/background/youtube/parse.ts
256
+ var YOUTUBE_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/;
257
+ function parseYouTubeTimeParam(value) {
258
+ if (value === void 0 || value === null || value === "") return 0;
259
+ if (typeof value === "number") {
260
+ return Number.isFinite(value) && value >= 0 ? value : 0;
261
+ }
262
+ const trimmed = String(value).trim().toLowerCase();
263
+ if (!trimmed) return 0;
264
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
265
+ return Math.max(0, parseFloat(trimmed));
266
+ }
267
+ const hmsMatch = trimmed.match(
268
+ /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s?)?$/
269
+ );
270
+ if (hmsMatch && (hmsMatch[1] || hmsMatch[2] || hmsMatch[3])) {
271
+ const hours = parseInt(hmsMatch[1] || "0", 10);
272
+ const minutes = parseInt(hmsMatch[2] || "0", 10);
273
+ const seconds = parseFloat(hmsMatch[3] || "0");
274
+ return Math.max(0, hours * 3600 + minutes * 60 + seconds);
275
+ }
276
+ return 0;
277
+ }
278
+ var YOUTUBE_HOST_PATH = /^(?:www\.|m\.|music\.)?(?:youtube\.com|youtu\.be|youtube-nocookie\.com)\//i;
279
+ function toUrl(input, { youtubeOnly = false } = {}) {
280
+ let candidate = null;
281
+ if (/^https?:\/\//.test(input)) candidate = input;
282
+ else if (input.startsWith("//")) candidate = `https:${input}`;
283
+ else if (!youtubeOnly || YOUTUBE_HOST_PATH.test(input)) {
284
+ candidate = `https://${input}`;
285
+ }
286
+ try {
287
+ return candidate ? new URL(candidate) : null;
288
+ } catch {
289
+ return null;
290
+ }
291
+ }
292
+ function getIdFromUrl(url) {
293
+ const host = url.hostname.replace(/^(www\.|m\.|music\.)/i, "").toLowerCase();
294
+ const segments = url.pathname.split("/").filter(Boolean);
295
+ if (host === "youtu.be") {
296
+ return YOUTUBE_ID_PATTERN.test(segments[0] ?? "") ? segments[0] : null;
297
+ }
298
+ if (host !== "youtube.com" && host !== "youtube-nocookie.com" && !host.endsWith(".youtube.com")) {
299
+ return null;
300
+ }
301
+ const fromQuery = url.searchParams.get("v") || url.searchParams.get("vi");
302
+ if (fromQuery && YOUTUBE_ID_PATTERN.test(fromQuery)) return fromQuery;
303
+ const isVideoPath = segments.length >= 2 && ["embed", "shorts", "live", "v", "e", "watch"].includes(
304
+ segments[0].toLowerCase()
305
+ );
306
+ return isVideoPath && YOUTUBE_ID_PATTERN.test(segments[1]) ? segments[1] : null;
307
+ }
308
+ function extractYouTubeVideoId(input, options = {}) {
309
+ const trimmed = typeof input === "string" ? input.trim() : "";
310
+ if (!trimmed) return null;
311
+ if (options.allowBareId && YOUTUBE_ID_PATTERN.test(trimmed)) return trimmed;
312
+ const prefixed = trimmed.match(/^(?:youtube|yt):([a-zA-Z0-9_-]{11})$/i);
313
+ if (prefixed) return prefixed[1];
314
+ const url = toUrl(trimmed, { youtubeOnly: true });
315
+ return url ? getIdFromUrl(url) : null;
316
+ }
317
+ function isYouTubeUrl(input) {
318
+ return Boolean(extractYouTubeVideoId(input));
319
+ }
320
+ function isDirectVideoUrl(input) {
321
+ if (!input || typeof input !== "string") return false;
322
+ const trimmed = input.trim();
323
+ if (!trimmed) return false;
324
+ if (isYouTubeUrl(trimmed)) return true;
325
+ if (trimmed.startsWith("/api/background/youtube") || trimmed.startsWith("blob:")) {
326
+ return true;
327
+ }
328
+ const cleanPath = trimmed.split("?")[0].split("#")[0].toLowerCase();
329
+ return /\.(mp4|webm|mov|m4v|ogg|ogv|m3u8)$/i.test(cleanPath);
330
+ }
331
+ function parseYouTubeUrlConfig(input, options = {}) {
332
+ const videoId = extractYouTubeVideoId(input, options);
333
+ if (!videoId || !input) return null;
334
+ const params = toUrl(input.trim())?.searchParams;
335
+ return {
336
+ endTime: parseYouTubeTimeParam(params?.get("end")),
337
+ listId: params?.get("list") || null,
338
+ rawUrl: input,
339
+ startTime: parseYouTubeTimeParam(params?.get("t") || params?.get("start")),
340
+ videoId
341
+ };
342
+ }
343
+ function getYouTubeStreamUrl(videoId, options = {}) {
344
+ const params = new URLSearchParams();
345
+ params.set("id", videoId);
346
+ params.set("stream", options.stream || "video");
347
+ if (options.quality) params.set("quality", options.quality);
348
+ if (options.codec) params.set("codec", options.codec);
349
+ return `/api/background/youtube?${params.toString()}`;
350
+ }
351
+ function getYouTubeThumbnailUrl(videoId, proxied = true) {
352
+ if (proxied) {
353
+ return `/api/background/youtube?id=${encodeURIComponent(videoId)}&stream=thumbnail`;
354
+ }
355
+ return `https://i.ytimg.com/vi/${encodeURIComponent(videoId)}/maxresdefault.jpg`;
356
+ }
357
+ function createYouTubeVideoElementProxy(controller) {
358
+ const proxyVideo = document.createElement("video");
359
+ Object.defineProperties(proxyVideo, {
360
+ currentTime: {
361
+ configurable: true,
362
+ get: () => controller.getCurrentTime(),
363
+ set: (value) => {
364
+ controller.seekTo(Number(value) || 0);
365
+ proxyVideo.dispatchEvent(new Event("timeupdate"));
366
+ }
367
+ },
368
+ duration: {
369
+ configurable: true,
370
+ get: () => controller.getDuration()
371
+ },
372
+ loop: {
373
+ configurable: true,
374
+ get: () => controller.getLoop(),
375
+ set: (value) => {
376
+ controller.setLoop(Boolean(value));
377
+ }
378
+ },
379
+ muted: {
380
+ configurable: true,
381
+ get: () => controller.getMuted(),
382
+ set: (value) => {
383
+ controller.setMuted(Boolean(value));
384
+ proxyVideo.dispatchEvent(new Event("volumechange"));
385
+ }
386
+ },
387
+ pause: {
388
+ configurable: true,
389
+ value: () => {
390
+ controller.pause();
391
+ proxyVideo.dispatchEvent(new Event("pause"));
392
+ }
393
+ },
394
+ paused: {
395
+ configurable: true,
396
+ get: () => controller.getPaused()
397
+ },
398
+ play: {
399
+ configurable: true,
400
+ value: () => controller.play().then(() => {
401
+ proxyVideo.dispatchEvent(new Event("play"));
402
+ proxyVideo.dispatchEvent(new Event("playing"));
403
+ })
404
+ },
405
+ playbackRate: {
406
+ configurable: true,
407
+ get: () => controller.getPlaybackRate(),
408
+ set: (value) => {
409
+ controller.setPlaybackRate(Number(value) || 1);
410
+ proxyVideo.dispatchEvent(new Event("ratechange"));
411
+ }
412
+ },
413
+ volume: {
414
+ configurable: true,
415
+ get: () => controller.getVolume(),
416
+ set: (value) => {
417
+ const clamped = Math.max(0, Math.min(1, Number(value) || 0));
418
+ controller.setVolume(clamped);
419
+ proxyVideo.dispatchEvent(new Event("volumechange"));
420
+ }
421
+ }
422
+ });
423
+ return proxyVideo;
424
+ }
425
+
426
+ // src/modules/background/state.ts
427
+ var DEFAULT_BACKGROUND = Object.freeze({
428
+ animation: null,
429
+ className: "",
430
+ fadeEdges: null,
431
+ fit: null,
432
+ image: null,
433
+ imageStyle: {},
434
+ isPlaying: false,
435
+ noiseStyle: {},
436
+ overlay: false,
437
+ overlayColor: "var(--black)",
438
+ overlayOpacity: 0,
439
+ position: "center",
440
+ video: null,
441
+ videoClassName: "",
442
+ videoElement: null,
443
+ videoOptions: {
444
+ autoplay: true,
445
+ className: "",
446
+ corp: 0,
447
+ loop: false,
448
+ muted: true,
449
+ playbackRate: 1,
450
+ width: null
451
+ },
452
+ videoStyle: {},
453
+ width: null
454
+ });
455
+ var DEFAULT_BACKGROUND_COMPUTED = Object.freeze({
456
+ ...DEFAULT_BACKGROUND,
457
+ hasBackground: false,
458
+ isVideo: false,
459
+ isYouTube: false,
460
+ posterUrl: null,
461
+ youtubeVideoId: null
462
+ });
463
+ var INERT_BACKGROUND_ACTIONS = Object.freeze({
464
+ resetBackground: () => {
465
+ },
466
+ setBackground: () => {
467
+ },
468
+ setVideoElement: () => {
469
+ },
470
+ setVideoMuted: () => {
471
+ },
472
+ setVideoPlaying: () => {
473
+ },
474
+ toggleLoop: () => {
475
+ },
476
+ toggleMute: () => {
477
+ },
478
+ toggleVideo: () => {
479
+ }
480
+ });
481
+ function normalizeBackgroundInput(patch = {}) {
482
+ if (!patch) return {};
483
+ if (typeof patch === "string") {
484
+ const trimmed = patch.trim();
485
+ if (isYouTubeUrl(trimmed) || isDirectVideoUrl(trimmed)) {
486
+ return { image: null, video: trimmed };
487
+ }
488
+ return { image: trimmed };
489
+ }
490
+ const nextPatch = { ...patch };
491
+ if (typeof nextPatch.image === "string" && isYouTubeUrl(nextPatch.image) && !nextPatch.video) {
492
+ nextPatch.video = nextPatch.image;
493
+ nextPatch.image = null;
494
+ }
495
+ return nextPatch;
496
+ }
497
+ function mergeBackgroundState(baseState, patch = {}) {
498
+ const resolvedPatch = normalizeBackgroundInput(patch);
499
+ const nextVideoOptions = {
500
+ ...baseState.videoOptions,
501
+ ...resolvedPatch.videoOptions || {}
502
+ };
503
+ const nextVideo = resolvedPatch.video !== void 0 ? resolvedPatch.video : baseState.video;
504
+ const shouldAutoPlay = nextVideoOptions.autoplay !== false;
505
+ const resolvedIsPlaying = resolvedPatch.isPlaying !== void 0 ? resolvedPatch.isPlaying : resolvedPatch.video !== void 0 && Boolean(nextVideo) ? shouldAutoPlay : baseState.isPlaying;
506
+ return {
507
+ ...baseState,
508
+ ...resolvedPatch,
509
+ isPlaying: resolvedIsPlaying,
510
+ animation: resolvedPatch.animation !== void 0 ? resolvedPatch.animation ? {
511
+ ...baseState.animation || {},
512
+ ...resolvedPatch.animation
513
+ } : resolvedPatch.animation : baseState.animation,
514
+ imageStyle: {
515
+ ...baseState.imageStyle,
516
+ ...resolvedPatch.imageStyle || {}
517
+ },
518
+ noiseStyle: {
519
+ ...baseState.noiseStyle,
520
+ ...resolvedPatch.noiseStyle || {}
521
+ },
522
+ videoOptions: nextVideoOptions,
523
+ videoStyle: {
524
+ ...baseState.videoStyle,
525
+ ...resolvedPatch.videoStyle || {}
526
+ }
527
+ };
528
+ }
529
+ function resolveBackgroundState(registryBackground, override, pathname) {
530
+ const base = registryBackground ? mergeBackgroundState(DEFAULT_BACKGROUND, registryBackground) : DEFAULT_BACKGROUND;
531
+ const patch = override.pathname === pathname ? override.patch : null;
532
+ return patch ? mergeBackgroundState(base, patch) : base;
533
+ }
534
+ function computeBackgroundState(background) {
535
+ const youtubeVideoId = extractYouTubeVideoId(background.video);
536
+ const isYouTube = Boolean(youtubeVideoId);
537
+ const isVideo = Boolean(background.video || isYouTube);
538
+ return {
539
+ ...background,
540
+ hasBackground: Boolean(
541
+ background.image || isVideo || background.color || background.overlay || background.noiseStyle && (background.noiseStyle.opacity === void 0 || (background.noiseStyle.opacity ?? 0) > 0)
542
+ ),
543
+ isVideo,
544
+ isYouTube,
545
+ posterUrl: youtubeVideoId ? getYouTubeThumbnailUrl(youtubeVideoId) : null,
546
+ youtubeVideoId
547
+ };
548
+ }
549
+ var BackgroundContext = getOrCreateGlobalContext(
550
+ "BackgroundContext",
551
+ null
552
+ );
553
+ function useSafePathname() {
554
+ try {
555
+ return usePathname();
556
+ } catch {
557
+ return null;
558
+ }
559
+ }
560
+ function BackgroundProvider({ children }) {
561
+ const pathname = useSafePathname();
562
+ const registryBackground = useRegistryValue(
563
+ "background",
564
+ BACKGROUND_REGISTRY_KEY
565
+ ) ?? null;
566
+ const [overrideStore] = useState(
567
+ () => createStore(
568
+ { patch: null, pathname },
569
+ { freezeSnapshots: false }
570
+ )
571
+ );
572
+ const scopedOverride = useStore(overrideStore);
573
+ const inputsRef = useRef({ pathname, registryBackground });
574
+ useIsomorphicLayoutEffect(() => {
575
+ inputsRef.current = { pathname, registryBackground };
576
+ }, [pathname, registryBackground]);
577
+ const videoElementRef = useRef(null);
578
+ const state = useMemo(
579
+ () => computeBackgroundState(
580
+ resolveBackgroundState(registryBackground, scopedOverride, pathname)
581
+ ),
582
+ [pathname, registryBackground, scopedOverride]
583
+ );
584
+ const [stateStore] = useState(
585
+ () => createStore(state, { freezeSnapshots: false })
586
+ );
587
+ useIsomorphicLayoutEffect(() => {
588
+ stateStore.publish(state);
589
+ }, [state, stateStore]);
590
+ const actions = useMemo(() => {
591
+ const readCurrent = () => {
592
+ const { pathname: currentPath, registryBackground: registry } = inputsRef.current;
593
+ return resolveBackgroundState(
594
+ registry,
595
+ overrideStore.getSnapshot(),
596
+ currentPath
597
+ );
598
+ };
599
+ const updatePatch = (updater) => {
600
+ overrideStore.publish((prev) => {
601
+ const { pathname: currentPath, registryBackground: registry } = inputsRef.current;
602
+ const currentPatch = prev.pathname === currentPath ? prev.patch : null;
603
+ const rawNext = updater(
604
+ resolveBackgroundState(registry, prev, currentPath)
605
+ );
606
+ if (!rawNext || Object.keys(rawNext).length === 0) {
607
+ return prev;
608
+ }
609
+ const normalizedNext = normalizeBackgroundInput(rawNext);
610
+ const mergedPatch = {
611
+ ...currentPatch || {},
612
+ ...normalizedNext,
613
+ ...currentPatch?.videoOptions || normalizedNext.videoOptions ? {
614
+ videoOptions: {
615
+ ...currentPatch?.videoOptions || {},
616
+ ...normalizedNext.videoOptions || {}
617
+ }
618
+ } : {}
619
+ };
620
+ return {
621
+ patch: mergedPatch,
622
+ pathname: currentPath
623
+ };
624
+ });
625
+ };
626
+ const currentVideoElement = (current) => videoElementRef.current || current.videoElement;
627
+ return {
628
+ resetBackground: () => {
629
+ overrideStore.publish({
630
+ patch: null,
631
+ pathname: inputsRef.current.pathname
632
+ });
633
+ },
634
+ setBackground: (nextBackground) => {
635
+ updatePatch(() => normalizeBackgroundInput(nextBackground));
636
+ },
637
+ setVideoElement: (videoElement2) => {
638
+ videoElementRef.current = videoElement2;
639
+ updatePatch(
640
+ (cur) => cur.videoElement === videoElement2 ? {} : { videoElement: videoElement2 }
641
+ );
642
+ },
643
+ setVideoMuted: (muted) => {
644
+ const nextMuted = Boolean(muted);
645
+ syncVideoMutedDirect(currentVideoElement(readCurrent()), nextMuted);
646
+ updatePatch((cur) => {
647
+ if (cur.videoOptions?.muted === nextMuted) return {};
648
+ return {
649
+ videoOptions: { ...cur.videoOptions, muted: nextMuted }
650
+ };
651
+ });
652
+ },
653
+ setVideoPlaying: (isPlaying2) => {
654
+ updatePatch(
655
+ (cur) => cur.isPlaying === isPlaying2 ? {} : { isPlaying: isPlaying2 }
656
+ );
657
+ },
658
+ toggleLoop: () => {
659
+ const current = readCurrent();
660
+ const nextLoop = !current.videoOptions?.loop;
661
+ syncVideoLoopDirect(currentVideoElement(current), nextLoop);
662
+ updatePatch((cur) => ({
663
+ videoOptions: { ...cur.videoOptions, loop: nextLoop }
664
+ }));
665
+ },
666
+ toggleMute: () => {
667
+ const current = readCurrent();
668
+ const nextMuted = !current.videoOptions?.muted;
669
+ syncVideoMutedDirect(currentVideoElement(current), nextMuted);
670
+ updatePatch((cur) => ({
671
+ isPlaying: nextMuted ? cur.isPlaying : true,
672
+ videoOptions: { ...cur.videoOptions, muted: nextMuted }
673
+ }));
674
+ },
675
+ toggleVideo: () => {
676
+ const current = readCurrent();
677
+ const videoEl = currentVideoElement(current);
678
+ const domIsActuallyPlaying = videoEl ? !videoEl.paused && !videoEl.ended : Boolean(current.isPlaying);
679
+ const nextPlaying = !domIsActuallyPlaying;
680
+ const configuredMuted = Boolean(current.videoOptions?.muted);
681
+ triggerVideoPlaybackDirect(videoEl, nextPlaying, configuredMuted);
682
+ updatePatch(() => ({ isPlaying: nextPlaying }));
683
+ }
684
+ };
685
+ }, [overrideStore]);
686
+ const media = useOptionalMediaActions();
687
+ const { isPlaying, isVideo, videoElement } = state;
688
+ const isLoop = Boolean(state.videoOptions?.loop);
689
+ useEffect(() => {
690
+ if (!isVideo) {
691
+ media.removeSource(BACKGROUND_MEDIA_ID);
692
+ return;
693
+ }
694
+ media.upsertSource({
695
+ controls: {
696
+ setMuted: actions.setVideoMuted,
697
+ toggle: actions.toggleVideo,
698
+ toggleLoop: actions.toggleLoop
699
+ },
700
+ element: videoElement ?? null,
701
+ id: BACKGROUND_MEDIA_ID,
702
+ isPlaying,
703
+ kind: "video",
704
+ loop: isLoop
705
+ });
706
+ }, [actions, isLoop, isPlaying, isVideo, media, videoElement]);
707
+ useEffect(() => () => media.removeSource(BACKGROUND_MEDIA_ID), [media]);
708
+ const value = useMemo(
709
+ () => ({ actions, store: stateStore }),
710
+ [actions, stateStore]
711
+ );
712
+ return /* @__PURE__ */ jsx(BackgroundContext, { value, children });
713
+ }
714
+
715
+ // src/modules/background/hooks.ts
716
+ var NOOP_BACKGROUND_STORE = createStore(
717
+ DEFAULT_BACKGROUND_COMPUTED
718
+ );
719
+ function useBackgroundRegistration(config, options) {
720
+ useModuleRegistration("background", config, options);
721
+ }
722
+ function useBackgroundState() {
723
+ const { store } = useRequiredContext(
724
+ BackgroundContext,
725
+ "useBackgroundState",
726
+ "BackgroundProvider"
727
+ );
728
+ return useStore(store);
729
+ }
730
+ function useBackgroundActions() {
731
+ return useRequiredContext(
732
+ BackgroundContext,
733
+ "useBackgroundActions",
734
+ "BackgroundProvider"
735
+ ).actions;
736
+ }
737
+ function useBackground(config, options) {
738
+ useBackgroundRegistration(config, options);
739
+ const actions = useBackgroundActions();
740
+ const state = useBackgroundState();
741
+ return useMemo(() => ({ ...state, ...actions }), [actions, state]);
742
+ }
743
+ function useOptionalBackgroundState(selector, isEqual) {
744
+ const ctx = useContext(BackgroundContext);
745
+ return useStore(
746
+ ctx?.store ?? NOOP_BACKGROUND_STORE,
747
+ selector,
748
+ isEqual
749
+ );
750
+ }
751
+ function useOptionalBackgroundActions() {
752
+ const ctx = useContext(BackgroundContext);
753
+ return ctx?.actions ?? INERT_BACKGROUND_ACTIONS;
754
+ }
755
+ var PLAYER_STATE = { ENDED: 0, PLAYING: 1, PAUSED: 2, BUFFERING: 3 };
756
+ var apiPromise = null;
757
+ function loadYouTubeIframeApi() {
758
+ if (typeof window === "undefined") return Promise.resolve(null);
759
+ if (window.YT?.Player) return Promise.resolve(window.YT);
760
+ if (apiPromise) return apiPromise;
761
+ apiPromise = new Promise((resolve) => {
762
+ const previousCallback = window.onYouTubeIframeAPIReady;
763
+ window.onYouTubeIframeAPIReady = () => {
764
+ previousCallback?.();
765
+ resolve(window.YT);
766
+ };
767
+ if (!document.querySelector(
768
+ 'script[src="https://www.youtube.com/iframe_api"]'
769
+ )) {
770
+ const script = document.createElement("script");
771
+ script.src = "https://www.youtube.com/iframe_api";
772
+ script.async = true;
773
+ document.head.appendChild(script);
774
+ }
775
+ });
776
+ return apiPromise;
777
+ }
778
+ function setHighQuality(player) {
779
+ player?.setPlaybackQualityRange?.("hd1080", "hd1080");
780
+ player?.setPlaybackQuality?.("hd1080");
781
+ }
782
+ function useYouTubeIframePlayer({
783
+ enabled,
784
+ hostRef,
785
+ isLoop,
786
+ isMuted,
787
+ isPlaying,
788
+ live,
789
+ playbackRate,
790
+ setIsBuffering,
791
+ setIsFrameReady,
792
+ setVideoElement,
793
+ setVideoPlaying,
794
+ shouldAutoPlay,
795
+ startTime,
796
+ videoId
797
+ }) {
798
+ const playerRef = useRef(null);
799
+ useEffect(() => {
800
+ if (!enabled) return void 0;
801
+ let isDisposed = false;
802
+ let progressInterval = null;
803
+ let proxyElement = null;
804
+ const state = {
805
+ currentTime: startTime || 0,
806
+ duration: 0,
807
+ loop: Boolean(isLoop),
808
+ muted: Boolean(isMuted),
809
+ paused: !shouldAutoPlay,
810
+ playbackRate: Number(playbackRate) || 1,
811
+ volume: isMuted ? 0 : 0.8
812
+ };
813
+ const player = () => playerRef.current;
814
+ const restart = (target) => {
815
+ const restartAt = Math.max(0, live.current.startTime || 0);
816
+ target?.seekTo?.(restartAt, true);
817
+ target?.playVideo?.();
818
+ return restartAt;
819
+ };
820
+ const emit = (type) => proxyElement?.dispatchEvent(new Event(type));
821
+ const trackProgress = () => {
822
+ const current = player();
823
+ if (!current || typeof current.getCurrentTime !== "function") return;
824
+ const time = Number(current.getCurrentTime()) || 0;
825
+ const duration = Number(current.getDuration?.()) || state.duration;
826
+ state.currentTime = time;
827
+ if (duration > 0 && duration !== state.duration) {
828
+ state.duration = duration;
829
+ emit("durationchange");
830
+ }
831
+ const { corp, endTime, isLoop: loops } = live.current;
832
+ const safetyEnd = endTime > 0 ? endTime : duration > 0 ? duration - Math.max(corp, 0.4) : 0;
833
+ if (safetyEnd > 0 && time >= safetyEnd) {
834
+ if (state.loop || loops) {
835
+ state.currentTime = restart(current);
836
+ } else {
837
+ current.pauseVideo?.();
838
+ state.paused = true;
839
+ setVideoPlaying(false);
840
+ }
841
+ }
842
+ emit("timeupdate");
843
+ };
844
+ const handleReady = (event) => {
845
+ if (isDisposed) return;
846
+ const target = event.target;
847
+ playerRef.current = target ?? null;
848
+ state.duration = Number(target?.getDuration?.()) || 0;
849
+ const { isMuted: muted, isPlaying: isPlaying2, playbackRate: rate } = live.current;
850
+ if (rate !== 1) target?.setPlaybackRate?.(rate);
851
+ if (muted) {
852
+ target?.mute?.();
853
+ } else {
854
+ target?.unMute?.();
855
+ target?.setVolume?.(80);
856
+ }
857
+ if (live.current.shouldAutoPlay && isPlaying2) {
858
+ setHighQuality(target);
859
+ target?.playVideo?.();
860
+ state.paused = false;
861
+ setVideoPlaying(true);
862
+ }
863
+ if (proxyElement) {
864
+ setVideoElement(proxyElement);
865
+ emit("loadedmetadata");
866
+ emit("durationchange");
867
+ }
868
+ progressInterval = window.setInterval(trackProgress, 200);
869
+ };
870
+ const handleStateChange = (event) => {
871
+ if (isDisposed) return;
872
+ switch (event.data) {
873
+ case PLAYER_STATE.PLAYING:
874
+ setHighQuality(event.target);
875
+ state.paused = false;
876
+ setIsFrameReady(true);
877
+ setIsBuffering(false);
878
+ setVideoPlaying(true);
879
+ emit("play");
880
+ emit("playing");
881
+ break;
882
+ case PLAYER_STATE.BUFFERING:
883
+ setIsBuffering(true);
884
+ break;
885
+ case PLAYER_STATE.PAUSED:
886
+ state.paused = true;
887
+ setIsBuffering(false);
888
+ setVideoPlaying(false);
889
+ emit("pause");
890
+ break;
891
+ case PLAYER_STATE.ENDED:
892
+ if (state.loop || live.current.isLoop) {
893
+ restart(player());
894
+ } else {
895
+ state.paused = true;
896
+ setVideoPlaying(false);
897
+ emit("ended");
898
+ }
899
+ break;
900
+ }
901
+ };
902
+ loadYouTubeIframeApi().then((YT) => {
903
+ const host = hostRef.current;
904
+ if (isDisposed || !YT?.Player || !host) return;
905
+ host.innerHTML = "";
906
+ const mountTarget = document.createElement("div");
907
+ host.appendChild(mountTarget);
908
+ proxyElement = createYouTubeVideoElementProxy({
909
+ getCurrentTime: () => state.currentTime,
910
+ getDuration: () => state.duration,
911
+ getLoop: () => state.loop,
912
+ getMuted: () => state.muted,
913
+ getPaused: () => state.paused,
914
+ getPlaybackRate: () => state.playbackRate,
915
+ getVolume: () => state.volume,
916
+ pause: () => {
917
+ state.paused = true;
918
+ player()?.pauseVideo?.();
919
+ setVideoPlaying(false);
920
+ },
921
+ play: async () => {
922
+ state.paused = false;
923
+ player()?.playVideo?.();
924
+ setVideoPlaying(true);
925
+ },
926
+ seekTo: (seconds) => {
927
+ state.currentTime = seconds;
928
+ player()?.seekTo?.(seconds, true);
929
+ if (!state.paused) player()?.playVideo?.();
930
+ },
931
+ setLoop: (loop) => {
932
+ state.loop = loop;
933
+ },
934
+ setMuted: (muted) => {
935
+ state.muted = muted;
936
+ if (muted) {
937
+ player()?.mute?.();
938
+ return;
939
+ }
940
+ player()?.unMute?.();
941
+ if (state.volume === 0) {
942
+ state.volume = 0.7;
943
+ player()?.setVolume?.(70);
944
+ }
945
+ },
946
+ setPlaybackRate: (rate) => {
947
+ state.playbackRate = rate;
948
+ player()?.setPlaybackRate?.(rate);
949
+ },
950
+ setVolume: (volume) => {
951
+ state.volume = volume;
952
+ player()?.setVolume?.(Math.round(volume * 100));
953
+ if (volume > 0 && state.muted) {
954
+ state.muted = false;
955
+ player()?.unMute?.();
956
+ } else if (volume === 0 && !state.muted) {
957
+ state.muted = true;
958
+ player()?.mute?.();
959
+ }
960
+ }
961
+ });
962
+ const initial = live.current;
963
+ playerRef.current = new YT.Player(mountTarget, {
964
+ events: { onReady: handleReady, onStateChange: handleStateChange },
965
+ host: "https://www.youtube-nocookie.com",
966
+ playerVars: {
967
+ autoplay: initial.shouldAutoPlay ? 1 : 0,
968
+ controls: 0,
969
+ disablekb: 1,
970
+ enablejsapi: 1,
971
+ fs: 0,
972
+ iv_load_policy: 3,
973
+ loop: initial.isLoop ? 1 : 0,
974
+ modestbranding: 1,
975
+ mute: initial.isMuted ? 1 : 0,
976
+ origin: window.location.origin,
977
+ playlist: videoId,
978
+ playsinline: 1,
979
+ rel: 0,
980
+ start: Math.floor(initial.startTime || 0)
981
+ },
982
+ videoId
983
+ });
984
+ });
985
+ return () => {
986
+ isDisposed = true;
987
+ if (progressInterval !== null) window.clearInterval(progressInterval);
988
+ try {
989
+ playerRef.current?.destroy?.();
990
+ } catch {
991
+ }
992
+ playerRef.current = null;
993
+ setVideoElement(null);
994
+ };
995
+ }, [
996
+ enabled,
997
+ hostRef,
998
+ isLoop,
999
+ isMuted,
1000
+ live,
1001
+ playbackRate,
1002
+ setIsBuffering,
1003
+ setIsFrameReady,
1004
+ setVideoElement,
1005
+ setVideoPlaying,
1006
+ shouldAutoPlay,
1007
+ startTime,
1008
+ videoId
1009
+ ]);
1010
+ useEffect(() => {
1011
+ const current = playerRef.current;
1012
+ if (!enabled || !current) return;
1013
+ try {
1014
+ if (isPlaying) current.playVideo?.();
1015
+ else current.pauseVideo?.();
1016
+ if (isMuted) current.mute?.();
1017
+ else current.unMute?.();
1018
+ if (playbackRate) current.setPlaybackRate?.(playbackRate);
1019
+ } catch {
1020
+ }
1021
+ }, [enabled, isMuted, isPlaying, playbackRate]);
1022
+ }
1023
+ var AUDIO_SYNC_EVENTS = [
1024
+ "play",
1025
+ "playing",
1026
+ "pause",
1027
+ "waiting",
1028
+ "volumechange",
1029
+ "ratechange"
1030
+ ];
1031
+ function setElementMuted(video, muted) {
1032
+ video.muted = muted;
1033
+ if (!muted && video.volume === 0) video.volume = 0.8;
1034
+ }
1035
+ function unlockAudioOnGesture(unlock) {
1036
+ const handler = () => {
1037
+ unlock();
1038
+ window.removeEventListener("pointerdown", handler);
1039
+ window.removeEventListener("keydown", handler);
1040
+ };
1041
+ window.addEventListener("pointerdown", handler, { once: true });
1042
+ window.addEventListener("keydown", handler, { once: true });
1043
+ }
1044
+ function useYouTubeBackgroundPlayerModel({
1045
+ codec = "auto",
1046
+ corp = 0,
1047
+ endTime = 0,
1048
+ forceIframe = false,
1049
+ isLoop = false,
1050
+ isMuted = true,
1051
+ isPlaying = true,
1052
+ playbackRate = 1,
1053
+ posterUrl = null,
1054
+ quality = "1080p",
1055
+ setVideoElement,
1056
+ setVideoPlaying,
1057
+ shouldAutoPlay = true,
1058
+ showPoster = false,
1059
+ showSpinner = true,
1060
+ startTime = 0,
1061
+ videoClasses: _videoClasses,
1062
+ videoId,
1063
+ videoStyle: _videoStyle
1064
+ }) {
1065
+ const [useIframeFallback, setUseIframeFallback] = useState(
1066
+ Boolean(forceIframe)
1067
+ );
1068
+ const [isFrameReady, setIsFrameReady] = useState(false);
1069
+ const [isBuffering, setIsBuffering] = useState(true);
1070
+ const videoRef = useRef(null);
1071
+ const audioRef = useRef(null);
1072
+ const iframeHostRef = useRef(null);
1073
+ const hasLoadedVideoRef = useRef(false);
1074
+ const errorRetryCountRef = useRef(0);
1075
+ const audioErrorRetryCountRef = useRef(0);
1076
+ const retryTimerIdsRef = useRef(/* @__PURE__ */ new Set());
1077
+ const lastAudioSeekAtRef = useRef(0);
1078
+ const live = useRef({
1079
+ corp,
1080
+ endTime,
1081
+ isLoop,
1082
+ isMuted,
1083
+ isPlaying,
1084
+ playbackRate,
1085
+ shouldAutoPlay,
1086
+ startTime
1087
+ });
1088
+ live.current = {
1089
+ corp,
1090
+ endTime,
1091
+ isLoop,
1092
+ isMuted,
1093
+ isPlaying,
1094
+ playbackRate,
1095
+ shouldAutoPlay,
1096
+ startTime
1097
+ };
1098
+ useEffect(() => {
1099
+ setUseIframeFallback(Boolean(forceIframe));
1100
+ setIsFrameReady(false);
1101
+ setIsBuffering(true);
1102
+ hasLoadedVideoRef.current = false;
1103
+ errorRetryCountRef.current = 0;
1104
+ audioErrorRetryCountRef.current = 0;
1105
+ }, [forceIframe, videoId]);
1106
+ const videoStreamUrl = useMemo(
1107
+ () => getYouTubeStreamUrl(videoId, { codec, quality, stream: "video" }),
1108
+ [codec, quality, videoId]
1109
+ );
1110
+ const audioStreamUrl = useMemo(
1111
+ () => getYouTubeStreamUrl(videoId, { stream: "audio" }),
1112
+ [videoId]
1113
+ );
1114
+ const resolvedPoster = showPoster ? posterUrl || getYouTubeThumbnailUrl(videoId, true) : null;
1115
+ const syncCompanionAudio = useCallback((forceSeek = false) => {
1116
+ const video = videoRef.current;
1117
+ const audio = audioRef.current;
1118
+ if (!video || !audio) return;
1119
+ try {
1120
+ const targetRate = Number(video.playbackRate) || 1;
1121
+ if (audio.playbackRate !== targetRate) audio.playbackRate = targetRate;
1122
+ if (audio.readyState < 2 || !Number.isFinite(audio.duration) || audio.duration <= 0) {
1123
+ return;
1124
+ }
1125
+ const volume = Math.max(0, Math.min(1, Number(video.volume) ?? 1));
1126
+ if (Math.abs(audio.volume - volume) > 5e-3) audio.volume = volume;
1127
+ const isSilent = Boolean(video.muted) || volume === 0;
1128
+ if (audio.muted !== isSilent) audio.muted = isSilent;
1129
+ if (video.paused || video.ended || video.seeking) {
1130
+ if (!audio.paused) audio.pause();
1131
+ return;
1132
+ }
1133
+ const now = performance.now();
1134
+ const drift = Math.abs(audio.currentTime - video.currentTime);
1135
+ const maxDrift = isSilent ? 0.5 : 0.35;
1136
+ if (forceSeek || drift > maxDrift && now - lastAudioSeekAtRef.current > 1500) {
1137
+ lastAudioSeekAtRef.current = now;
1138
+ audio.currentTime = video.currentTime;
1139
+ }
1140
+ if (audio.paused) audio.play().catch(() => {
1141
+ });
1142
+ } catch {
1143
+ }
1144
+ }, []);
1145
+ const playWithFallback = useCallback(
1146
+ (video, forceSeek, unlockAudio) => {
1147
+ const onPlayed = () => {
1148
+ setVideoPlaying(true);
1149
+ syncCompanionAudio(forceSeek);
1150
+ };
1151
+ video.play().then(onPlayed).catch((error) => {
1152
+ if (error?.name !== "NotAllowedError") return;
1153
+ video.muted = true;
1154
+ video.play().then(() => {
1155
+ onPlayed();
1156
+ if (!unlockAudio) return;
1157
+ unlockAudioOnGesture(() => {
1158
+ const current = videoRef.current;
1159
+ if (!live.current.isMuted && current) {
1160
+ setElementMuted(current, false);
1161
+ }
1162
+ });
1163
+ }).catch(() => {
1164
+ });
1165
+ });
1166
+ },
1167
+ [setVideoPlaying, syncCompanionAudio]
1168
+ );
1169
+ const scheduleRetry = (callback, delay) => {
1170
+ const timerId = window.setTimeout(() => {
1171
+ retryTimerIdsRef.current.delete(timerId);
1172
+ try {
1173
+ callback();
1174
+ } catch {
1175
+ }
1176
+ }, delay);
1177
+ retryTimerIdsRef.current.add(timerId);
1178
+ };
1179
+ const handleEnded = useCallback(() => {
1180
+ const video = videoRef.current;
1181
+ const audio = audioRef.current;
1182
+ if (!video) return;
1183
+ if (video.loop || live.current.isLoop) {
1184
+ const resetTime = Math.max(0, live.current.startTime || 0);
1185
+ video.currentTime = resetTime;
1186
+ if (audio && audio.readyState >= 2) audio.currentTime = resetTime;
1187
+ video.play().then(() => {
1188
+ setVideoPlaying(true);
1189
+ syncCompanionAudio(true);
1190
+ }).catch(() => {
1191
+ });
1192
+ return;
1193
+ }
1194
+ video.pause();
1195
+ if (audio && !audio.paused) audio.pause();
1196
+ setVideoPlaying(false);
1197
+ }, [setVideoPlaying, syncCompanionAudio]);
1198
+ const handleTimeUpdate = () => {
1199
+ const video = videoRef.current;
1200
+ if (!video) return;
1201
+ if (video.currentTime > 0 && video.readyState >= 2) {
1202
+ setIsFrameReady(true);
1203
+ setIsBuffering(false);
1204
+ }
1205
+ const duration = Number(video.duration) || 0;
1206
+ const { corp: activeCorp, endTime: activeEndTime } = live.current;
1207
+ const effectiveEnd = activeEndTime > 0 ? activeEndTime : activeCorp > 0 && duration > 0 ? duration - activeCorp : 0;
1208
+ if (effectiveEnd > 0 && video.currentTime >= effectiveEnd) handleEnded();
1209
+ };
1210
+ const handlePlay = () => {
1211
+ const video = videoRef.current;
1212
+ hasLoadedVideoRef.current = true;
1213
+ if (video && !live.current.isMuted && video.muted) {
1214
+ setElementMuted(video, false);
1215
+ }
1216
+ if (!video || video.readyState < 2) setIsBuffering(true);
1217
+ setVideoPlaying(true);
1218
+ syncCompanionAudio(false);
1219
+ };
1220
+ const handlePlaying = () => {
1221
+ hasLoadedVideoRef.current = true;
1222
+ setIsFrameReady(true);
1223
+ setIsBuffering(false);
1224
+ setVideoPlaying(true);
1225
+ syncCompanionAudio(false);
1226
+ };
1227
+ const handlePause = () => {
1228
+ const video = videoRef.current;
1229
+ syncCompanionAudio(false);
1230
+ setIsBuffering(false);
1231
+ if (video && !video.seeking && !video.ended && !live.current.isPlaying) {
1232
+ setVideoPlaying(false);
1233
+ }
1234
+ };
1235
+ const handleSeeked = () => {
1236
+ const video = videoRef.current;
1237
+ if (!video) return;
1238
+ setIsFrameReady(true);
1239
+ if (video.readyState >= 2 && (!live.current.isPlaying || !video.paused)) {
1240
+ setIsBuffering(false);
1241
+ }
1242
+ syncCompanionAudio(true);
1243
+ if (live.current.isPlaying && video.paused) {
1244
+ video.play().then(() => {
1245
+ setVideoPlaying(true);
1246
+ syncCompanionAudio(true);
1247
+ }).catch(() => {
1248
+ });
1249
+ }
1250
+ };
1251
+ const handleCanPlay = () => {
1252
+ const video = videoRef.current;
1253
+ if (!video) return;
1254
+ hasLoadedVideoRef.current = true;
1255
+ if (!live.current.isPlaying) {
1256
+ setIsFrameReady(true);
1257
+ setIsBuffering(false);
1258
+ } else if (video.paused) {
1259
+ setElementMuted(video, Boolean(live.current.isMuted));
1260
+ playWithFallback(video, false, true);
1261
+ }
1262
+ };
1263
+ const handleLoadedMetadata = () => {
1264
+ const video = videoRef.current;
1265
+ if (!video) return;
1266
+ hasLoadedVideoRef.current = true;
1267
+ if (startTime > 0 && video.currentTime < startTime) {
1268
+ video.currentTime = startTime;
1269
+ if (audioRef.current) audioRef.current.currentTime = startTime;
1270
+ }
1271
+ };
1272
+ const handleLoadedData = () => {
1273
+ const video = videoRef.current;
1274
+ if (!video) return;
1275
+ hasLoadedVideoRef.current = true;
1276
+ video.playbackRate = playbackRate;
1277
+ setElementMuted(video, Boolean(live.current.isMuted));
1278
+ if (startTime > 0 && video.currentTime < startTime) {
1279
+ video.currentTime = startTime;
1280
+ }
1281
+ if (!live.current.isPlaying) {
1282
+ setIsFrameReady(true);
1283
+ setIsBuffering(false);
1284
+ } else if (video.paused) {
1285
+ playWithFallback(video, true, false);
1286
+ }
1287
+ };
1288
+ const handleError = () => {
1289
+ const video = videoRef.current;
1290
+ if (video && hasLoadedVideoRef.current) {
1291
+ const resumeTime = video.currentTime || 0;
1292
+ scheduleRetry(() => {
1293
+ video.load();
1294
+ video.currentTime = resumeTime;
1295
+ if (live.current.isPlaying) video.play().catch(() => {
1296
+ });
1297
+ }, 150);
1298
+ return;
1299
+ }
1300
+ errorRetryCountRef.current += 1;
1301
+ if (video && errorRetryCountRef.current <= 1) {
1302
+ scheduleRetry(() => video.load(), 200);
1303
+ return;
1304
+ }
1305
+ setUseIframeFallback(true);
1306
+ };
1307
+ const handleAudioError = useCallback(() => {
1308
+ const audio = audioRef.current;
1309
+ if (!audio) return;
1310
+ audioErrorRetryCountRef.current += 1;
1311
+ if (audioErrorRetryCountRef.current <= 1) {
1312
+ scheduleRetry(() => {
1313
+ audio.load();
1314
+ if (videoRef.current) {
1315
+ audio.currentTime = videoRef.current.currentTime || 0;
1316
+ }
1317
+ }, 200);
1318
+ return;
1319
+ }
1320
+ if (!live.current.isMuted) {
1321
+ setUseIframeFallback(true);
1322
+ }
1323
+ }, []);
1324
+ useEffect(() => {
1325
+ if (useIframeFallback) return void 0;
1326
+ const video = videoRef.current;
1327
+ const audio = audioRef.current;
1328
+ const retryTimerIds = retryTimerIdsRef.current;
1329
+ if (!video) {
1330
+ setVideoElement(null);
1331
+ return void 0;
1332
+ }
1333
+ setVideoElement(video);
1334
+ const onSync = () => syncCompanionAudio(false);
1335
+ const onSeeked = () => syncCompanionAudio(true);
1336
+ for (const event of AUDIO_SYNC_EVENTS) {
1337
+ video.addEventListener(event, onSync);
1338
+ }
1339
+ video.addEventListener("seeked", onSeeked);
1340
+ const syncTimer = window.setInterval(onSync, 1e3);
1341
+ return () => {
1342
+ window.clearInterval(syncTimer);
1343
+ retryTimerIds.forEach((timerId) => window.clearTimeout(timerId));
1344
+ retryTimerIds.clear();
1345
+ for (const event of AUDIO_SYNC_EVENTS) {
1346
+ video.removeEventListener(event, onSync);
1347
+ }
1348
+ video.removeEventListener("seeked", onSeeked);
1349
+ try {
1350
+ video.pause();
1351
+ audio?.pause();
1352
+ } catch {
1353
+ }
1354
+ };
1355
+ }, [setVideoElement, syncCompanionAudio, useIframeFallback, videoStreamUrl]);
1356
+ useEffect(() => {
1357
+ const video = videoRef.current;
1358
+ if (useIframeFallback || !video) return;
1359
+ applyVideoPlaybackState({
1360
+ isPlaying,
1361
+ playbackRate,
1362
+ setVideoPlaying,
1363
+ videoElement: video
1364
+ });
1365
+ syncCompanionAudio();
1366
+ }, [
1367
+ isPlaying,
1368
+ playbackRate,
1369
+ setVideoPlaying,
1370
+ syncCompanionAudio,
1371
+ useIframeFallback
1372
+ ]);
1373
+ useEffect(() => {
1374
+ const video = videoRef.current;
1375
+ if (useIframeFallback || !video) return;
1376
+ if (video.muted !== isMuted) setElementMuted(video, isMuted);
1377
+ syncCompanionAudio(true);
1378
+ }, [isMuted, syncCompanionAudio, useIframeFallback]);
1379
+ useYouTubeIframePlayer({
1380
+ enabled: useIframeFallback,
1381
+ hostRef: iframeHostRef,
1382
+ isLoop,
1383
+ isMuted,
1384
+ isPlaying,
1385
+ live,
1386
+ playbackRate,
1387
+ setIsBuffering,
1388
+ setIsFrameReady,
1389
+ setVideoElement,
1390
+ setVideoPlaying,
1391
+ shouldAutoPlay,
1392
+ startTime,
1393
+ videoId
1394
+ });
1395
+ const isCovered = !isFrameReady || useIframeFallback && !isPlaying;
1396
+ const showSpinnerOverlay = showSpinner && (!isFrameReady || isBuffering);
1397
+ return {
1398
+ useIframeFallback,
1399
+ isFrameReady,
1400
+ setIsBuffering,
1401
+ videoRef,
1402
+ audioRef,
1403
+ iframeHostRef,
1404
+ videoStreamUrl,
1405
+ audioStreamUrl,
1406
+ resolvedPoster,
1407
+ syncCompanionAudio,
1408
+ handleEnded,
1409
+ handleTimeUpdate,
1410
+ handlePlay,
1411
+ handlePlaying,
1412
+ handlePause,
1413
+ handleSeeked,
1414
+ handleCanPlay,
1415
+ handleLoadedMetadata,
1416
+ handleLoadedData,
1417
+ handleError,
1418
+ handleAudioError,
1419
+ isCovered,
1420
+ showSpinnerOverlay
1421
+ };
1422
+ }
1423
+ var YouTubeBackgroundPlayer = memo(function YouTubeBackgroundPlayer2({
1424
+ codec = "auto",
1425
+ corp = 0,
1426
+ endTime = 0,
1427
+ forceIframe = false,
1428
+ isLoop = false,
1429
+ isMuted = true,
1430
+ isPlaying = true,
1431
+ playbackRate = 1,
1432
+ posterUrl = null,
1433
+ quality = "1080p",
1434
+ setVideoElement,
1435
+ setVideoPlaying,
1436
+ shouldAutoPlay = true,
1437
+ showPoster = false,
1438
+ showSpinner = true,
1439
+ startTime = 0,
1440
+ theme,
1441
+ videoClasses,
1442
+ videoId,
1443
+ videoStyle
1444
+ }) {
1445
+ const {
1446
+ useIframeFallback,
1447
+ isFrameReady,
1448
+ setIsBuffering: _setIsBuffering,
1449
+ videoRef,
1450
+ audioRef,
1451
+ iframeHostRef,
1452
+ videoStreamUrl,
1453
+ audioStreamUrl,
1454
+ resolvedPoster,
1455
+ syncCompanionAudio: _syncCompanionAudio,
1456
+ handleEnded,
1457
+ handleTimeUpdate,
1458
+ handlePlay,
1459
+ handlePlaying,
1460
+ handlePause,
1461
+ handleSeeked,
1462
+ handleCanPlay,
1463
+ handleLoadedMetadata,
1464
+ handleLoadedData,
1465
+ handleError,
1466
+ handleAudioError,
1467
+ isCovered,
1468
+ showSpinnerOverlay
1469
+ } = useYouTubeBackgroundPlayerModel({
1470
+ codec,
1471
+ corp,
1472
+ endTime,
1473
+ forceIframe,
1474
+ isLoop,
1475
+ isMuted,
1476
+ isPlaying,
1477
+ playbackRate,
1478
+ posterUrl,
1479
+ quality,
1480
+ setVideoElement,
1481
+ setVideoPlaying,
1482
+ shouldAutoPlay,
1483
+ showPoster,
1484
+ showSpinner,
1485
+ startTime,
1486
+ videoClasses,
1487
+ videoId,
1488
+ videoStyle
1489
+ });
1490
+ return /* @__PURE__ */ jsxs("div", { className: theme.slots.youtube, children: [
1491
+ /* @__PURE__ */ jsx("div", { "data-visible": isCovered, className: theme.slots.youtubeCover }),
1492
+ /* @__PURE__ */ jsx(
1493
+ "div",
1494
+ {
1495
+ "data-visible": showSpinnerOverlay,
1496
+ className: theme.slots.youtubeSpinner,
1497
+ children: showSpinner ? /* @__PURE__ */ jsx(Spinner, { size: 30, className: theme.slots.youtubeSpinnerIcon }) : null
1498
+ }
1499
+ ),
1500
+ resolvedPoster ? /* @__PURE__ */ jsx(
1501
+ "div",
1502
+ {
1503
+ "data-visible": isCovered,
1504
+ className: theme.slots.youtubePoster,
1505
+ style: {
1506
+ backgroundImage: `url(${resolvedPoster})`,
1507
+ ...videoStyle
1508
+ }
1509
+ }
1510
+ ) : null,
1511
+ useIframeFallback && !isPlaying ? /* @__PURE__ */ jsx("div", { className: theme.slots.youtubeBlackout }) : null,
1512
+ useIframeFallback ? /* @__PURE__ */ jsx(
1513
+ "div",
1514
+ {
1515
+ "data-visible": isFrameReady,
1516
+ className: theme.slots.youtubeFrame,
1517
+ style: videoStyle,
1518
+ children: /* @__PURE__ */ jsx("div", { ref: iframeHostRef, className: theme.slots.youtubeHost })
1519
+ }
1520
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1521
+ /* @__PURE__ */ jsx(
1522
+ "video",
1523
+ {
1524
+ ref: videoRef,
1525
+ src: videoStreamUrl,
1526
+ "data-visible": isFrameReady,
1527
+ className: cn(videoClasses, theme.slots.youtubeVideo),
1528
+ preload: "auto",
1529
+ muted: isMuted,
1530
+ loop: isLoop,
1531
+ playsInline: true,
1532
+ style: videoStyle,
1533
+ onTimeUpdate: handleTimeUpdate,
1534
+ onEnded: handleEnded,
1535
+ onPlay: handlePlay,
1536
+ onWaiting: () => {
1537
+ _setIsBuffering(true);
1538
+ _syncCompanionAudio(false);
1539
+ },
1540
+ onPlaying: handlePlaying,
1541
+ onPause: handlePause,
1542
+ onSeeking: () => _setIsBuffering(true),
1543
+ onSeeked: handleSeeked,
1544
+ onCanPlay: handleCanPlay,
1545
+ onLoadedMetadata: handleLoadedMetadata,
1546
+ onLoadedData: handleLoadedData,
1547
+ onError: handleError
1548
+ }
1549
+ ),
1550
+ /* @__PURE__ */ jsx(
1551
+ "audio",
1552
+ {
1553
+ ref: audioRef,
1554
+ src: audioStreamUrl,
1555
+ preload: "auto",
1556
+ onCanPlay: () => _syncCompanionAudio(true),
1557
+ onError: handleAudioError
1558
+ }
1559
+ )
1560
+ ] })
1561
+ ] });
1562
+ });
1563
+ function useNativeVideoModel({
1564
+ corp,
1565
+ isLoop,
1566
+ isMuted,
1567
+ isPlaying,
1568
+ playbackRate,
1569
+ setVideoElement,
1570
+ setVideoPlaying,
1571
+ shouldAutoPlay,
1572
+ src,
1573
+ style: _style,
1574
+ className: _className
1575
+ }) {
1576
+ const videoRef = useRef(null);
1577
+ const handleEnded = useCallback(() => {
1578
+ const video = videoRef.current;
1579
+ if (!video) return;
1580
+ if (video.loop) {
1581
+ video.currentTime = 0;
1582
+ video.play().catch((error) => report("Background loop play", error, "warn"));
1583
+ return;
1584
+ }
1585
+ video.pause();
1586
+ setVideoPlaying(false);
1587
+ }, [setVideoPlaying]);
1588
+ const handleTimeUpdate = useCallback(() => {
1589
+ const video = videoRef.current;
1590
+ if (video?.duration && corp > 0 && video.currentTime >= video.duration - corp) {
1591
+ handleEnded();
1592
+ }
1593
+ }, [corp, handleEnded]);
1594
+ const handleLoadedData = () => {
1595
+ const video = videoRef.current;
1596
+ if (!video) return;
1597
+ video.playbackRate = playbackRate;
1598
+ if (!shouldAutoPlay) return;
1599
+ if (isMuted) video.muted = true;
1600
+ video.play().then(() => setVideoPlaying(true)).catch((error) => {
1601
+ report("Background autoplay", error, "warn");
1602
+ setVideoPlaying(false);
1603
+ });
1604
+ };
1605
+ useEffect(() => {
1606
+ const video = videoRef.current;
1607
+ setVideoElement(video);
1608
+ return () => {
1609
+ try {
1610
+ video?.pause();
1611
+ } catch {
1612
+ }
1613
+ };
1614
+ }, [src, setVideoElement]);
1615
+ useEffect(() => () => setVideoElement(null), [setVideoElement]);
1616
+ useEffect(() => {
1617
+ applyVideoPlaybackState({
1618
+ isPlaying,
1619
+ playbackRate,
1620
+ setVideoPlaying,
1621
+ videoElement: videoRef.current
1622
+ });
1623
+ }, [isPlaying, playbackRate, setVideoPlaying]);
1624
+ return { videoRef, handleEnded, handleTimeUpdate, handleLoadedData };
1625
+ }
1626
+ function NativeVideo({
1627
+ corp,
1628
+ isLoop,
1629
+ isMuted,
1630
+ isPlaying,
1631
+ playbackRate,
1632
+ setVideoElement,
1633
+ setVideoPlaying,
1634
+ shouldAutoPlay,
1635
+ src,
1636
+ style,
1637
+ className
1638
+ }) {
1639
+ const { videoRef, handleEnded, handleTimeUpdate, handleLoadedData } = useNativeVideoModel({
1640
+ corp,
1641
+ isLoop,
1642
+ isMuted,
1643
+ isPlaying,
1644
+ playbackRate,
1645
+ setVideoElement,
1646
+ setVideoPlaying,
1647
+ shouldAutoPlay,
1648
+ src,
1649
+ style,
1650
+ className
1651
+ });
1652
+ return /* @__PURE__ */ jsx(
1653
+ "video",
1654
+ {
1655
+ ref: videoRef,
1656
+ src,
1657
+ className,
1658
+ preload: "auto",
1659
+ muted: isMuted,
1660
+ loop: isLoop,
1661
+ playsInline: true,
1662
+ style,
1663
+ onTimeUpdate: handleTimeUpdate,
1664
+ onEnded: handleEnded,
1665
+ onLoadedData: handleLoadedData
1666
+ }
1667
+ );
1668
+ }
1669
+ var BackgroundGradients = memo(function BackgroundGradients2({
1670
+ count = 0,
1671
+ direction,
1672
+ color = DEFAULT_COLOR,
1673
+ theme
1674
+ }) {
1675
+ if (!count || count <= 0) return null;
1676
+ const opacity = Math.min(1, Math.max(0.2, count * 0.25));
1677
+ return /* @__PURE__ */ jsx(
1678
+ "div",
1679
+ {
1680
+ "data-side": direction,
1681
+ className: theme.slots.gradient,
1682
+ style: {
1683
+ ...theme.styles.gradient,
1684
+ opacity,
1685
+ background: generateBaseGradient(direction, color)
1686
+ }
1687
+ }
1688
+ );
1689
+ });
1690
+ var EdgeGradient = memo(function EdgeGradient2({
1691
+ direction,
1692
+ percent = 0,
1693
+ opacity = 0,
1694
+ color,
1695
+ theme
1696
+ }) {
1697
+ if (opacity <= 0) return null;
1698
+ return /* @__PURE__ */ jsx(
1699
+ "div",
1700
+ {
1701
+ "data-side": direction,
1702
+ className: theme.slots.edge,
1703
+ style: {
1704
+ width: `${Math.max(30, percent * 1.15)}%`,
1705
+ opacity,
1706
+ background: generateEdgeGradient(direction, color || DEFAULT_COLOR)
1707
+ }
1708
+ }
1709
+ );
1710
+ });
1711
+ var NoiseOverlay = memo(function NoiseOverlay2({
1712
+ opacity,
1713
+ blendMode,
1714
+ inlineStyle,
1715
+ maskImage,
1716
+ isFixed,
1717
+ theme
1718
+ }) {
1719
+ return /* @__PURE__ */ jsx(
1720
+ "div",
1721
+ {
1722
+ "data-position": isFixed ? "fixed" : "absolute",
1723
+ className: theme.slots.noise,
1724
+ style: {
1725
+ ...theme.styles.noise,
1726
+ ...typeof opacity === "number" ? { opacity } : {},
1727
+ ...typeof blendMode === "string" && blendMode.trim() ? { mixBlendMode: blendMode } : {},
1728
+ ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
1729
+ ...inlineStyle
1730
+ }
1731
+ }
1732
+ );
1733
+ });
1734
+ var SolidOverlay = memo(function SolidOverlay2({
1735
+ opacity = 0,
1736
+ color,
1737
+ transitionStyle,
1738
+ maskImage,
1739
+ theme
1740
+ }) {
1741
+ return /* @__PURE__ */ jsx(
1742
+ "div",
1743
+ {
1744
+ className: theme.slots.solid,
1745
+ style: {
1746
+ opacity,
1747
+ backgroundColor: color,
1748
+ ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
1749
+ ...transitionStyle
1750
+ }
1751
+ }
1752
+ );
1753
+ });
1754
+ function useBackgroundOverlayModel() {
1755
+ const {
1756
+ animation,
1757
+ className,
1758
+ fadeEdges,
1759
+ fit,
1760
+ hasBackground,
1761
+ image,
1762
+ imageStyle,
1763
+ isPlaying,
1764
+ isVideo,
1765
+ isYouTube,
1766
+ leftGradient: configuredLeftGradient,
1767
+ noiseStyle,
1768
+ overlay,
1769
+ overlayColor,
1770
+ overlayOpacity,
1771
+ position,
1772
+ rightGradient: configuredRightGradient,
1773
+ video,
1774
+ videoClassName,
1775
+ videoOptions,
1776
+ videoStyle,
1777
+ width
1778
+ } = useBackgroundState();
1779
+ const { setVideoElement, setVideoPlaying } = useBackgroundActions();
1780
+ const options = resolveVideoOptions(videoOptions);
1781
+ const { corp, isMuted, playbackRate } = options;
1782
+ const youtubeConfig = useMemo(
1783
+ () => isYouTube ? parseYouTubeUrlConfig(video) : null,
1784
+ [isYouTube, video]
1785
+ );
1786
+ const startTime = videoOptions?.startTime ?? youtubeConfig?.startTime ?? 0;
1787
+ const endTime = videoOptions?.endTime ?? youtubeConfig?.endTime ?? 0;
1788
+ const backgroundKey = isVideo ? youtubeConfig ? `youtube:${youtubeConfig.videoId}` : video : image;
1789
+ const backgroundMotion = useBackgroundMotion();
1790
+ const { reduced, tempo } = useMotionTokens();
1791
+ const motionConfig = useMemo(
1792
+ () => getBackgroundMotionConfig(
1793
+ backgroundMotion,
1794
+ retime(animation, { reduced, tempo })
1795
+ ),
1796
+ [animation, backgroundMotion, reduced, tempo]
1797
+ );
1798
+ const {
1799
+ baseStyle,
1800
+ leftGradient: styleLeft,
1801
+ rightGradient: styleRight
1802
+ } = useMemo(
1803
+ () => getVisualStyle((isVideo ? videoStyle : imageStyle) || {}),
1804
+ [imageStyle, isVideo, videoStyle]
1805
+ );
1806
+ const leftGradient = configuredLeftGradient ?? styleLeft;
1807
+ const rightGradient = configuredRightGradient ?? styleRight;
1808
+ const {
1809
+ opacity: noiseOpacity,
1810
+ mixBlendMode: noiseBlendMode,
1811
+ ...noiseInlineStyle
1812
+ } = noiseStyle || {};
1813
+ const overlayTransitionStyle = useMemo(
1814
+ () => ({
1815
+ transitionDelay: toCssDelay(motionConfig.transition.delay),
1816
+ transitionDuration: toCssDuration(
1817
+ motionConfig.transition.duration,
1818
+ backgroundMotion.transition.duration
1819
+ ),
1820
+ transitionProperty: "opacity",
1821
+ transitionTimingFunction: toCssEasing(motionConfig.transition.ease)
1822
+ }),
1823
+ [backgroundMotion.transition.duration, motionConfig.transition]
1824
+ );
1825
+ const rawWidth = width ?? videoOptions?.width ?? videoStyle?.width;
1826
+ const resolvedWidth = rawWidth === void 0 || rawWidth === null || rawWidth === "" ? void 0 : typeof rawWidth === "number" ? `${rawWidth}px` : String(rawWidth);
1827
+ const rawFit = fit ?? videoOptions?.fit ?? videoOptions?.objectFit;
1828
+ const theme = useTheme(backgroundTheme);
1829
+ const fitStyle = useMemo(
1830
+ () => rawFit && OBJECT_FITS.includes(rawFit) ? { objectFit: rawFit } : {},
1831
+ [rawFit]
1832
+ );
1833
+ const classNames = resolveVideoClassNames(
1834
+ videoClassName,
1835
+ className,
1836
+ videoOptions?.videoClassName,
1837
+ videoOptions?.className,
1838
+ videoStyle?.className
1839
+ );
1840
+ const hasCustomWidth = Boolean(resolvedWidth || classNames.width);
1841
+ const gradientSettings = useMemo(
1842
+ () => resolveGradientSettings({
1843
+ fadeEdges,
1844
+ hasWidth: hasCustomWidth,
1845
+ leftGradient,
1846
+ rightGradient
1847
+ }),
1848
+ [fadeEdges, hasCustomWidth, leftGradient, rightGradient]
1849
+ );
1850
+ const maskImage = useMemo(
1851
+ () => gradientSettings.enabled ? getEdgeFadeMask({
1852
+ color: overlayColor || DEFAULT_COLOR,
1853
+ leftPercent: gradientSettings.leftPercent,
1854
+ rightPercent: gradientSettings.rightPercent
1855
+ }) : void 0,
1856
+ [gradientSettings, overlayColor]
1857
+ );
1858
+ const framePosition = position === "left" || position === "right" ? position : "center";
1859
+ const videoClasses = cn(theme.slots.video, classNames.other);
1860
+ const objectPosition2 = baseStyle.objectPosition || position || void 0;
1861
+ const sharedVideoStyle = useMemo(
1862
+ () => ({
1863
+ ...classNames.objectStyle,
1864
+ ...fitStyle,
1865
+ ...objectPosition2 ? { objectPosition: objectPosition2 } : {},
1866
+ ...maskImage ? { WebkitMaskImage: maskImage, maskImage } : {},
1867
+ ...baseStyle
1868
+ }),
1869
+ [baseStyle, classNames.objectStyle, fitStyle, maskImage, objectPosition2]
1870
+ );
1871
+ const exitTransition = useMemo(
1872
+ () => getBackgroundExitTransition(backgroundMotion, motionConfig),
1873
+ [backgroundMotion, motionConfig]
1874
+ );
1875
+ return {
1876
+ className,
1877
+ hasBackground,
1878
+ image,
1879
+ isPlaying,
1880
+ isVideo,
1881
+ overlay,
1882
+ overlayColor,
1883
+ overlayOpacity,
1884
+ position,
1885
+ video,
1886
+ videoStyle,
1887
+ width,
1888
+ setVideoElement,
1889
+ setVideoPlaying,
1890
+ options,
1891
+ corp,
1892
+ isMuted,
1893
+ playbackRate,
1894
+ youtubeConfig,
1895
+ startTime,
1896
+ endTime,
1897
+ backgroundKey,
1898
+ motionConfig,
1899
+ baseStyle,
1900
+ leftGradient,
1901
+ rightGradient,
1902
+ noiseOpacity,
1903
+ noiseBlendMode,
1904
+ noiseInlineStyle,
1905
+ overlayTransitionStyle,
1906
+ resolvedWidth,
1907
+ classNames,
1908
+ hasCustomWidth,
1909
+ gradientSettings,
1910
+ maskImage,
1911
+ framePosition,
1912
+ videoClasses,
1913
+ sharedVideoStyle,
1914
+ exitTransition,
1915
+ theme
1916
+ };
1917
+ }
1918
+ function BackgroundOverlay() {
1919
+ const {
1920
+ hasBackground,
1921
+ image,
1922
+ isPlaying,
1923
+ isVideo,
1924
+ overlay,
1925
+ overlayColor,
1926
+ overlayOpacity,
1927
+ position,
1928
+ video,
1929
+ setVideoElement,
1930
+ setVideoPlaying,
1931
+ options,
1932
+ corp,
1933
+ isMuted,
1934
+ playbackRate,
1935
+ youtubeConfig,
1936
+ startTime,
1937
+ endTime,
1938
+ backgroundKey,
1939
+ motionConfig,
1940
+ baseStyle,
1941
+ leftGradient,
1942
+ rightGradient,
1943
+ noiseOpacity,
1944
+ noiseBlendMode,
1945
+ noiseInlineStyle,
1946
+ overlayTransitionStyle,
1947
+ resolvedWidth,
1948
+ classNames,
1949
+ hasCustomWidth,
1950
+ gradientSettings,
1951
+ maskImage,
1952
+ framePosition,
1953
+ videoClasses,
1954
+ sharedVideoStyle,
1955
+ exitTransition,
1956
+ theme
1957
+ } = useBackgroundOverlayModel();
1958
+ return /* @__PURE__ */ jsx(AnimatePresence, { mode: "sync", children: hasBackground && /* @__PURE__ */ jsxs(
1959
+ motion.div,
1960
+ {
1961
+ initial: motionConfig.initial,
1962
+ animate: motionConfig.animate,
1963
+ transition: motionConfig.transition,
1964
+ exit: { ...motionConfig.exit, transition: exitTransition },
1965
+ className: theme.slots.root,
1966
+ style: {
1967
+ willChange: "transform, opacity, filter",
1968
+ ...theme.styles.root
1969
+ },
1970
+ children: [
1971
+ isVideo ? /* @__PURE__ */ jsxs(
1972
+ "div",
1973
+ {
1974
+ "data-position": framePosition,
1975
+ "data-width": classNames.width || resolvedWidth ? void 0 : "full",
1976
+ className: cn(theme.slots.videoFrame, classNames.width),
1977
+ style: {
1978
+ ...theme.styles.videoFrame,
1979
+ ...resolvedWidth ? { width: resolvedWidth } : {}
1980
+ },
1981
+ children: [
1982
+ youtubeConfig ? /* @__PURE__ */ jsx(
1983
+ YouTubeBackgroundPlayer,
1984
+ {
1985
+ videoId: youtubeConfig.videoId,
1986
+ startTime,
1987
+ endTime,
1988
+ corp,
1989
+ isPlaying,
1990
+ isMuted,
1991
+ isLoop: options.isLoop,
1992
+ shouldAutoPlay: options.shouldAutoPlay,
1993
+ showPoster: options.showPoster,
1994
+ showSpinner: options.showSpinner,
1995
+ playbackRate,
1996
+ quality: options.quality,
1997
+ codec: options.codec,
1998
+ forceIframe: options.forceIframe,
1999
+ posterUrl: options.showPoster ? image || null : null,
2000
+ theme,
2001
+ videoClasses,
2002
+ videoStyle: sharedVideoStyle,
2003
+ setVideoElement,
2004
+ setVideoPlaying
2005
+ }
2006
+ ) : /* @__PURE__ */ jsx(
2007
+ NativeVideo,
2008
+ {
2009
+ src: video || void 0,
2010
+ className: videoClasses,
2011
+ style: sharedVideoStyle,
2012
+ corp,
2013
+ isLoop: options.isLoop,
2014
+ isMuted,
2015
+ isPlaying,
2016
+ playbackRate,
2017
+ shouldAutoPlay: options.shouldAutoPlay,
2018
+ setVideoElement,
2019
+ setVideoPlaying
2020
+ }
2021
+ ),
2022
+ /* @__PURE__ */ jsx(
2023
+ EdgeGradient,
2024
+ {
2025
+ theme,
2026
+ direction: "left",
2027
+ percent: gradientSettings.leftPercent,
2028
+ opacity: gradientSettings.leftOpacity,
2029
+ color: overlayColor
2030
+ }
2031
+ ),
2032
+ /* @__PURE__ */ jsx(
2033
+ EdgeGradient,
2034
+ {
2035
+ theme,
2036
+ direction: "right",
2037
+ percent: gradientSettings.rightPercent,
2038
+ opacity: gradientSettings.rightOpacity,
2039
+ color: overlayColor
2040
+ }
2041
+ ),
2042
+ hasCustomWidth && /* @__PURE__ */ jsx(
2043
+ NoiseOverlay,
2044
+ {
2045
+ theme,
2046
+ opacity: noiseOpacity,
2047
+ blendMode: noiseBlendMode,
2048
+ inlineStyle: noiseInlineStyle,
2049
+ maskImage
2050
+ }
2051
+ ),
2052
+ hasCustomWidth && overlay && /* @__PURE__ */ jsx(
2053
+ SolidOverlay,
2054
+ {
2055
+ theme,
2056
+ opacity: overlayOpacity,
2057
+ color: overlayColor,
2058
+ transitionStyle: overlayTransitionStyle,
2059
+ maskImage
2060
+ }
2061
+ )
2062
+ ]
2063
+ }
2064
+ ) : /* @__PURE__ */ jsx(
2065
+ "div",
2066
+ {
2067
+ className: theme.slots.image,
2068
+ style: {
2069
+ backgroundImage: image ? `url(${image})` : void 0,
2070
+ backgroundPosition: position,
2071
+ ...baseStyle
2072
+ }
2073
+ }
2074
+ ),
2075
+ (!isVideo || !hasCustomWidth) && /* @__PURE__ */ jsxs(Fragment, { children: [
2076
+ /* @__PURE__ */ jsx(
2077
+ BackgroundGradients,
2078
+ {
2079
+ theme,
2080
+ count: leftGradient,
2081
+ direction: "left",
2082
+ color: overlayColor
2083
+ }
2084
+ ),
2085
+ /* @__PURE__ */ jsx(
2086
+ BackgroundGradients,
2087
+ {
2088
+ theme,
2089
+ count: rightGradient,
2090
+ direction: "right",
2091
+ color: overlayColor
2092
+ }
2093
+ ),
2094
+ /* @__PURE__ */ jsx(
2095
+ NoiseOverlay,
2096
+ {
2097
+ theme,
2098
+ isFixed: true,
2099
+ opacity: noiseOpacity,
2100
+ blendMode: noiseBlendMode,
2101
+ inlineStyle: noiseInlineStyle
2102
+ }
2103
+ ),
2104
+ overlay && /* @__PURE__ */ jsx(
2105
+ SolidOverlay,
2106
+ {
2107
+ theme,
2108
+ opacity: overlayOpacity,
2109
+ color: overlayColor,
2110
+ transitionStyle: overlayTransitionStyle
2111
+ }
2112
+ )
2113
+ ] })
2114
+ ]
2115
+ },
2116
+ backgroundKey
2117
+ ) });
2118
+ }
2119
+ function selectPageBackground(background) {
2120
+ return background ? normalizeBackgroundInput(background) : null;
2121
+ }
2122
+ function useBackgroundPage(_slice, page) {
2123
+ const actions = useBackgroundActions();
2124
+ return useMemo(
2125
+ () => ({
2126
+ ...actions,
2127
+ set: (background) => page.set({ background })
2128
+ }),
2129
+ [actions, page]
2130
+ );
2131
+ }
2132
+ var backgroundModule = defineModule({
2133
+ id: "background",
2134
+ context: BackgroundContext,
2135
+ Provider: BackgroundProvider,
2136
+ Backdrop: BackgroundOverlay,
2137
+ uses: ["media"],
2138
+ registry: {
2139
+ cleanupDelayMs: 600,
2140
+ keyPolicy: "singleton",
2141
+ lifecycle: "immediate",
2142
+ singletonKey: BACKGROUND_REGISTRY_KEY
2143
+ },
2144
+ page: {
2145
+ select: (config) => selectPageBackground(config.background),
2146
+ entries: (slice) => [
2147
+ { key: BACKGROUND_REGISTRY_KEY, value: slice }
2148
+ ],
2149
+ use: useBackgroundPage
2150
+ }
2151
+ });
2152
+ function defineBackground(definition = {}) {
2153
+ const { id = "background", ...config } = typeof definition === "string" ? { image: definition } : definition;
2154
+ return Object.freeze({
2155
+ config,
2156
+ id,
2157
+ use: function useDefinedBackground(overrides = {}, options = {}) {
2158
+ const patch = typeof overrides === "string" ? { image: overrides } : overrides;
2159
+ return useBackground({ ...config, ...patch }, options);
2160
+ }
2161
+ });
2162
+ }
2163
+
2164
+ 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 };
2165
+ //# sourceMappingURL=chunk-CGHZSSFR.js.map
2166
+ //# sourceMappingURL=chunk-CGHZSSFR.js.map