@omerdlw/base-framework 1.0.0

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 (383) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/dist/atoms/button.d.ts +11 -0
  4. package/dist/atoms/button.d.ts.map +1 -0
  5. package/dist/atoms/icon.d.ts +15 -0
  6. package/dist/atoms/icon.d.ts.map +1 -0
  7. package/dist/atoms/index.d.ts +6 -0
  8. package/dist/atoms/index.d.ts.map +1 -0
  9. package/dist/atoms/index.js +169 -0
  10. package/dist/atoms/index.js.map +1 -0
  11. package/dist/atoms/spinner.d.ts +9 -0
  12. package/dist/atoms/spinner.d.ts.map +1 -0
  13. package/dist/atoms/tooltip.d.ts +18 -0
  14. package/dist/atoms/tooltip.d.ts.map +1 -0
  15. package/dist/error/boundary.d.ts +14 -0
  16. package/dist/error/boundary.d.ts.map +1 -0
  17. package/dist/error/constants.d.ts +18 -0
  18. package/dist/error/constants.d.ts.map +1 -0
  19. package/dist/error/index.d.ts +9 -0
  20. package/dist/error/index.d.ts.map +1 -0
  21. package/dist/error/index.js +688 -0
  22. package/dist/error/index.js.map +1 -0
  23. package/dist/error/listener.d.ts +2 -0
  24. package/dist/error/listener.d.ts.map +1 -0
  25. package/dist/error/reporter.d.ts +32 -0
  26. package/dist/error/reporter.d.ts.map +1 -0
  27. package/dist/error/theme.d.ts +3 -0
  28. package/dist/error/theme.d.ts.map +1 -0
  29. package/dist/error/types.d.ts +91 -0
  30. package/dist/error/types.d.ts.map +1 -0
  31. package/dist/error/utils.d.ts +21 -0
  32. package/dist/error/utils.d.ts.map +1 -0
  33. package/dist/events.d.ts +51 -0
  34. package/dist/events.d.ts.map +1 -0
  35. package/dist/events.js +88 -0
  36. package/dist/events.js.map +1 -0
  37. package/dist/hooks/index.d.ts +17 -0
  38. package/dist/hooks/index.d.ts.map +1 -0
  39. package/dist/hooks/index.js +804 -0
  40. package/dist/hooks/index.js.map +1 -0
  41. package/dist/hooks/types.d.ts +58 -0
  42. package/dist/hooks/types.d.ts.map +1 -0
  43. package/dist/hooks/use-async-action.d.ts +3 -0
  44. package/dist/hooks/use-async-action.d.ts.map +1 -0
  45. package/dist/hooks/use-click-outside.d.ts +3 -0
  46. package/dist/hooks/use-click-outside.d.ts.map +1 -0
  47. package/dist/hooks/use-controllable-state.d.ts +3 -0
  48. package/dist/hooks/use-controllable-state.d.ts.map +1 -0
  49. package/dist/hooks/use-debounce.d.ts +2 -0
  50. package/dist/hooks/use-debounce.d.ts.map +1 -0
  51. package/dist/hooks/use-fullscreen-state.d.ts +4 -0
  52. package/dist/hooks/use-fullscreen-state.d.ts.map +1 -0
  53. package/dist/hooks/use-global-event.d.ts +7 -0
  54. package/dist/hooks/use-global-event.d.ts.map +1 -0
  55. package/dist/hooks/use-hotkey.d.ts +4 -0
  56. package/dist/hooks/use-hotkey.d.ts.map +1 -0
  57. package/dist/hooks/use-intersection-observer.d.ts +4 -0
  58. package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
  59. package/dist/hooks/use-isomorphic-layout-effect.d.ts +3 -0
  60. package/dist/hooks/use-isomorphic-layout-effect.d.ts.map +1 -0
  61. package/dist/hooks/use-media-query.d.ts +2 -0
  62. package/dist/hooks/use-media-query.d.ts.map +1 -0
  63. package/dist/hooks/use-mounted.d.ts +2 -0
  64. package/dist/hooks/use-mounted.d.ts.map +1 -0
  65. package/dist/hooks/use-required-context.d.ts +3 -0
  66. package/dist/hooks/use-required-context.d.ts.map +1 -0
  67. package/dist/hooks/use-server-action.d.ts +4 -0
  68. package/dist/hooks/use-server-action.d.ts.map +1 -0
  69. package/dist/hooks/use-storage-state.d.ts +5 -0
  70. package/dist/hooks/use-storage-state.d.ts.map +1 -0
  71. package/dist/hooks/use-store.d.ts +3 -0
  72. package/dist/hooks/use-store.d.ts.map +1 -0
  73. package/dist/index.d.ts +12 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +20415 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/kernel/adapters.d.ts +5 -0
  78. package/dist/kernel/adapters.d.ts.map +1 -0
  79. package/dist/kernel/compose.d.ts +15 -0
  80. package/dist/kernel/compose.d.ts.map +1 -0
  81. package/dist/kernel/constants.d.ts +12 -0
  82. package/dist/kernel/constants.d.ts.map +1 -0
  83. package/dist/kernel/context-registry.d.ts +3 -0
  84. package/dist/kernel/context-registry.d.ts.map +1 -0
  85. package/dist/kernel/handlers.d.ts +3 -0
  86. package/dist/kernel/handlers.d.ts.map +1 -0
  87. package/dist/kernel/hooks.d.ts +7 -0
  88. package/dist/kernel/hooks.d.ts.map +1 -0
  89. package/dist/kernel/index.d.ts +14 -0
  90. package/dist/kernel/index.d.ts.map +1 -0
  91. package/dist/kernel/index.js +2109 -0
  92. package/dist/kernel/index.js.map +1 -0
  93. package/dist/kernel/installed.d.ts +21 -0
  94. package/dist/kernel/installed.d.ts.map +1 -0
  95. package/dist/kernel/module.d.ts +32 -0
  96. package/dist/kernel/module.d.ts.map +1 -0
  97. package/dist/kernel/operations.d.ts +21 -0
  98. package/dist/kernel/operations.d.ts.map +1 -0
  99. package/dist/kernel/page-controller.d.ts +8 -0
  100. package/dist/kernel/page-controller.d.ts.map +1 -0
  101. package/dist/kernel/provider.d.ts +18 -0
  102. package/dist/kernel/provider.d.ts.map +1 -0
  103. package/dist/kernel/runtime.d.ts +30 -0
  104. package/dist/kernel/runtime.d.ts.map +1 -0
  105. package/dist/kernel/schema.d.ts +13 -0
  106. package/dist/kernel/schema.d.ts.map +1 -0
  107. package/dist/kernel/store.d.ts +4 -0
  108. package/dist/kernel/store.d.ts.map +1 -0
  109. package/dist/kernel/types.d.ts +233 -0
  110. package/dist/kernel/types.d.ts.map +1 -0
  111. package/dist/kernel/utils.d.ts +20 -0
  112. package/dist/kernel/utils.d.ts.map +1 -0
  113. package/dist/modules/ambient/constants.d.ts +23 -0
  114. package/dist/modules/ambient/constants.d.ts.map +1 -0
  115. package/dist/modules/ambient/context.d.ts +10 -0
  116. package/dist/modules/ambient/context.d.ts.map +1 -0
  117. package/dist/modules/ambient/index.d.ts +6 -0
  118. package/dist/modules/ambient/index.d.ts.map +1 -0
  119. package/dist/modules/ambient/index.js +896 -0
  120. package/dist/modules/ambient/index.js.map +1 -0
  121. package/dist/modules/ambient/module.d.ts +12 -0
  122. package/dist/modules/ambient/module.d.ts.map +1 -0
  123. package/dist/modules/ambient/types.d.ts +84 -0
  124. package/dist/modules/ambient/types.d.ts.map +1 -0
  125. package/dist/modules/ambient/utils.d.ts +18 -0
  126. package/dist/modules/ambient/utils.d.ts.map +1 -0
  127. package/dist/modules/background/constants.d.ts +12 -0
  128. package/dist/modules/background/constants.d.ts.map +1 -0
  129. package/dist/modules/background/context.d.ts +13 -0
  130. package/dist/modules/background/context.d.ts.map +1 -0
  131. package/dist/modules/background/hooks.d.ts +119 -0
  132. package/dist/modules/background/hooks.d.ts.map +1 -0
  133. package/dist/modules/background/index.d.ts +7 -0
  134. package/dist/modules/background/index.d.ts.map +1 -0
  135. package/dist/modules/background/index.js +3195 -0
  136. package/dist/modules/background/index.js.map +1 -0
  137. package/dist/modules/background/module.d.ts +14 -0
  138. package/dist/modules/background/module.d.ts.map +1 -0
  139. package/dist/modules/background/motion.d.ts +13 -0
  140. package/dist/modules/background/motion.d.ts.map +1 -0
  141. package/dist/modules/background/overlay.d.ts +49 -0
  142. package/dist/modules/background/overlay.d.ts.map +1 -0
  143. package/dist/modules/background/types.d.ts +153 -0
  144. package/dist/modules/background/types.d.ts.map +1 -0
  145. package/dist/modules/background/utils.d.ts +56 -0
  146. package/dist/modules/background/utils.d.ts.map +1 -0
  147. package/dist/modules/background/youtube/iframe.d.ts +52 -0
  148. package/dist/modules/background/youtube/iframe.d.ts.map +1 -0
  149. package/dist/modules/background/youtube/parse.d.ts +17 -0
  150. package/dist/modules/background/youtube/parse.d.ts.map +1 -0
  151. package/dist/modules/context-menu/constants.d.ts +8 -0
  152. package/dist/modules/context-menu/constants.d.ts.map +1 -0
  153. package/dist/modules/context-menu/context.d.ts +16 -0
  154. package/dist/modules/context-menu/context.d.ts.map +1 -0
  155. package/dist/modules/context-menu/hooks.d.ts +31 -0
  156. package/dist/modules/context-menu/hooks.d.ts.map +1 -0
  157. package/dist/modules/context-menu/index.d.ts +6 -0
  158. package/dist/modules/context-menu/index.d.ts.map +1 -0
  159. package/dist/modules/context-menu/index.js +2008 -0
  160. package/dist/modules/context-menu/index.js.map +1 -0
  161. package/dist/modules/context-menu/module.d.ts +12 -0
  162. package/dist/modules/context-menu/module.d.ts.map +1 -0
  163. package/dist/modules/context-menu/motion.d.ts +9 -0
  164. package/dist/modules/context-menu/motion.d.ts.map +1 -0
  165. package/dist/modules/context-menu/overlay.d.ts +15 -0
  166. package/dist/modules/context-menu/overlay.d.ts.map +1 -0
  167. package/dist/modules/context-menu/resolver.d.ts +7 -0
  168. package/dist/modules/context-menu/resolver.d.ts.map +1 -0
  169. package/dist/modules/context-menu/state.d.ts +4 -0
  170. package/dist/modules/context-menu/state.d.ts.map +1 -0
  171. package/dist/modules/context-menu/types.d.ts +171 -0
  172. package/dist/modules/context-menu/types.d.ts.map +1 -0
  173. package/dist/modules/context-menu/utils.d.ts +16 -0
  174. package/dist/modules/context-menu/utils.d.ts.map +1 -0
  175. package/dist/modules/controls/constants.d.ts +7 -0
  176. package/dist/modules/controls/constants.d.ts.map +1 -0
  177. package/dist/modules/controls/hooks.d.ts +15 -0
  178. package/dist/modules/controls/hooks.d.ts.map +1 -0
  179. package/dist/modules/controls/index.d.ts +6 -0
  180. package/dist/modules/controls/index.d.ts.map +1 -0
  181. package/dist/modules/controls/index.js +1242 -0
  182. package/dist/modules/controls/index.js.map +1 -0
  183. package/dist/modules/controls/module.d.ts +12 -0
  184. package/dist/modules/controls/module.d.ts.map +1 -0
  185. package/dist/modules/controls/overlay.d.ts +2 -0
  186. package/dist/modules/controls/overlay.d.ts.map +1 -0
  187. package/dist/modules/controls/types.d.ts +86 -0
  188. package/dist/modules/controls/types.d.ts.map +1 -0
  189. package/dist/modules/controls/utils.d.ts +9 -0
  190. package/dist/modules/controls/utils.d.ts.map +1 -0
  191. package/dist/modules/dock/cards.d.ts +1035 -0
  192. package/dist/modules/dock/cards.d.ts.map +1 -0
  193. package/dist/modules/dock/constants.d.ts +157 -0
  194. package/dist/modules/dock/constants.d.ts.map +1 -0
  195. package/dist/modules/dock/context.d.ts +26 -0
  196. package/dist/modules/dock/context.d.ts.map +1 -0
  197. package/dist/modules/dock/hooks.d.ts +957 -0
  198. package/dist/modules/dock/hooks.d.ts.map +1 -0
  199. package/dist/modules/dock/hud.d.ts +43 -0
  200. package/dist/modules/dock/hud.d.ts.map +1 -0
  201. package/dist/modules/dock/index.d.ts +27 -0
  202. package/dist/modules/dock/index.d.ts.map +1 -0
  203. package/dist/modules/dock/index.js +12111 -0
  204. package/dist/modules/dock/index.js.map +1 -0
  205. package/dist/modules/dock/module.d.ts +71 -0
  206. package/dist/modules/dock/module.d.ts.map +1 -0
  207. package/dist/modules/dock/motion.d.ts +986 -0
  208. package/dist/modules/dock/motion.d.ts.map +1 -0
  209. package/dist/modules/dock/overlay.d.ts +79 -0
  210. package/dist/modules/dock/overlay.d.ts.map +1 -0
  211. package/dist/modules/dock/provider.d.ts +3 -0
  212. package/dist/modules/dock/provider.d.ts.map +1 -0
  213. package/dist/modules/dock/routing/breadcrumbs.d.ts +43 -0
  214. package/dist/modules/dock/routing/breadcrumbs.d.ts.map +1 -0
  215. package/dist/modules/dock/routing/continuity.d.ts +19 -0
  216. package/dist/modules/dock/routing/continuity.d.ts.map +1 -0
  217. package/dist/modules/dock/routing/guards.d.ts +21 -0
  218. package/dist/modules/dock/routing/guards.d.ts.map +1 -0
  219. package/dist/modules/dock/routing/navigation.d.ts +37 -0
  220. package/dist/modules/dock/routing/navigation.d.ts.map +1 -0
  221. package/dist/modules/dock/routing/transactions.d.ts +21 -0
  222. package/dist/modules/dock/routing/transactions.d.ts.map +1 -0
  223. package/dist/modules/dock/runtime/commands.d.ts +18 -0
  224. package/dist/modules/dock/runtime/commands.d.ts.map +1 -0
  225. package/dist/modules/dock/runtime/display.d.ts +36 -0
  226. package/dist/modules/dock/runtime/display.d.ts.map +1 -0
  227. package/dist/modules/dock/runtime/dock.d.ts +123 -0
  228. package/dist/modules/dock/runtime/dock.d.ts.map +1 -0
  229. package/dist/modules/dock/state.d.ts +22 -0
  230. package/dist/modules/dock/state.d.ts.map +1 -0
  231. package/dist/modules/dock/status/events.d.ts +37 -0
  232. package/dist/modules/dock/status/events.d.ts.map +1 -0
  233. package/dist/modules/dock/status/hooks.d.ts +6 -0
  234. package/dist/modules/dock/status/hooks.d.ts.map +1 -0
  235. package/dist/modules/dock/status/model.d.ts +65 -0
  236. package/dist/modules/dock/status/model.d.ts.map +1 -0
  237. package/dist/modules/dock/surface/context.d.ts +43 -0
  238. package/dist/modules/dock/surface/context.d.ts.map +1 -0
  239. package/dist/modules/dock/surface/definition.d.ts +38 -0
  240. package/dist/modules/dock/surface/definition.d.ts.map +1 -0
  241. package/dist/modules/dock/surface/hooks.d.ts +123 -0
  242. package/dist/modules/dock/surface/hooks.d.ts.map +1 -0
  243. package/dist/modules/dock/surface/machine.d.ts +75 -0
  244. package/dist/modules/dock/surface/machine.d.ts.map +1 -0
  245. package/dist/modules/dock/surface/stack.d.ts +38 -0
  246. package/dist/modules/dock/surface/stack.d.ts.map +1 -0
  247. package/dist/modules/dock/surface/view-model.d.ts +3 -0
  248. package/dist/modules/dock/surface/view-model.d.ts.map +1 -0
  249. package/dist/modules/dock/types.d.ts +1158 -0
  250. package/dist/modules/dock/types.d.ts.map +1 -0
  251. package/dist/modules/dock/utils.d.ts +93 -0
  252. package/dist/modules/dock/utils.d.ts.map +1 -0
  253. package/dist/modules/index.d.ts +12 -0
  254. package/dist/modules/index.d.ts.map +1 -0
  255. package/dist/modules/index.js +18020 -0
  256. package/dist/modules/index.js.map +1 -0
  257. package/dist/modules/loading/constants.d.ts +5 -0
  258. package/dist/modules/loading/constants.d.ts.map +1 -0
  259. package/dist/modules/loading/context.d.ts +13 -0
  260. package/dist/modules/loading/context.d.ts.map +1 -0
  261. package/dist/modules/loading/hooks.d.ts +6 -0
  262. package/dist/modules/loading/hooks.d.ts.map +1 -0
  263. package/dist/modules/loading/index.d.ts +7 -0
  264. package/dist/modules/loading/index.d.ts.map +1 -0
  265. package/dist/modules/loading/index.js +1256 -0
  266. package/dist/modules/loading/index.js.map +1 -0
  267. package/dist/modules/loading/module.d.ts +14 -0
  268. package/dist/modules/loading/module.d.ts.map +1 -0
  269. package/dist/modules/loading/overlay.d.ts +2 -0
  270. package/dist/modules/loading/overlay.d.ts.map +1 -0
  271. package/dist/modules/loading/types.d.ts +47 -0
  272. package/dist/modules/loading/types.d.ts.map +1 -0
  273. package/dist/modules/loading/utils.d.ts +4 -0
  274. package/dist/modules/loading/utils.d.ts.map +1 -0
  275. package/dist/modules/media/constants.d.ts +7 -0
  276. package/dist/modules/media/constants.d.ts.map +1 -0
  277. package/dist/modules/media/context.d.ts +6 -0
  278. package/dist/modules/media/context.d.ts.map +1 -0
  279. package/dist/modules/media/hooks.d.ts +3 -0
  280. package/dist/modules/media/hooks.d.ts.map +1 -0
  281. package/dist/modules/media/index.d.ts +8 -0
  282. package/dist/modules/media/index.d.ts.map +1 -0
  283. package/dist/modules/media/index.js +728 -0
  284. package/dist/modules/media/index.js.map +1 -0
  285. package/dist/modules/media/module.d.ts +11 -0
  286. package/dist/modules/media/module.d.ts.map +1 -0
  287. package/dist/modules/media/overlay.d.ts +9 -0
  288. package/dist/modules/media/overlay.d.ts.map +1 -0
  289. package/dist/modules/media/types.d.ts +77 -0
  290. package/dist/modules/media/types.d.ts.map +1 -0
  291. package/dist/modules/media/utils.d.ts +17 -0
  292. package/dist/modules/media/utils.d.ts.map +1 -0
  293. package/dist/modules/modal/constants.d.ts +20 -0
  294. package/dist/modules/modal/constants.d.ts.map +1 -0
  295. package/dist/modules/modal/context.d.ts +20 -0
  296. package/dist/modules/modal/context.d.ts.map +1 -0
  297. package/dist/modules/modal/hooks.d.ts +41 -0
  298. package/dist/modules/modal/hooks.d.ts.map +1 -0
  299. package/dist/modules/modal/index.d.ts +7 -0
  300. package/dist/modules/modal/index.d.ts.map +1 -0
  301. package/dist/modules/modal/index.js +2672 -0
  302. package/dist/modules/modal/index.js.map +1 -0
  303. package/dist/modules/modal/module.d.ts +12 -0
  304. package/dist/modules/modal/module.d.ts.map +1 -0
  305. package/dist/modules/modal/motion.d.ts +16 -0
  306. package/dist/modules/modal/motion.d.ts.map +1 -0
  307. package/dist/modules/modal/overlay.d.ts +4 -0
  308. package/dist/modules/modal/overlay.d.ts.map +1 -0
  309. package/dist/modules/modal/state.d.ts +4 -0
  310. package/dist/modules/modal/state.d.ts.map +1 -0
  311. package/dist/modules/modal/types.d.ts +109 -0
  312. package/dist/modules/modal/types.d.ts.map +1 -0
  313. package/dist/modules/modal/utils.d.ts +31 -0
  314. package/dist/modules/modal/utils.d.ts.map +1 -0
  315. package/dist/modules/notification/constants.d.ts +9 -0
  316. package/dist/modules/notification/constants.d.ts.map +1 -0
  317. package/dist/modules/notification/context.d.ts +7 -0
  318. package/dist/modules/notification/context.d.ts.map +1 -0
  319. package/dist/modules/notification/hooks.d.ts +10 -0
  320. package/dist/modules/notification/hooks.d.ts.map +1 -0
  321. package/dist/modules/notification/index.d.ts +7 -0
  322. package/dist/modules/notification/index.d.ts.map +1 -0
  323. package/dist/modules/notification/index.js +905 -0
  324. package/dist/modules/notification/index.js.map +1 -0
  325. package/dist/modules/notification/module.d.ts +11 -0
  326. package/dist/modules/notification/module.d.ts.map +1 -0
  327. package/dist/modules/notification/motion.d.ts +15 -0
  328. package/dist/modules/notification/motion.d.ts.map +1 -0
  329. package/dist/modules/notification/overlay.d.ts +3 -0
  330. package/dist/modules/notification/overlay.d.ts.map +1 -0
  331. package/dist/modules/notification/types.d.ts +57 -0
  332. package/dist/modules/notification/types.d.ts.map +1 -0
  333. package/dist/modules/notification/utils.d.ts +9 -0
  334. package/dist/modules/notification/utils.d.ts.map +1 -0
  335. package/dist/modules/theme.d.ts +3 -0
  336. package/dist/modules/theme.d.ts.map +1 -0
  337. package/dist/provider.d.ts +23 -0
  338. package/dist/provider.d.ts.map +1 -0
  339. package/dist/provider.js +1973 -0
  340. package/dist/provider.js.map +1 -0
  341. package/dist/result.d.ts +50 -0
  342. package/dist/result.d.ts.map +1 -0
  343. package/dist/result.js +163 -0
  344. package/dist/result.js.map +1 -0
  345. package/dist/theme.d.ts +25 -0
  346. package/dist/theme.d.ts.map +1 -0
  347. package/dist/theme.js +44 -0
  348. package/dist/theme.js.map +1 -0
  349. package/dist/tokens/index.d.ts +3 -0
  350. package/dist/tokens/index.d.ts.map +1 -0
  351. package/dist/tokens/index.js +325 -0
  352. package/dist/tokens/index.js.map +1 -0
  353. package/dist/tokens/motion.d.ts +315 -0
  354. package/dist/tokens/motion.d.ts.map +1 -0
  355. package/dist/tokens/tokens.d.ts +34 -0
  356. package/dist/tokens/tokens.d.ts.map +1 -0
  357. package/dist/utils/cn.d.ts +3 -0
  358. package/dist/utils/cn.d.ts.map +1 -0
  359. package/dist/utils/dom.d.ts +5 -0
  360. package/dist/utils/dom.d.ts.map +1 -0
  361. package/dist/utils/index.d.ts +16 -0
  362. package/dist/utils/index.d.ts.map +1 -0
  363. package/dist/utils/index.js +485 -0
  364. package/dist/utils/index.js.map +1 -0
  365. package/dist/utils/json.d.ts +3 -0
  366. package/dist/utils/json.d.ts.map +1 -0
  367. package/dist/utils/number.d.ts +4 -0
  368. package/dist/utils/number.d.ts.map +1 -0
  369. package/dist/utils/object.d.ts +7 -0
  370. package/dist/utils/object.d.ts.map +1 -0
  371. package/dist/utils/report.d.ts +5 -0
  372. package/dist/utils/report.d.ts.map +1 -0
  373. package/dist/utils/scheduler.d.ts +34 -0
  374. package/dist/utils/scheduler.d.ts.map +1 -0
  375. package/dist/utils/store.d.ts +11 -0
  376. package/dist/utils/store.d.ts.map +1 -0
  377. package/dist/utils/string.d.ts +8 -0
  378. package/dist/utils/string.d.ts.map +1 -0
  379. package/dist/utils/timing.d.ts +8 -0
  380. package/dist/utils/timing.d.ts.map +1 -0
  381. package/dist/utils/user-message.d.ts +20 -0
  382. package/dist/utils/user-message.d.ts.map +1 -0
  383. package/package.json +113 -0
@@ -0,0 +1,3195 @@
1
+ "use client";
2
+ import { memo, createContext, useState, useRef, useEffect, useMemo, useCallback, useSyncExternalStore, use, useInsertionEffect, useLayoutEffect, useId, useContext, isValidElement, cloneElement, Children } from 'react';
3
+ import { clsx } from 'clsx';
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
+ import '@radix-ui/react-tooltip';
8
+ import { AnimatePresence, motion } from 'motion/react';
9
+ import { usePathname } from 'next/navigation';
10
+
11
+ function cn(...inputs) {
12
+ return twMerge(clsx(inputs));
13
+ }
14
+
15
+ // src/utils/string.ts
16
+ function trimToNull(value) {
17
+ if (value === null || value === void 0) return null;
18
+ const trimmed = String(value).trim();
19
+ return trimmed.length > 0 ? trimmed : null;
20
+ }
21
+
22
+ // src/utils/dom.ts
23
+ var isBrowser = typeof window !== "undefined";
24
+
25
+ // src/utils/object.ts
26
+ function isObject(value) {
27
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
28
+ }
29
+ function report(scope, error, level = "error") {
30
+ if (process.env.NODE_ENV === "production" && typeof window !== "undefined") {
31
+ return;
32
+ }
33
+ console[level](`[${scope}]`, error);
34
+ }
35
+
36
+ // src/utils/store.ts
37
+ function freezeStoreSnapshot(state) {
38
+ if (process.env.NODE_ENV === "production" || !state || typeof state !== "object") {
39
+ return state;
40
+ }
41
+ const seen = /* @__PURE__ */ new WeakSet();
42
+ const freeze = (value) => {
43
+ if (seen.has(value) || Object.isFrozen(value)) return;
44
+ seen.add(value);
45
+ const prototype = Object.getPrototypeOf(value);
46
+ if (Array.isArray(value) || prototype === Object.prototype || prototype === null) {
47
+ for (const key of Reflect.ownKeys(value)) {
48
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
49
+ if (descriptor && "value" in descriptor && descriptor.value !== null) {
50
+ if (typeof descriptor.value === "object") freeze(descriptor.value);
51
+ }
52
+ }
53
+ }
54
+ Object.freeze(value);
55
+ };
56
+ freeze(state);
57
+ return state;
58
+ }
59
+ function createStore(initialState, { freezeSnapshots = true } = {}) {
60
+ const listeners = /* @__PURE__ */ new Set();
61
+ const prepare = freezeSnapshots ? freezeStoreSnapshot : (state) => state;
62
+ let snapshot = prepare(initialState);
63
+ const publish = (nextStateOrUpdater) => {
64
+ const nextState = typeof nextStateOrUpdater === "function" ? nextStateOrUpdater(snapshot) : nextStateOrUpdater;
65
+ if (Object.is(snapshot, nextState)) return false;
66
+ snapshot = prepare(nextState);
67
+ for (const listener of listeners) {
68
+ try {
69
+ listener();
70
+ } catch (error) {
71
+ report("CoreStore subscriber", error, "warn");
72
+ }
73
+ }
74
+ return true;
75
+ };
76
+ const setState = (updater) => {
77
+ if (typeof updater === "function") {
78
+ return publish(updater);
79
+ }
80
+ if (snapshot && typeof snapshot === "object" && updater && typeof updater === "object") {
81
+ return publish({ ...snapshot, ...updater });
82
+ }
83
+ return publish(updater);
84
+ };
85
+ return Object.freeze({
86
+ getSnapshot() {
87
+ return snapshot;
88
+ },
89
+ publish,
90
+ setState,
91
+ subscribe(listener) {
92
+ if (typeof listener !== "function") return () => {
93
+ };
94
+ listeners.add(listener);
95
+ return () => listeners.delete(listener);
96
+ }
97
+ });
98
+ }
99
+ function Icon({
100
+ className = "center",
101
+ color,
102
+ icon,
103
+ onClick,
104
+ size = 20,
105
+ style,
106
+ ...props
107
+ }) {
108
+ return /* @__PURE__ */ jsx(
109
+ Icon$1,
110
+ {
111
+ className,
112
+ height: size,
113
+ icon,
114
+ onClick,
115
+ style: { color, ...style },
116
+ width: size,
117
+ ...props
118
+ }
119
+ );
120
+ }
121
+ Icon.displayName = "Icon";
122
+ function Spinner({ className = "", size = 15 }) {
123
+ return /* @__PURE__ */ jsx(
124
+ "div",
125
+ {
126
+ className,
127
+ "aria-label": "Loading",
128
+ role: "status",
129
+ children: /* @__PURE__ */ jsx(Icon, { icon: "mingcute:loading-3-fill", size })
130
+ }
131
+ );
132
+ }
133
+ Spinner.displayName = "Spinner";
134
+
135
+ // src/tokens/motion.ts
136
+ var DURATION_TOKENS = Object.freeze({
137
+ INSTANT: 0.08,
138
+ MICRO: 0.18,
139
+ FAST: 0.28,
140
+ BASE: 0.36,
141
+ MODERATE: 0.44,
142
+ SLOW: 0.58,
143
+ CINEMATIC: 0.86
144
+ });
145
+ var EASING_CURVES = Object.freeze({
146
+ OUT_EXPO: [0.16, 1, 0.3, 1],
147
+ OUT_QUART: [0.25, 1, 0.5, 1],
148
+ OUT_QUINT: [0.22, 1, 0.36, 1],
149
+ IN_OUT_CUBIC: [0.65, 0, 0.35, 1],
150
+ IN_CUBIC: [0.5, 0, 1, 1],
151
+ OUT_BACK: [0.34, 1.56, 0.64, 1]
152
+ });
153
+ var MOTION_EASINGS = Object.freeze({
154
+ ENTER: EASING_CURVES.OUT_QUART,
155
+ ENTER_EMPHASIZED: EASING_CURVES.OUT_EXPO,
156
+ EXIT: EASING_CURVES.IN_CUBIC
157
+ });
158
+ Object.freeze({
159
+ MICRO: Object.freeze({
160
+ distance: 4,
161
+ duration: DURATION_TOKENS.MICRO,
162
+ ease: MOTION_EASINGS.ENTER_EMPHASIZED,
163
+ scaleDelta: 8e-3
164
+ }),
165
+ FAST: Object.freeze({
166
+ distance: 9,
167
+ duration: DURATION_TOKENS.FAST,
168
+ ease: MOTION_EASINGS.ENTER_EMPHASIZED,
169
+ scaleDelta: 0.012
170
+ }),
171
+ STANDARD: Object.freeze({
172
+ distance: 18,
173
+ duration: DURATION_TOKENS.MODERATE,
174
+ ease: MOTION_EASINGS.ENTER,
175
+ scaleDelta: 0.018
176
+ }),
177
+ SURFACE: Object.freeze({
178
+ distance: 28,
179
+ duration: DURATION_TOKENS.SLOW,
180
+ ease: MOTION_EASINGS.ENTER_EMPHASIZED,
181
+ scaleDelta: 0.024
182
+ })
183
+ });
184
+ Object.freeze({
185
+ duration: DURATION_TOKENS.INSTANT,
186
+ ease: "linear"
187
+ });
188
+ function getOrCreateGlobalContext(name, defaultValue) {
189
+ const sym = /* @__PURE__ */ Symbol.for(`@omerdlw/base-framework/context/${name}`);
190
+ const store = globalThis;
191
+ if (!store[sym]) {
192
+ store[sym] = createContext(defaultValue);
193
+ }
194
+ return store[sym];
195
+ }
196
+
197
+ // src/theme.tsx
198
+ function defineThemeSpec(id) {
199
+ return Object.freeze({ id });
200
+ }
201
+ var EMPTY = /* @__PURE__ */ new Map();
202
+ var ThemeContext = getOrCreateGlobalContext("ThemeContext", EMPTY);
203
+ function useTheme(spec) {
204
+ const config = useContext(ThemeContext).get(spec.id);
205
+ if (!config) {
206
+ throw new Error(
207
+ `Theme "${spec.id}" is missing. Add its theme file to src/config/ and list it in src/config/index.ts.`
208
+ );
209
+ }
210
+ return {
211
+ slots: config.slots,
212
+ styles: config.styles ?? {}
213
+ };
214
+ }
215
+
216
+ // src/modules/background/constants.ts
217
+ var DEFAULT_BACKGROUND = Object.freeze({
218
+ animation: null,
219
+ className: "",
220
+ fadeEdges: null,
221
+ fit: null,
222
+ image: null,
223
+ imageStyle: {},
224
+ isPlaying: false,
225
+ noiseStyle: {},
226
+ overlay: false,
227
+ overlayColor: "var(--black)",
228
+ overlayOpacity: 0,
229
+ position: "center",
230
+ video: null,
231
+ videoClassName: "",
232
+ videoElement: null,
233
+ videoOptions: {
234
+ autoplay: true,
235
+ className: "",
236
+ corp: 0,
237
+ loop: false,
238
+ muted: true,
239
+ playbackRate: 1,
240
+ width: null
241
+ },
242
+ videoStyle: {},
243
+ width: null
244
+ });
245
+ var objectFit = (value) => ({
246
+ objectFit: value
247
+ });
248
+ var objectPosition = (value) => ({
249
+ objectPosition: value
250
+ });
251
+ var BG_TOKEN_TO_OBJECT_STYLE = Object.freeze({
252
+ "bg-bottom": objectPosition("bottom"),
253
+ "bg-center": objectPosition("center"),
254
+ "bg-contain": objectFit("contain"),
255
+ "bg-cover": objectFit("cover"),
256
+ "bg-fill": objectFit("fill"),
257
+ "bg-left": objectPosition("left"),
258
+ "bg-left-bottom": objectPosition("left bottom"),
259
+ "bg-left-top": objectPosition("left top"),
260
+ "bg-none": objectFit("none"),
261
+ "bg-right": objectPosition("right"),
262
+ "bg-right-bottom": objectPosition("right bottom"),
263
+ "bg-right-top": objectPosition("right top"),
264
+ "bg-scale-down": objectFit("scale-down"),
265
+ "bg-top": objectPosition("top")
266
+ });
267
+ var OBJECT_FITS = Object.freeze([
268
+ "contain",
269
+ "cover",
270
+ "fill",
271
+ "none",
272
+ "scale-down"
273
+ ]);
274
+ var DEFAULT_COLOR = "var(--black, #000)";
275
+ var backgroundTheme = defineThemeSpec("background");
276
+ var BACKGROUND_REGISTRY_KEY = "page-background";
277
+ var BACKGROUND_MEDIA_ID = "background";
278
+
279
+ // src/modules/background/youtube/parse.ts
280
+ var YOUTUBE_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/;
281
+ function parseYouTubeTimeParam(value) {
282
+ if (value === void 0 || value === null || value === "") return 0;
283
+ if (typeof value === "number") {
284
+ return Number.isFinite(value) && value >= 0 ? value : 0;
285
+ }
286
+ const trimmed = String(value).trim().toLowerCase();
287
+ if (!trimmed) return 0;
288
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
289
+ return Math.max(0, parseFloat(trimmed));
290
+ }
291
+ const hmsMatch = trimmed.match(
292
+ /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s?)?$/
293
+ );
294
+ if (hmsMatch && (hmsMatch[1] || hmsMatch[2] || hmsMatch[3])) {
295
+ const hours = parseInt(hmsMatch[1] || "0", 10);
296
+ const minutes = parseInt(hmsMatch[2] || "0", 10);
297
+ const seconds = parseFloat(hmsMatch[3] || "0");
298
+ return Math.max(0, hours * 3600 + minutes * 60 + seconds);
299
+ }
300
+ return 0;
301
+ }
302
+ var YOUTUBE_HOST_PATH = /^(?:www\.|m\.|music\.)?(?:youtube\.com|youtu\.be|youtube-nocookie\.com)\//i;
303
+ function toUrl(input, { youtubeOnly = false } = {}) {
304
+ let candidate = null;
305
+ if (/^https?:\/\//.test(input)) candidate = input;
306
+ else if (input.startsWith("//")) candidate = `https:${input}`;
307
+ else if (!youtubeOnly || YOUTUBE_HOST_PATH.test(input)) {
308
+ candidate = `https://${input}`;
309
+ }
310
+ try {
311
+ return candidate ? new URL(candidate) : null;
312
+ } catch {
313
+ return null;
314
+ }
315
+ }
316
+ function getIdFromUrl(url) {
317
+ const host = url.hostname.replace(/^(www\.|m\.|music\.)/i, "").toLowerCase();
318
+ const segments = url.pathname.split("/").filter(Boolean);
319
+ if (host === "youtu.be") {
320
+ return YOUTUBE_ID_PATTERN.test(segments[0] ?? "") ? segments[0] : null;
321
+ }
322
+ if (host !== "youtube.com" && host !== "youtube-nocookie.com" && !host.endsWith(".youtube.com")) {
323
+ return null;
324
+ }
325
+ const fromQuery = url.searchParams.get("v") || url.searchParams.get("vi");
326
+ if (fromQuery && YOUTUBE_ID_PATTERN.test(fromQuery)) return fromQuery;
327
+ const isVideoPath = segments.length >= 2 && ["embed", "shorts", "live", "v", "e", "watch"].includes(
328
+ segments[0].toLowerCase()
329
+ );
330
+ return isVideoPath && YOUTUBE_ID_PATTERN.test(segments[1]) ? segments[1] : null;
331
+ }
332
+ function extractYouTubeVideoId(input, options = {}) {
333
+ const trimmed = typeof input === "string" ? input.trim() : "";
334
+ if (!trimmed) return null;
335
+ if (options.allowBareId && YOUTUBE_ID_PATTERN.test(trimmed)) return trimmed;
336
+ const prefixed = trimmed.match(/^(?:youtube|yt):([a-zA-Z0-9_-]{11})$/i);
337
+ if (prefixed) return prefixed[1];
338
+ const url = toUrl(trimmed, { youtubeOnly: true });
339
+ return url ? getIdFromUrl(url) : null;
340
+ }
341
+ function isYouTubeUrl(input) {
342
+ return Boolean(extractYouTubeVideoId(input));
343
+ }
344
+ function isDirectVideoUrl(input) {
345
+ if (!input || typeof input !== "string") return false;
346
+ const trimmed = input.trim();
347
+ if (!trimmed) return false;
348
+ if (isYouTubeUrl(trimmed)) return true;
349
+ if (trimmed.startsWith("/api/background/youtube") || trimmed.startsWith("blob:")) {
350
+ return true;
351
+ }
352
+ const cleanPath = trimmed.split("?")[0].split("#")[0].toLowerCase();
353
+ return /\.(mp4|webm|mov|m4v|ogg|ogv|m3u8)$/i.test(cleanPath);
354
+ }
355
+ function parseYouTubeUrlConfig(input, options = {}) {
356
+ const videoId = extractYouTubeVideoId(input, options);
357
+ if (!videoId || !input) return null;
358
+ const params = toUrl(input.trim())?.searchParams;
359
+ return {
360
+ endTime: parseYouTubeTimeParam(params?.get("end")),
361
+ listId: params?.get("list") || null,
362
+ rawUrl: input,
363
+ startTime: parseYouTubeTimeParam(params?.get("t") || params?.get("start")),
364
+ videoId
365
+ };
366
+ }
367
+ function getYouTubeStreamUrl(videoId, options = {}) {
368
+ const params = new URLSearchParams();
369
+ params.set("id", videoId);
370
+ params.set("stream", options.stream || "video");
371
+ if (options.quality) params.set("quality", options.quality);
372
+ if (options.codec) params.set("codec", options.codec);
373
+ return `/api/background/youtube?${params.toString()}`;
374
+ }
375
+ function getYouTubeThumbnailUrl(videoId, proxied = true) {
376
+ if (proxied) {
377
+ return `/api/background/youtube?id=${encodeURIComponent(videoId)}&stream=thumbnail`;
378
+ }
379
+ return `https://i.ytimg.com/vi/${encodeURIComponent(videoId)}/maxresdefault.jpg`;
380
+ }
381
+ function createYouTubeVideoElementProxy(controller) {
382
+ const proxyVideo = document.createElement("video");
383
+ Object.defineProperties(proxyVideo, {
384
+ currentTime: {
385
+ configurable: true,
386
+ get: () => controller.getCurrentTime(),
387
+ set: (value) => {
388
+ controller.seekTo(Number(value) || 0);
389
+ proxyVideo.dispatchEvent(new Event("timeupdate"));
390
+ }
391
+ },
392
+ duration: {
393
+ configurable: true,
394
+ get: () => controller.getDuration()
395
+ },
396
+ loop: {
397
+ configurable: true,
398
+ get: () => controller.getLoop(),
399
+ set: (value) => {
400
+ controller.setLoop(Boolean(value));
401
+ }
402
+ },
403
+ muted: {
404
+ configurable: true,
405
+ get: () => controller.getMuted(),
406
+ set: (value) => {
407
+ controller.setMuted(Boolean(value));
408
+ proxyVideo.dispatchEvent(new Event("volumechange"));
409
+ }
410
+ },
411
+ pause: {
412
+ configurable: true,
413
+ value: () => {
414
+ controller.pause();
415
+ proxyVideo.dispatchEvent(new Event("pause"));
416
+ }
417
+ },
418
+ paused: {
419
+ configurable: true,
420
+ get: () => controller.getPaused()
421
+ },
422
+ play: {
423
+ configurable: true,
424
+ value: () => controller.play().then(() => {
425
+ proxyVideo.dispatchEvent(new Event("play"));
426
+ proxyVideo.dispatchEvent(new Event("playing"));
427
+ })
428
+ },
429
+ playbackRate: {
430
+ configurable: true,
431
+ get: () => controller.getPlaybackRate(),
432
+ set: (value) => {
433
+ controller.setPlaybackRate(Number(value) || 1);
434
+ proxyVideo.dispatchEvent(new Event("ratechange"));
435
+ }
436
+ },
437
+ volume: {
438
+ configurable: true,
439
+ get: () => controller.getVolume(),
440
+ set: (value) => {
441
+ const clamped = Math.max(0, Math.min(1, Number(value) || 0));
442
+ controller.setVolume(clamped);
443
+ proxyVideo.dispatchEvent(new Event("volumechange"));
444
+ }
445
+ }
446
+ });
447
+ return proxyVideo;
448
+ }
449
+
450
+ // src/modules/background/utils.ts
451
+ var WIDTH_CLASS = /^(w-|max-w-|min-w-)/;
452
+ function resolveVideoClassNames(...inputs) {
453
+ const tokens = inputs.flatMap(
454
+ (input) => typeof input === "string" ? input.replace(/,/g, " ").split(/\s+/) : []
455
+ ).filter(Boolean);
456
+ return {
457
+ objectStyle: Object.assign(
458
+ {},
459
+ ...tokens.map((token) => BG_TOKEN_TO_OBJECT_STYLE[token])
460
+ ),
461
+ other: tokens.filter((token) => !WIDTH_CLASS.test(token)).join(" "),
462
+ width: tokens.filter((token) => WIDTH_CLASS.test(token)).join(" ")
463
+ };
464
+ }
465
+ function resolveVideoOptions(options = {}) {
466
+ return {
467
+ codec: options.codec || "auto",
468
+ corp: options.corp ?? 0,
469
+ forceIframe: Boolean(options.forceIframe),
470
+ isLoop: options.loop ?? false,
471
+ isMuted: options.muted ?? true,
472
+ playbackRate: options.playbackRate ?? 1,
473
+ quality: options.quality || "1080p",
474
+ shouldAutoPlay: options.autoplay ?? true,
475
+ showPoster: Boolean(options.showPoster),
476
+ showSpinner: options.showSpinner !== false
477
+ };
478
+ }
479
+ function normalizeBackgroundInput(patch = {}) {
480
+ if (!patch) return {};
481
+ if (typeof patch === "string") {
482
+ const trimmed = patch.trim();
483
+ if (isYouTubeUrl(trimmed) || isDirectVideoUrl(trimmed)) {
484
+ return { image: null, video: trimmed };
485
+ }
486
+ return { image: trimmed };
487
+ }
488
+ const nextPatch = { ...patch };
489
+ if (typeof nextPatch.image === "string" && isYouTubeUrl(nextPatch.image) && !nextPatch.video) {
490
+ nextPatch.video = nextPatch.image;
491
+ nextPatch.image = null;
492
+ }
493
+ return nextPatch;
494
+ }
495
+ function mergeBackgroundState(baseState, patch = {}) {
496
+ const resolvedPatch = normalizeBackgroundInput(patch);
497
+ const nextVideoOptions = {
498
+ ...baseState.videoOptions,
499
+ ...resolvedPatch.videoOptions || {}
500
+ };
501
+ const nextVideo = resolvedPatch.video !== void 0 ? resolvedPatch.video : baseState.video;
502
+ const shouldAutoPlay = nextVideoOptions.autoplay !== false;
503
+ const resolvedIsPlaying = resolvedPatch.isPlaying !== void 0 ? resolvedPatch.isPlaying : resolvedPatch.video !== void 0 && Boolean(nextVideo) ? shouldAutoPlay : baseState.isPlaying;
504
+ return {
505
+ ...baseState,
506
+ ...resolvedPatch,
507
+ isPlaying: resolvedIsPlaying,
508
+ animation: resolvedPatch.animation !== void 0 ? resolvedPatch.animation ? {
509
+ ...baseState.animation || {},
510
+ ...resolvedPatch.animation
511
+ } : resolvedPatch.animation : baseState.animation,
512
+ imageStyle: {
513
+ ...baseState.imageStyle,
514
+ ...resolvedPatch.imageStyle || {}
515
+ },
516
+ noiseStyle: {
517
+ ...baseState.noiseStyle,
518
+ ...resolvedPatch.noiseStyle || {}
519
+ },
520
+ videoOptions: nextVideoOptions,
521
+ videoStyle: {
522
+ ...baseState.videoStyle,
523
+ ...resolvedPatch.videoStyle || {}
524
+ }
525
+ };
526
+ }
527
+ function selectPageBackground(background) {
528
+ return background ? normalizeBackgroundInput(background) : null;
529
+ }
530
+ var generateBaseGradient = (direction, color) => {
531
+ const to = direction === "left" ? "to right" : "to left";
532
+ 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%)`;
533
+ };
534
+ var generateEdgeGradient = (direction, color) => {
535
+ const to = direction === "left" ? "to right" : "to left";
536
+ 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%)`;
537
+ };
538
+ function getVisualStyle(currentStyle = {}) {
539
+ const {
540
+ className: _className,
541
+ leftGradient = 0,
542
+ rightGradient = 0,
543
+ ...baseStyle
544
+ } = currentStyle;
545
+ return {
546
+ baseStyle,
547
+ leftGradient: Number(leftGradient) || 0,
548
+ rightGradient: Number(rightGradient) || 0
549
+ };
550
+ }
551
+ function resolveGradientSettings({
552
+ fadeEdges = null,
553
+ hasWidth = false,
554
+ leftGradient = 0,
555
+ rightGradient = 0
556
+ }) {
557
+ let leftPercent = 0;
558
+ let rightPercent = 0;
559
+ if (leftGradient > 0)
560
+ leftPercent = Math.min(48, Math.max(12, leftGradient * 7.5));
561
+ else if (hasWidth && fadeEdges !== false) leftPercent = 20;
562
+ if (rightGradient > 0)
563
+ rightPercent = Math.min(48, Math.max(12, rightGradient * 7.5));
564
+ else if (hasWidth && fadeEdges !== false) rightPercent = 20;
565
+ if (typeof fadeEdges === "number") {
566
+ leftPercent = fadeEdges;
567
+ rightPercent = fadeEdges;
568
+ } else if (typeof fadeEdges === "string") {
569
+ const parsed = parseFloat(fadeEdges);
570
+ if (!Number.isNaN(parsed)) {
571
+ leftPercent = parsed;
572
+ rightPercent = parsed;
573
+ }
574
+ } else if (typeof fadeEdges === "object" && fadeEdges !== null) {
575
+ const edgeObj = fadeEdges;
576
+ if (edgeObj.left !== void 0)
577
+ leftPercent = parseFloat(String(edgeObj.left)) || 0;
578
+ if (edgeObj.right !== void 0)
579
+ rightPercent = parseFloat(String(edgeObj.right)) || 0;
580
+ } else if (fadeEdges === false) {
581
+ leftPercent = 0;
582
+ rightPercent = 0;
583
+ }
584
+ const leftOpacity = leftGradient > 0 ? Math.min(1, leftGradient * 0.22) : 0;
585
+ const rightOpacity = rightGradient > 0 ? Math.min(1, rightGradient * 0.22) : 0;
586
+ return {
587
+ enabled: leftPercent > 0 || rightPercent > 0,
588
+ leftOpacity,
589
+ leftPercent,
590
+ rightOpacity,
591
+ rightPercent
592
+ };
593
+ }
594
+ function generateSmoothstepStops(percent, direction = "in", color = "var(--black, #000)") {
595
+ const steps = [
596
+ { s: 0, t: 0 },
597
+ { s: 0.06, t: 0.15 },
598
+ { s: 0.22, t: 0.35 },
599
+ { s: 0.47, t: 0.55 },
600
+ { s: 0.76, t: 0.75 },
601
+ { s: 0.93, t: 0.9 },
602
+ { s: 1, t: 1 }
603
+ ];
604
+ if (direction === "in") {
605
+ return steps.map(
606
+ ({ 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)}%`
607
+ );
608
+ }
609
+ return steps.map(({ s, t }) => {
610
+ const alpha = 1 - s;
611
+ 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)}%`;
612
+ });
613
+ }
614
+ function getEdgeFadeMask({
615
+ color = "var(--black, #000)",
616
+ leftPercent = 0,
617
+ rightPercent = 0
618
+ }) {
619
+ if (leftPercent <= 0 && rightPercent <= 0) return void 0;
620
+ const leftStops = leftPercent > 0 ? generateSmoothstepStops(leftPercent, "in", color) : [`${color} 0%`];
621
+ const rightStops = rightPercent > 0 ? generateSmoothstepStops(rightPercent, "out", color) : [`${color} 100%`];
622
+ return `linear-gradient(to right, ${leftStops.join(", ")}, ${rightStops.join(", ")})`;
623
+ }
624
+ function applyVideoPlaybackState({
625
+ isPlaying,
626
+ playbackRate,
627
+ setVideoPlaying,
628
+ videoElement
629
+ }) {
630
+ if (!videoElement) return;
631
+ const numericPlaybackRate = Number(playbackRate);
632
+ const resolvedPlaybackRate = Number.isFinite(numericPlaybackRate) && numericPlaybackRate > 0 ? numericPlaybackRate : 1;
633
+ try {
634
+ if (videoElement.playbackRate !== resolvedPlaybackRate) {
635
+ videoElement.playbackRate = resolvedPlaybackRate;
636
+ }
637
+ } catch {
638
+ return;
639
+ }
640
+ if (!isPlaying) {
641
+ if (!videoElement.paused) videoElement.pause();
642
+ return;
643
+ }
644
+ if (videoElement.readyState === 0) {
645
+ return;
646
+ }
647
+ const playPromise = videoElement.play();
648
+ if (!playPromise || typeof playPromise.then !== "function") return;
649
+ playPromise.then(() => setVideoPlaying(true)).catch((error) => {
650
+ if (error?.name === "AbortError" || videoElement.readyState < 2) {
651
+ return;
652
+ }
653
+ if (error?.name === "NotAllowedError") {
654
+ videoElement.muted = true;
655
+ videoElement.play().then(() => setVideoPlaying(true)).catch(() => {
656
+ });
657
+ return;
658
+ }
659
+ setVideoPlaying(false);
660
+ });
661
+ }
662
+ function triggerVideoPlaybackDirect(videoElement, nextPlaying, configuredMuted) {
663
+ if (!videoElement) return;
664
+ if (nextPlaying) {
665
+ videoElement.muted = configuredMuted;
666
+ if (!configuredMuted && videoElement.volume === 0) {
667
+ videoElement.volume = 0.8;
668
+ }
669
+ videoElement.play().catch((err2) => {
670
+ if (err2?.name === "NotAllowedError") {
671
+ videoElement.muted = true;
672
+ videoElement.play().catch(() => {
673
+ });
674
+ }
675
+ });
676
+ } else {
677
+ videoElement.pause();
678
+ }
679
+ }
680
+ function syncVideoMutedDirect(videoElement, nextMuted) {
681
+ if (!videoElement) return;
682
+ videoElement.muted = nextMuted;
683
+ if (!nextMuted && videoElement.volume === 0) {
684
+ videoElement.volume = 0.8;
685
+ }
686
+ }
687
+ function syncVideoLoopDirect(videoElement, nextLoop) {
688
+ if (!videoElement) return;
689
+ videoElement.loop = nextLoop;
690
+ }
691
+
692
+ // src/modules/background/motion.ts
693
+ var DEFAULT_MOTION = Object.freeze({
694
+ animate: Object.freeze({
695
+ opacity: 1
696
+ }),
697
+ exit: Object.freeze({
698
+ opacity: 0,
699
+ transition: Object.freeze({
700
+ duration: DURATION_TOKENS.SLOW,
701
+ ease: EASING_CURVES.IN_CUBIC
702
+ })
703
+ }),
704
+ initial: Object.freeze({
705
+ opacity: 0
706
+ }),
707
+ transition: Object.freeze({
708
+ delay: 0,
709
+ duration: DURATION_TOKENS.SLOW,
710
+ ease: EASING_CURVES.OUT_QUART
711
+ })
712
+ });
713
+ function getBackgroundMotionConfig(animation) {
714
+ return {
715
+ animate: animation?.animate ?? DEFAULT_MOTION.animate,
716
+ exit: animation?.exit ?? DEFAULT_MOTION.exit,
717
+ exitDurationFactor: Number(animation?.exitDurationFactor),
718
+ initial: animation?.initial ?? DEFAULT_MOTION.initial,
719
+ transition: animation?.transition ?? DEFAULT_MOTION.transition
720
+ };
721
+ }
722
+ function toCssDuration(seconds) {
723
+ const value = Number(seconds);
724
+ return `${Math.max(0, Number.isFinite(value) ? value : DURATION_TOKENS.SLOW) * 1e3}ms`;
725
+ }
726
+ function toCssDelay(seconds) {
727
+ const value = Number(seconds);
728
+ return `${Math.max(0, Number.isFinite(value) ? value : 0) * 1e3}ms`;
729
+ }
730
+ function toCssEasing(easing) {
731
+ if (Array.isArray(easing)) {
732
+ return `cubic-bezier(${easing.join(", ")})`;
733
+ }
734
+ if (typeof easing === "string" && easing.trim()) {
735
+ return easing;
736
+ }
737
+ return "ease";
738
+ }
739
+ function useRequiredContext(context, hookName, providerName) {
740
+ const value = use(context);
741
+ if (value === null) {
742
+ throw new Error(`${hookName} must be used within ${providerName}`);
743
+ }
744
+ return value;
745
+ }
746
+ function useStore(store, selector = (state) => state, isEqual = Object.is) {
747
+ const cacheRef = useRef({
748
+ isEqual: null,
749
+ selected: void 0,
750
+ selector: null,
751
+ snapshot: null
752
+ });
753
+ const getSelectedSnapshot = useCallback(() => {
754
+ const snapshot = store.getSnapshot();
755
+ const cache = cacheRef.current;
756
+ if (cache.snapshot === snapshot && cache.selector === selector && cache.isEqual === isEqual) {
757
+ return cache.selected;
758
+ }
759
+ const selected = selector(snapshot);
760
+ if (cache.snapshot !== null && cache.isEqual === isEqual && isEqual(cache.selected, selected)) {
761
+ cache.snapshot = snapshot;
762
+ cache.selector = selector;
763
+ return cache.selected;
764
+ }
765
+ cacheRef.current = {
766
+ isEqual,
767
+ selected,
768
+ selector,
769
+ snapshot
770
+ };
771
+ return selected;
772
+ }, [isEqual, selector, store]);
773
+ return useSyncExternalStore(
774
+ store.subscribe,
775
+ getSelectedSnapshot,
776
+ getSelectedSnapshot
777
+ );
778
+ }
779
+ var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
780
+ var EventEmitter = class {
781
+ events = /* @__PURE__ */ new Map();
782
+ debounceTimers = /* @__PURE__ */ new Map();
783
+ subscribe(event, callback) {
784
+ if (typeof event !== "string" || !event || typeof callback !== "function") {
785
+ return () => {
786
+ };
787
+ }
788
+ const listeners = this.events.get(event) || /* @__PURE__ */ new Set();
789
+ listeners.add(callback);
790
+ this.events.set(event, listeners);
791
+ return () => {
792
+ listeners.delete(callback);
793
+ if (listeners.size === 0) this.events.delete(event);
794
+ };
795
+ }
796
+ emit(event, payload) {
797
+ const listeners = this.events.get(event);
798
+ if (!listeners || listeners.size === 0) return;
799
+ const snapshot = Array.from(listeners);
800
+ for (const callback of snapshot) {
801
+ try {
802
+ callback(payload);
803
+ } catch (error) {
804
+ report(`Event listener (${String(event)})`, error);
805
+ }
806
+ }
807
+ }
808
+ emitDebounced(event, payload, waitMs = 100) {
809
+ const existing = this.debounceTimers.get(event);
810
+ if (existing) clearTimeout(existing);
811
+ const timer = setTimeout(() => {
812
+ this.debounceTimers.delete(event);
813
+ this.emit(event, payload);
814
+ }, waitMs);
815
+ this.debounceTimers.set(event, timer);
816
+ }
817
+ cancelDebounced(event) {
818
+ if (event) {
819
+ const timer = this.debounceTimers.get(event);
820
+ if (timer) {
821
+ clearTimeout(timer);
822
+ this.debounceTimers.delete(event);
823
+ }
824
+ } else {
825
+ for (const timer of this.debounceTimers.values()) {
826
+ clearTimeout(timer);
827
+ }
828
+ this.debounceTimers.clear();
829
+ }
830
+ }
831
+ unsubscribeAll(event) {
832
+ this.cancelDebounced(event);
833
+ if (event) this.events.delete(event);
834
+ else this.events.clear();
835
+ }
836
+ hasListeners(event) {
837
+ return Boolean(this.events.get(event)?.size);
838
+ }
839
+ getListenerCount(event) {
840
+ return this.events.get(event)?.size || 0;
841
+ }
842
+ getAllEvents() {
843
+ return [...this.events.keys()];
844
+ }
845
+ };
846
+ var GLOBAL_EVENTS_KEY = /* @__PURE__ */ Symbol.for("__base_framework_global_events__");
847
+ var _global = globalThis;
848
+ _global[GLOBAL_EVENTS_KEY] ?? (_global[GLOBAL_EVENTS_KEY] = new EventEmitter());
849
+
850
+ // src/kernel/constants.ts
851
+ var DEFAULT_SOURCE = "dynamic";
852
+ var REGISTRY_SOURCES = Object.freeze({
853
+ STATIC: "static",
854
+ DYNAMIC: "dynamic",
855
+ USER: "user"
856
+ });
857
+ var REGISTRY_LIFECYCLES = Object.freeze({
858
+ IMMEDIATE: "immediate",
859
+ GRACEFUL: "graceful",
860
+ PERSISTENT: "persistent",
861
+ ROUTE: "route"
862
+ });
863
+ var REGISTRY_VALIDATION_MODES = Object.freeze({
864
+ WARN: "warn",
865
+ STRICT: "strict"
866
+ });
867
+ var REGISTRY_METADATA_KEYS = Object.freeze([
868
+ "cleanup",
869
+ "cleanupDelayMs",
870
+ "instanceId",
871
+ "lifecycle",
872
+ "priority",
873
+ "source",
874
+ "scope",
875
+ "validation"
876
+ ]);
877
+ Object.freeze({
878
+ [REGISTRY_SOURCES.STATIC]: 100,
879
+ [REGISTRY_SOURCES.DYNAMIC]: 200,
880
+ [REGISTRY_SOURCES.USER]: 300
881
+ });
882
+ Object.freeze({
883
+ [REGISTRY_SOURCES.STATIC]: 10,
884
+ [REGISTRY_SOURCES.DYNAMIC]: 20,
885
+ [REGISTRY_SOURCES.USER]: 30
886
+ });
887
+ var REGISTRY_LIFECYCLE_VALUES = new Set(
888
+ Object.values(REGISTRY_LIFECYCLES)
889
+ );
890
+ var REGISTRY_METADATA_KEY_SET = new Set(
891
+ REGISTRY_METADATA_KEYS
892
+ );
893
+ var REGISTRY_SCOPE_KINDS = Object.freeze({
894
+ APP: "app",
895
+ SESSION: "session",
896
+ ROUTE: "route",
897
+ INSTANCE: "instance",
898
+ WORKSPACE: "workspace"
899
+ });
900
+ REGISTRY_SCOPE_KINDS.APP;
901
+
902
+ // src/kernel/utils.ts
903
+ function parseFiniteNumber(value) {
904
+ const parsed = Number(value);
905
+ return Number.isFinite(parsed) ? parsed : null;
906
+ }
907
+ function getValidString(value, fallback = null) {
908
+ return trimToNull(value) ?? fallback;
909
+ }
910
+
911
+ // src/kernel/schema.ts
912
+ function resolveLifecycle(metadata, fallback) {
913
+ const lifecycle = metadata?.lifecycle ?? metadata?.cleanup;
914
+ return lifecycle && REGISTRY_LIFECYCLE_VALUES.has(lifecycle) ? lifecycle : fallback;
915
+ }
916
+ function validateRegistryMetadata(metadata) {
917
+ if (metadata === void 0 || metadata === null)
918
+ return { issues: [], valid: true };
919
+ if (!isObject(metadata))
920
+ return { issues: ["registry metadata must be an object"], valid: false };
921
+ const issues = [];
922
+ Object.keys(metadata).forEach((key) => {
923
+ if (!REGISTRY_METADATA_KEY_SET.has(key))
924
+ issues.push(`unknown registry metadata field: ${key}`);
925
+ });
926
+ if (metadata.source !== void 0 && !getValidString(metadata.source))
927
+ issues.push("source must be a non-empty string");
928
+ if (metadata.instanceId !== void 0 && !getValidString(metadata.instanceId))
929
+ issues.push("instanceId must be a non-empty string");
930
+ if (metadata.scope !== void 0 && !getValidString(metadata.scope))
931
+ issues.push("scope must be a non-empty string");
932
+ if (metadata.priority !== void 0 && parseFiniteNumber(metadata.priority) === null)
933
+ issues.push("priority must be a finite number");
934
+ if (metadata.cleanupDelayMs !== void 0) {
935
+ const delay = parseFiniteNumber(metadata.cleanupDelayMs);
936
+ if (delay === null || delay < 0)
937
+ issues.push("cleanupDelayMs must be a non-negative finite number");
938
+ }
939
+ const lifecycle = metadata.lifecycle ?? metadata.cleanup;
940
+ if (lifecycle !== void 0 && !REGISTRY_LIFECYCLE_VALUES.has(String(lifecycle))) {
941
+ issues.push(
942
+ `lifecycle must be one of: ${[...REGISTRY_LIFECYCLE_VALUES].join(", ")}`
943
+ );
944
+ }
945
+ if (metadata.validation !== void 0 && !Object.values(REGISTRY_VALIDATION_MODES).includes(
946
+ metadata.validation
947
+ )) {
948
+ issues.push(
949
+ `validation must be one of: ${Object.values(REGISTRY_VALIDATION_MODES).join(", ")}`
950
+ );
951
+ }
952
+ return { issues, valid: issues.length === 0 };
953
+ }
954
+ function normalizeRegistryMetadata(metadata, {
955
+ defaultCleanupDelayMs = null,
956
+ defaultLifecycle = null,
957
+ defaultSource = DEFAULT_SOURCE
958
+ } = {}) {
959
+ const registryMeta = isObject(metadata) ? metadata : {};
960
+ const normalizedDefaultDelay = parseFiniteNumber(defaultCleanupDelayMs);
961
+ const fallbackCleanupDelayMs = normalizedDefaultDelay !== null && normalizedDefaultDelay >= 0 ? normalizedDefaultDelay : null;
962
+ const fallbackLifecycle = defaultLifecycle && REGISTRY_LIFECYCLE_VALUES.has(defaultLifecycle) ? defaultLifecycle : null;
963
+ const source = getValidString(registryMeta.source) || getValidString(defaultSource, DEFAULT_SOURCE) || DEFAULT_SOURCE;
964
+ const scope = getValidString(registryMeta.scope);
965
+ const priority = parseFiniteNumber(registryMeta.priority);
966
+ const lifecycle = resolveLifecycle(registryMeta, fallbackLifecycle);
967
+ const validation = isValidationMode(registryMeta.validation) ? registryMeta.validation : null;
968
+ const cleanupDelayCandidate = parseFiniteNumber(registryMeta.cleanupDelayMs);
969
+ let cleanupDelayMs = cleanupDelayCandidate !== null && cleanupDelayCandidate >= 0 ? cleanupDelayCandidate : fallbackCleanupDelayMs;
970
+ if (lifecycle === REGISTRY_LIFECYCLES.IMMEDIATE) {
971
+ cleanupDelayMs = 0;
972
+ } else if ((lifecycle === REGISTRY_LIFECYCLES.GRACEFUL || lifecycle === REGISTRY_LIFECYCLES.ROUTE) && cleanupDelayMs === null) {
973
+ cleanupDelayMs = fallbackCleanupDelayMs;
974
+ }
975
+ return {
976
+ cleanupDelayMs,
977
+ lifecycle,
978
+ priority,
979
+ registerOptions: {
980
+ ...priority !== null && { priority },
981
+ ...validation === REGISTRY_VALIDATION_MODES.STRICT && { validation },
982
+ ...scope && { scope }
983
+ },
984
+ source,
985
+ ...scope && { scope },
986
+ ...validation && { validation }
987
+ };
988
+ }
989
+ function isValidationMode(value) {
990
+ return Object.values(REGISTRY_VALIDATION_MODES).includes(value);
991
+ }
992
+ function pickRegistryMetadata(options) {
993
+ if (!isObject(options)) return {};
994
+ return Object.fromEntries(
995
+ REGISTRY_METADATA_KEYS.filter((key) => options[key] !== void 0).map(
996
+ (key) => [key, options[key]]
997
+ )
998
+ );
999
+ }
1000
+ function createNoopHandle(status = "rejected", reason = "unknown") {
1001
+ const handle = Object.assign(() => false, {
1002
+ active: false,
1003
+ dispose: () => false,
1004
+ instanceId: null,
1005
+ key: "",
1006
+ priority: 0,
1007
+ reason,
1008
+ source: "",
1009
+ status,
1010
+ type: "",
1011
+ update: () => handle,
1012
+ updatedAt: 0,
1013
+ validation: "warn"
1014
+ });
1015
+ return handle;
1016
+ }
1017
+ createNoopHandle();
1018
+ var RegistryContext = getOrCreateGlobalContext(
1019
+ "RegistryContext",
1020
+ null
1021
+ );
1022
+ function useRegistryActions() {
1023
+ return useRequiredContext(
1024
+ RegistryContext,
1025
+ "useRegistryActions",
1026
+ "RegistryProvider"
1027
+ ).actions;
1028
+ }
1029
+ function useRegistrySubscription() {
1030
+ return useRequiredContext(
1031
+ RegistryContext,
1032
+ "useRegistrySubscription",
1033
+ "RegistryProvider"
1034
+ ).subscription;
1035
+ }
1036
+ function useRegistryValue(type, key) {
1037
+ const { getSnapshot, subscribe } = useRegistrySubscription();
1038
+ const subscribeToKey = useCallback(
1039
+ (listener) => subscribe(type, key, listener),
1040
+ [key, subscribe, type]
1041
+ );
1042
+ const getValue = useCallback(
1043
+ () => getSnapshot(type, key),
1044
+ [getSnapshot, key, type]
1045
+ );
1046
+ return useSyncExternalStore(subscribeToKey, getValue, getValue);
1047
+ }
1048
+ var EMPTY_MODULES = Object.freeze([]);
1049
+ var ModuleHostContext = getOrCreateGlobalContext("ModuleHostContext", null);
1050
+ function selectModuleSlice(coreModule, config) {
1051
+ const slice = coreModule.page?.select ? coreModule.page.select(config) : config[coreModule.id];
1052
+ return slice ?? null;
1053
+ }
1054
+ function createModulePayload(modules, config, metadata = {}) {
1055
+ const payload = {};
1056
+ let hasSlices = false;
1057
+ for (const coreModule of modules) {
1058
+ if (!coreModule.page?.entries) continue;
1059
+ const slice = selectModuleSlice(coreModule, config);
1060
+ if (slice === null) continue;
1061
+ payload[coreModule.id] = slice;
1062
+ hasSlices = true;
1063
+ }
1064
+ if (!hasSlices) return null;
1065
+ return {
1066
+ ...payload,
1067
+ registry: {
1068
+ ...metadata,
1069
+ ...isObject(config.registry) ? config.registry : {}
1070
+ }
1071
+ };
1072
+ }
1073
+ function useInstalledModules() {
1074
+ return use(ModuleHostContext)?.modules ?? EMPTY_MODULES;
1075
+ }
1076
+
1077
+ // src/kernel/handlers.ts
1078
+ function isPersistentLifecycle(lifecycle) {
1079
+ return lifecycle === REGISTRY_LIFECYCLES.PERSISTENT;
1080
+ }
1081
+ function runRegistrationBatch(context, executor) {
1082
+ return typeof context.batch === "function" ? context.batch(executor) : executor(context);
1083
+ }
1084
+ function createEntryCleanupKey(type, key, source, instanceId, scope) {
1085
+ return JSON.stringify([
1086
+ "entry",
1087
+ type,
1088
+ key,
1089
+ scope ?? null,
1090
+ source,
1091
+ instanceId
1092
+ ]);
1093
+ }
1094
+ function getCleanupScope(context) {
1095
+ return context?.cleanupScope || /* @__PURE__ */ new Map();
1096
+ }
1097
+ function clearCleanupTimer(scope, cleanupKey) {
1098
+ const lifecycle = scope.get(cleanupKey);
1099
+ if (!lifecycle) return;
1100
+ lifecycle.cancelled = true;
1101
+ if (lifecycle.timerId !== null) clearTimeout(lifecycle.timerId);
1102
+ scope.delete(cleanupKey);
1103
+ }
1104
+ function scheduleCleanup(scope, cleanupKey, callback, delayMs) {
1105
+ clearCleanupTimer(scope, cleanupKey);
1106
+ const lifecycle = {
1107
+ cancelled: false,
1108
+ timerId: null
1109
+ };
1110
+ lifecycle.timerId = setTimeout(() => {
1111
+ if (lifecycle.cancelled || scope.get(cleanupKey) !== lifecycle) return;
1112
+ scope.delete(cleanupKey);
1113
+ callback();
1114
+ }, delayMs);
1115
+ scope.set(cleanupKey, lifecycle);
1116
+ }
1117
+ function collectModuleRegistrations(coreModule, slice, pageMetadata, context) {
1118
+ const definition = coreModule.registry;
1119
+ const toEntries = coreModule.page?.entries;
1120
+ if (!definition || !toEntries || slice == null || slice === false) return [];
1121
+ const type = coreModule.id;
1122
+ const items = Array.isArray(slice) ? slice : [slice];
1123
+ const registrations = [];
1124
+ for (const item of items) {
1125
+ if (item == null || item === false) continue;
1126
+ const itemMetadata = isObject(item) && isObject(item.registry) ? item.registry : {};
1127
+ const metadata = { ...pageMetadata, ...itemMetadata };
1128
+ if (metadata.validation === "strict" && !validateRegistryMetadata(metadata).valid) {
1129
+ continue;
1130
+ }
1131
+ const payload = isObject(item) ? Object.fromEntries(
1132
+ Object.entries(item).filter(([key]) => key !== "registry")
1133
+ ) : item;
1134
+ const { cleanupDelayMs, lifecycle, registerOptions, scope, source } = normalizeRegistryMetadata(metadata, {
1135
+ defaultCleanupDelayMs: definition.cleanupDelayMs ?? null,
1136
+ defaultLifecycle: definition.lifecycle,
1137
+ defaultSource: DEFAULT_SOURCE
1138
+ });
1139
+ for (const { key, value } of toEntries(payload, context) ?? []) {
1140
+ const validation = definition.validate?.(value);
1141
+ if (validation && !validation.valid) {
1142
+ report(`Registry ${type} config is invalid`, validation.issues, "warn");
1143
+ continue;
1144
+ }
1145
+ registrations.push({
1146
+ cleanupDelayMs,
1147
+ cleanupKey: createEntryCleanupKey(
1148
+ type,
1149
+ key,
1150
+ source,
1151
+ context.instanceId,
1152
+ scope
1153
+ ),
1154
+ key,
1155
+ lifecycle,
1156
+ registerOptions,
1157
+ scope,
1158
+ source,
1159
+ type,
1160
+ value
1161
+ });
1162
+ }
1163
+ }
1164
+ return registrations;
1165
+ }
1166
+ var NO_CLEANUP = () => {
1167
+ };
1168
+ function applyRegistryConfig(config, context) {
1169
+ const modules = context.modules ?? [];
1170
+ if (!config || modules.length === 0) return NO_CLEANUP;
1171
+ const pageMetadata = isObject(config.registry) ? config.registry : {};
1172
+ const slices = config;
1173
+ const registrations = modules.flatMap((coreModule) => {
1174
+ try {
1175
+ return collectModuleRegistrations(
1176
+ coreModule,
1177
+ slices[coreModule.id],
1178
+ pageMetadata,
1179
+ context
1180
+ );
1181
+ } catch (error) {
1182
+ report(`Registry apply (${coreModule.id})`, error);
1183
+ return [];
1184
+ }
1185
+ });
1186
+ if (registrations.length === 0) return NO_CLEANUP;
1187
+ const cleanupScope = getCleanupScope(context);
1188
+ const owner = (registration) => ({
1189
+ instanceId: context.instanceId,
1190
+ scope: registration.scope,
1191
+ source: registration.source
1192
+ });
1193
+ runRegistrationBatch(context, (queue) => {
1194
+ registrations.forEach(
1195
+ ({ cleanupKey, key, registerOptions, source, type, value }) => {
1196
+ clearCleanupTimer(cleanupScope, cleanupKey);
1197
+ queue.register(type, key, value, source, registerOptions);
1198
+ }
1199
+ );
1200
+ });
1201
+ return () => {
1202
+ const immediate = [];
1203
+ registrations.forEach((registration) => {
1204
+ if (isPersistentLifecycle(registration.lifecycle)) return;
1205
+ const { cleanupDelayMs, cleanupKey, key, type } = registration;
1206
+ if (typeof cleanupDelayMs === "number" && cleanupDelayMs > 0) {
1207
+ scheduleCleanup(
1208
+ cleanupScope,
1209
+ cleanupKey,
1210
+ () => context.unregister(type, key, owner(registration)),
1211
+ cleanupDelayMs
1212
+ );
1213
+ } else {
1214
+ immediate.push(registration);
1215
+ }
1216
+ });
1217
+ if (immediate.length === 0) return;
1218
+ runRegistrationBatch(context, (queue) => {
1219
+ immediate.forEach(
1220
+ (registration) => queue.unregister(
1221
+ registration.type,
1222
+ registration.key,
1223
+ owner(registration)
1224
+ )
1225
+ );
1226
+ });
1227
+ };
1228
+ }
1229
+
1230
+ // src/kernel/hooks.ts
1231
+ function withInstanceId(instanceId, sourceOrOptions, optionsArg) {
1232
+ if (typeof sourceOrOptions === "string") {
1233
+ return {
1234
+ optionsArg: { ...isObject(optionsArg) ? optionsArg : {}, instanceId },
1235
+ sourceOrOptions
1236
+ };
1237
+ }
1238
+ if (isObject(sourceOrOptions)) {
1239
+ return {
1240
+ optionsArg,
1241
+ sourceOrOptions: { ...sourceOrOptions, instanceId }
1242
+ };
1243
+ }
1244
+ return {
1245
+ optionsArg: void 0,
1246
+ sourceOrOptions: {
1247
+ ...isObject(optionsArg) ? optionsArg : {},
1248
+ instanceId
1249
+ }
1250
+ };
1251
+ }
1252
+ function withInstanceIdForUnregister(instanceId, sourceOrOptions) {
1253
+ if (typeof sourceOrOptions === "string") {
1254
+ return { instanceId, source: sourceOrOptions };
1255
+ }
1256
+ if (isObject(sourceOrOptions)) {
1257
+ return { ...sourceOrOptions, instanceId };
1258
+ }
1259
+ return { instanceId };
1260
+ }
1261
+ function resolveRegisterArgsWithInstance(instanceId, sourceOrOptions, optionsArg) {
1262
+ const input = withInstanceId(instanceId, sourceOrOptions, optionsArg);
1263
+ return [input.sourceOrOptions, input.optionsArg];
1264
+ }
1265
+ var MAX_STABILIZATION_DEPTH = 64;
1266
+ function createStableFunctionEntry(fn) {
1267
+ const entry = {
1268
+ current: fn,
1269
+ stable(...args) {
1270
+ return entry.current?.apply(this, args);
1271
+ }
1272
+ };
1273
+ return entry;
1274
+ }
1275
+ function isDirectRegistryComponentPath(path, componentSlices) {
1276
+ const match = /^config\.([^.[]+)\.[^.[]+$/.exec(path);
1277
+ return Boolean(match && componentSlices.has(match[1]));
1278
+ }
1279
+ function isReactNodeLike(value) {
1280
+ return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" || isValidElement(value);
1281
+ }
1282
+ function isStabilizableObject(value) {
1283
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !isValidElement(value);
1284
+ }
1285
+ function hasSameObjectKeys(previousValue, nextValue) {
1286
+ if (!isStabilizableObject(previousValue) || !isStabilizableObject(nextValue)) {
1287
+ return false;
1288
+ }
1289
+ const previousKeys = Object.keys(previousValue);
1290
+ const nextKeys = Object.keys(nextValue);
1291
+ if (previousKeys.length !== nextKeys.length) return false;
1292
+ return nextKeys.every(
1293
+ (key) => Object.prototype.hasOwnProperty.call(previousValue, key)
1294
+ );
1295
+ }
1296
+ function stabilizeRegistryValue(value, path, scope, previousValue, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
1297
+ if (depth > MAX_STABILIZATION_DEPTH) return value;
1298
+ if (typeof value === "function") {
1299
+ const isComponent = value.name && /^[A-Z]/.test(value.name);
1300
+ if (isComponent || isDirectRegistryComponentPath(path, scope.componentSlices)) {
1301
+ return value;
1302
+ }
1303
+ scope.usedPaths.add(path);
1304
+ let entry = scope.functionEntries.get(path);
1305
+ if (!entry) {
1306
+ entry = createStableFunctionEntry(value);
1307
+ scope.functionEntries.set(path, entry);
1308
+ } else {
1309
+ entry.current = value;
1310
+ }
1311
+ return entry.stable;
1312
+ }
1313
+ if (value && typeof value === "object") {
1314
+ if (seen.has(value)) return value;
1315
+ seen.add(value);
1316
+ }
1317
+ if (isValidElement(value)) {
1318
+ const nextProps = stabilizeRegistryValue(
1319
+ value.props,
1320
+ `${path}.props`,
1321
+ scope,
1322
+ isValidElement(previousValue) ? previousValue.props : void 0,
1323
+ seen,
1324
+ depth + 1
1325
+ );
1326
+ if (isValidElement(previousValue) && previousValue.type === value.type && previousValue.key === value.key && previousValue.props === nextProps) {
1327
+ return previousValue;
1328
+ }
1329
+ return cloneElement(value, nextProps);
1330
+ }
1331
+ if (Array.isArray(value)) {
1332
+ const nextValue = value.every(isReactNodeLike) ? Children.toArray(value) : value;
1333
+ const previousArray = Array.isArray(previousValue) ? previousValue : null;
1334
+ let hasChanged2 = !previousArray || previousArray.length !== nextValue.length;
1335
+ const stabilizedValue2 = nextValue.map((item, index) => {
1336
+ const nextItem = stabilizeRegistryValue(
1337
+ item,
1338
+ `${path}[${index}]`,
1339
+ scope,
1340
+ previousArray?.[index],
1341
+ seen,
1342
+ depth + 1
1343
+ );
1344
+ if (!previousArray || nextItem !== previousArray[index]) {
1345
+ hasChanged2 = true;
1346
+ }
1347
+ return nextItem;
1348
+ });
1349
+ return !hasChanged2 ? previousArray : stabilizedValue2;
1350
+ }
1351
+ if (typeof value !== "object" || value === null) {
1352
+ return value;
1353
+ }
1354
+ const source = value;
1355
+ const previousRecord = previousValue;
1356
+ const stabilizedValue = {};
1357
+ const canReusePrevious = hasSameObjectKeys(previousValue, value);
1358
+ let hasChanged = !canReusePrevious;
1359
+ Object.keys(source).forEach((key) => {
1360
+ const nextValue = stabilizeRegistryValue(
1361
+ source[key],
1362
+ `${path}.${key}`,
1363
+ scope,
1364
+ previousRecord?.[key],
1365
+ seen,
1366
+ depth + 1
1367
+ );
1368
+ stabilizedValue[key] = nextValue;
1369
+ if (!canReusePrevious || nextValue !== previousRecord?.[key]) {
1370
+ hasChanged = true;
1371
+ }
1372
+ });
1373
+ return !hasChanged ? previousValue : stabilizedValue;
1374
+ }
1375
+ function useAppliedRegistryConfig(payload, context, componentSlices) {
1376
+ const functionEntriesRef = useRef(/* @__PURE__ */ new Map());
1377
+ const appliedRef = useRef(null);
1378
+ useIsomorphicLayoutEffect(() => {
1379
+ const previous = appliedRef.current;
1380
+ if (previous && previous.payload === payload && previous.context === context) {
1381
+ return;
1382
+ }
1383
+ const functionEntries = functionEntriesRef.current;
1384
+ const usedPaths = /* @__PURE__ */ new Set();
1385
+ const config = stabilizeRegistryValue(
1386
+ payload,
1387
+ "config",
1388
+ { componentSlices, functionEntries, usedPaths },
1389
+ previous?.config
1390
+ );
1391
+ functionEntries.forEach((_entry, path) => {
1392
+ if (!usedPaths.has(path)) functionEntries.delete(path);
1393
+ });
1394
+ if (previous && previous.config === config && previous.context === context) {
1395
+ previous.payload = payload;
1396
+ return;
1397
+ }
1398
+ previous?.cleanup();
1399
+ appliedRef.current = {
1400
+ cleanup: applyRegistryConfig(config, context),
1401
+ config,
1402
+ context,
1403
+ payload
1404
+ };
1405
+ });
1406
+ useIsomorphicLayoutEffect(
1407
+ () => () => {
1408
+ appliedRef.current?.cleanup();
1409
+ appliedRef.current = null;
1410
+ },
1411
+ []
1412
+ );
1413
+ }
1414
+ function createRegistryApplyContext(actions, {
1415
+ cleanupScope = /* @__PURE__ */ new Map(),
1416
+ instanceId,
1417
+ modules = [],
1418
+ pathname
1419
+ }) {
1420
+ const stamp = (queue) => ({
1421
+ register: (type, key, item, sourceOrOptions, optionsArg) => queue.register(
1422
+ type,
1423
+ key,
1424
+ item,
1425
+ ...resolveRegisterArgsWithInstance(
1426
+ instanceId,
1427
+ sourceOrOptions,
1428
+ optionsArg
1429
+ )
1430
+ ),
1431
+ unregister: (type, key, sourceOrOptions) => queue.unregister(
1432
+ type,
1433
+ key,
1434
+ withInstanceIdForUnregister(instanceId, sourceOrOptions)
1435
+ )
1436
+ });
1437
+ return {
1438
+ ...stamp(actions),
1439
+ batch: (executor) => typeof executor === "function" ? actions.batch((queue) => executor(stamp(queue))) : 0,
1440
+ cleanupScope,
1441
+ instanceId,
1442
+ modules,
1443
+ pathname
1444
+ };
1445
+ }
1446
+ function useRegistry(config, metadata) {
1447
+ const { batch, register, unregister } = useRegistryActions();
1448
+ const pathname = usePathname();
1449
+ const modules = useInstalledModules();
1450
+ const instanceId = `registry-instance-${useId()}`;
1451
+ const [cleanupScope] = useState(
1452
+ () => /* @__PURE__ */ new Map()
1453
+ );
1454
+ const context = useMemo(
1455
+ () => createRegistryApplyContext(
1456
+ { batch, register, unregister },
1457
+ {
1458
+ cleanupScope,
1459
+ instanceId,
1460
+ modules,
1461
+ pathname
1462
+ }
1463
+ ),
1464
+ [batch, cleanupScope, instanceId, modules, pathname, register, unregister]
1465
+ );
1466
+ const payload = useMemo(
1467
+ () => config ? createModulePayload(modules, config, metadata) : null,
1468
+ [config, metadata, modules]
1469
+ );
1470
+ const componentSlices = useMemo(
1471
+ () => new Set(
1472
+ modules.filter(
1473
+ (coreModule) => coreModule.registry?.valueKind === "component"
1474
+ ).map((coreModule) => coreModule.id)
1475
+ ),
1476
+ [modules]
1477
+ );
1478
+ useAppliedRegistryConfig(payload, context, componentSlices);
1479
+ }
1480
+ function createPageControllerStore() {
1481
+ const listeners = /* @__PURE__ */ new Set();
1482
+ let stack = [];
1483
+ const notify = () => {
1484
+ listeners.forEach((listener) => {
1485
+ try {
1486
+ listener();
1487
+ } catch (error) {
1488
+ report("Page controller listener", error);
1489
+ }
1490
+ });
1491
+ };
1492
+ return {
1493
+ getSnapshot() {
1494
+ const top = stack[stack.length - 1];
1495
+ return top?.controllerRef?.current || null;
1496
+ },
1497
+ notify,
1498
+ register(id, controllerRef) {
1499
+ stack = stack.filter((item) => item.id !== id);
1500
+ stack.push({ controllerRef, id });
1501
+ notify();
1502
+ },
1503
+ subscribe(listener) {
1504
+ listeners.add(listener);
1505
+ return () => {
1506
+ listeners.delete(listener);
1507
+ };
1508
+ },
1509
+ unregister(id) {
1510
+ stack = stack.filter((item) => item.id !== id);
1511
+ notify();
1512
+ }
1513
+ };
1514
+ }
1515
+ var fallbackStandaloneStore = createPageControllerStore();
1516
+ getOrCreateGlobalContext(
1517
+ "PageControllerContext",
1518
+ null
1519
+ );
1520
+ getOrCreateGlobalContext(
1521
+ "PageControllerStoreContext",
1522
+ fallbackStandaloneStore
1523
+ );
1524
+ function defineModule(coreModule) {
1525
+ return Object.freeze({ ...coreModule });
1526
+ }
1527
+ function useModule(id) {
1528
+ const coreModule = use(ModuleHostContext)?.byId.get(id);
1529
+ return coreModule?.context ? use(coreModule.context) ?? null : null;
1530
+ }
1531
+ function definePeer(id, inert) {
1532
+ const useRuntime = () => useModule(id) ?? inert;
1533
+ return {
1534
+ useRuntime,
1535
+ useActions: () => useRuntime().actions,
1536
+ useState: (selector, isEqual) => useStore(
1537
+ useRuntime().store,
1538
+ selector,
1539
+ isEqual
1540
+ )
1541
+ };
1542
+ }
1543
+ createStore(void 0);
1544
+
1545
+ // src/kernel/adapters.tsx
1546
+ function useModuleRegistration(id, value, options) {
1547
+ const coreModule = useInstalledModules().find(
1548
+ (candidate) => candidate.id === id
1549
+ );
1550
+ const config = coreModule && options?.enabled !== false && value != null ? { [id]: value } : null;
1551
+ useRegistry(config, pickRegistryMetadata(options));
1552
+ }
1553
+ var BackgroundContext = getOrCreateGlobalContext(
1554
+ "BackgroundContext",
1555
+ null
1556
+ );
1557
+ var mediaPeer = definePeer("media", {
1558
+ actions: {
1559
+ removeSource: () => {
1560
+ },
1561
+ setMuted: () => {
1562
+ },
1563
+ toggle: () => {
1564
+ },
1565
+ toggleLoop: () => {
1566
+ },
1567
+ upsertSource: () => {
1568
+ }
1569
+ },
1570
+ store: createStore({
1571
+ audibleElement: null,
1572
+ element: null,
1573
+ hasMedia: false,
1574
+ isPlaying: false,
1575
+ kind: null,
1576
+ loop: false,
1577
+ sourceId: null
1578
+ })
1579
+ });
1580
+ function useBackgroundRegistration(config, options) {
1581
+ useModuleRegistration("background", config, options);
1582
+ }
1583
+ function useSafePathname() {
1584
+ try {
1585
+ return usePathname();
1586
+ } catch {
1587
+ return null;
1588
+ }
1589
+ }
1590
+ function resolveBackgroundState(registryBackground, override, pathname) {
1591
+ const base = registryBackground ? mergeBackgroundState(DEFAULT_BACKGROUND, registryBackground) : DEFAULT_BACKGROUND;
1592
+ const patch = override.pathname === pathname ? override.patch : null;
1593
+ return patch ? mergeBackgroundState(base, patch) : base;
1594
+ }
1595
+ function computeBackgroundState(background) {
1596
+ const youtubeVideoId = extractYouTubeVideoId(background.video);
1597
+ const isYouTube = Boolean(youtubeVideoId);
1598
+ const isVideo = Boolean(background.video || isYouTube);
1599
+ return {
1600
+ ...background,
1601
+ hasBackground: Boolean(
1602
+ background.image || isVideo || background.color || background.overlay || background.noiseStyle && (background.noiseStyle.opacity === void 0 || (background.noiseStyle.opacity ?? 0) > 0)
1603
+ ),
1604
+ isVideo,
1605
+ isYouTube,
1606
+ posterUrl: youtubeVideoId ? getYouTubeThumbnailUrl(youtubeVideoId) : null,
1607
+ youtubeVideoId
1608
+ };
1609
+ }
1610
+ function BackgroundProvider({ children }) {
1611
+ const pathname = useSafePathname();
1612
+ const registryBackground = useRegistryValue(
1613
+ "background",
1614
+ BACKGROUND_REGISTRY_KEY
1615
+ ) ?? null;
1616
+ const [overrideStore] = useState(
1617
+ () => createStore(
1618
+ { patch: null, pathname },
1619
+ { freezeSnapshots: false }
1620
+ )
1621
+ );
1622
+ const scopedOverride = useStore(overrideStore);
1623
+ const inputsRef = useRef({ pathname, registryBackground });
1624
+ useInsertionEffect(() => {
1625
+ inputsRef.current = { pathname, registryBackground };
1626
+ }, [pathname, registryBackground]);
1627
+ const videoElementRef = useRef(null);
1628
+ const state = useMemo(
1629
+ () => computeBackgroundState(
1630
+ resolveBackgroundState(registryBackground, scopedOverride, pathname)
1631
+ ),
1632
+ [pathname, registryBackground, scopedOverride]
1633
+ );
1634
+ const [stateStore] = useState(
1635
+ () => createStore(state, { freezeSnapshots: false })
1636
+ );
1637
+ useIsomorphicLayoutEffect(() => {
1638
+ stateStore.publish(state);
1639
+ }, [state, stateStore]);
1640
+ const actions = useMemo(() => {
1641
+ const readCurrent = () => {
1642
+ const { pathname: currentPath, registryBackground: registry } = inputsRef.current;
1643
+ return resolveBackgroundState(
1644
+ registry,
1645
+ overrideStore.getSnapshot(),
1646
+ currentPath
1647
+ );
1648
+ };
1649
+ const updatePatch = (updater) => {
1650
+ overrideStore.publish((prev) => {
1651
+ const { pathname: currentPath, registryBackground: registry } = inputsRef.current;
1652
+ const currentPatch = prev.pathname === currentPath ? prev.patch : null;
1653
+ const rawNext = updater(
1654
+ resolveBackgroundState(registry, prev, currentPath)
1655
+ );
1656
+ if (!rawNext || Object.keys(rawNext).length === 0) {
1657
+ return prev;
1658
+ }
1659
+ const normalizedNext = normalizeBackgroundInput(rawNext);
1660
+ const mergedPatch = {
1661
+ ...currentPatch || {},
1662
+ ...normalizedNext,
1663
+ ...currentPatch?.videoOptions || normalizedNext.videoOptions ? {
1664
+ videoOptions: {
1665
+ ...currentPatch?.videoOptions || {},
1666
+ ...normalizedNext.videoOptions || {}
1667
+ }
1668
+ } : {}
1669
+ };
1670
+ return {
1671
+ patch: mergedPatch,
1672
+ pathname: currentPath
1673
+ };
1674
+ });
1675
+ };
1676
+ const currentVideoElement = (current) => videoElementRef.current || current.videoElement;
1677
+ return {
1678
+ resetBackground: () => {
1679
+ overrideStore.publish({
1680
+ patch: null,
1681
+ pathname: inputsRef.current.pathname
1682
+ });
1683
+ },
1684
+ setBackground: (nextBackground) => {
1685
+ updatePatch(() => normalizeBackgroundInput(nextBackground));
1686
+ },
1687
+ setVideoElement: (videoElement2) => {
1688
+ videoElementRef.current = videoElement2;
1689
+ updatePatch(
1690
+ (cur) => cur.videoElement === videoElement2 ? {} : { videoElement: videoElement2 }
1691
+ );
1692
+ },
1693
+ setVideoMuted: (muted) => {
1694
+ const nextMuted = Boolean(muted);
1695
+ syncVideoMutedDirect(currentVideoElement(readCurrent()), nextMuted);
1696
+ updatePatch((cur) => {
1697
+ if (cur.videoOptions?.muted === nextMuted) return {};
1698
+ return {
1699
+ videoOptions: { ...cur.videoOptions, muted: nextMuted }
1700
+ };
1701
+ });
1702
+ },
1703
+ setVideoPlaying: (isPlaying2) => {
1704
+ updatePatch(
1705
+ (cur) => cur.isPlaying === isPlaying2 ? {} : { isPlaying: isPlaying2 }
1706
+ );
1707
+ },
1708
+ toggleLoop: () => {
1709
+ const current = readCurrent();
1710
+ const nextLoop = !current.videoOptions?.loop;
1711
+ syncVideoLoopDirect(currentVideoElement(current), nextLoop);
1712
+ updatePatch((cur) => ({
1713
+ videoOptions: { ...cur.videoOptions, loop: nextLoop }
1714
+ }));
1715
+ },
1716
+ toggleMute: () => {
1717
+ const current = readCurrent();
1718
+ const nextMuted = !current.videoOptions?.muted;
1719
+ syncVideoMutedDirect(currentVideoElement(current), nextMuted);
1720
+ updatePatch((cur) => ({
1721
+ isPlaying: nextMuted ? cur.isPlaying : true,
1722
+ videoOptions: { ...cur.videoOptions, muted: nextMuted }
1723
+ }));
1724
+ },
1725
+ toggleVideo: () => {
1726
+ const current = readCurrent();
1727
+ const videoEl = currentVideoElement(current);
1728
+ const domIsActuallyPlaying = videoEl ? !videoEl.paused && !videoEl.ended : Boolean(current.isPlaying);
1729
+ const nextPlaying = !domIsActuallyPlaying;
1730
+ const configuredMuted = Boolean(current.videoOptions?.muted);
1731
+ triggerVideoPlaybackDirect(videoEl, nextPlaying, configuredMuted);
1732
+ updatePatch(() => ({ isPlaying: nextPlaying }));
1733
+ }
1734
+ };
1735
+ }, [overrideStore]);
1736
+ const media = mediaPeer.useActions();
1737
+ const { isPlaying, isVideo, videoElement } = state;
1738
+ const isLoop = Boolean(state.videoOptions?.loop);
1739
+ useEffect(() => {
1740
+ if (!isVideo) {
1741
+ media.removeSource(BACKGROUND_MEDIA_ID);
1742
+ return;
1743
+ }
1744
+ media.upsertSource({
1745
+ controls: {
1746
+ setMuted: actions.setVideoMuted,
1747
+ toggle: actions.toggleVideo,
1748
+ toggleLoop: actions.toggleLoop
1749
+ },
1750
+ element: videoElement ?? null,
1751
+ id: BACKGROUND_MEDIA_ID,
1752
+ isPlaying,
1753
+ kind: "video",
1754
+ loop: isLoop
1755
+ });
1756
+ }, [actions, isLoop, isPlaying, isVideo, media, videoElement]);
1757
+ useEffect(() => () => media.removeSource(BACKGROUND_MEDIA_ID), [media]);
1758
+ const value = useMemo(
1759
+ () => ({ actions, store: stateStore }),
1760
+ [actions, stateStore]
1761
+ );
1762
+ return /* @__PURE__ */ jsx(BackgroundContext, { value, children });
1763
+ }
1764
+ function useBackgroundState() {
1765
+ const { store } = useRequiredContext(
1766
+ BackgroundContext,
1767
+ "useBackgroundState",
1768
+ "BackgroundProvider"
1769
+ );
1770
+ return useStore(store);
1771
+ }
1772
+ function useBackgroundActions() {
1773
+ return useRequiredContext(
1774
+ BackgroundContext,
1775
+ "useBackgroundActions",
1776
+ "BackgroundProvider"
1777
+ ).actions;
1778
+ }
1779
+ function useBackground(config, options) {
1780
+ useBackgroundRegistration(config, options);
1781
+ const actions = useBackgroundActions();
1782
+ const state = useBackgroundState();
1783
+ return useMemo(() => ({ ...state, ...actions }), [actions, state]);
1784
+ }
1785
+ var PLAYER_STATE = { ENDED: 0, PLAYING: 1, PAUSED: 2, BUFFERING: 3 };
1786
+ var apiPromise = null;
1787
+ function loadYouTubeIframeApi() {
1788
+ if (typeof window === "undefined") return Promise.resolve(null);
1789
+ if (window.YT?.Player) return Promise.resolve(window.YT);
1790
+ if (apiPromise) return apiPromise;
1791
+ apiPromise = new Promise((resolve) => {
1792
+ const previousCallback = window.onYouTubeIframeAPIReady;
1793
+ window.onYouTubeIframeAPIReady = () => {
1794
+ previousCallback?.();
1795
+ resolve(window.YT);
1796
+ };
1797
+ if (!document.querySelector(
1798
+ 'script[src="https://www.youtube.com/iframe_api"]'
1799
+ )) {
1800
+ const script = document.createElement("script");
1801
+ script.src = "https://www.youtube.com/iframe_api";
1802
+ script.async = true;
1803
+ document.head.appendChild(script);
1804
+ }
1805
+ });
1806
+ return apiPromise;
1807
+ }
1808
+ function setHighQuality(player) {
1809
+ player?.setPlaybackQualityRange?.("hd1080", "hd1080");
1810
+ player?.setPlaybackQuality?.("hd1080");
1811
+ }
1812
+ function useYouTubeIframePlayer({
1813
+ enabled,
1814
+ hostRef,
1815
+ isLoop,
1816
+ isMuted,
1817
+ isPlaying,
1818
+ live,
1819
+ playbackRate,
1820
+ setIsBuffering,
1821
+ setIsFrameReady,
1822
+ setVideoElement,
1823
+ setVideoPlaying,
1824
+ shouldAutoPlay,
1825
+ startTime,
1826
+ videoId
1827
+ }) {
1828
+ const playerRef = useRef(null);
1829
+ useEffect(() => {
1830
+ if (!enabled) return void 0;
1831
+ let isDisposed = false;
1832
+ let progressInterval = null;
1833
+ let proxyElement = null;
1834
+ const state = {
1835
+ currentTime: startTime || 0,
1836
+ duration: 0,
1837
+ loop: Boolean(isLoop),
1838
+ muted: Boolean(isMuted),
1839
+ paused: !shouldAutoPlay,
1840
+ playbackRate: Number(playbackRate) || 1,
1841
+ volume: isMuted ? 0 : 0.8
1842
+ };
1843
+ const player = () => playerRef.current;
1844
+ const restart = (target) => {
1845
+ const restartAt = Math.max(0, live.current.startTime || 0);
1846
+ target?.seekTo?.(restartAt, true);
1847
+ target?.playVideo?.();
1848
+ return restartAt;
1849
+ };
1850
+ const emit = (type) => proxyElement?.dispatchEvent(new Event(type));
1851
+ const trackProgress = () => {
1852
+ const current = player();
1853
+ if (!current || typeof current.getCurrentTime !== "function") return;
1854
+ const time = Number(current.getCurrentTime()) || 0;
1855
+ const duration = Number(current.getDuration?.()) || state.duration;
1856
+ state.currentTime = time;
1857
+ if (duration > 0 && duration !== state.duration) {
1858
+ state.duration = duration;
1859
+ emit("durationchange");
1860
+ }
1861
+ const { corp, endTime, isLoop: loops } = live.current;
1862
+ const safetyEnd = endTime > 0 ? endTime : duration > 0 ? duration - Math.max(corp, 0.4) : 0;
1863
+ if (safetyEnd > 0 && time >= safetyEnd) {
1864
+ if (state.loop || loops) {
1865
+ state.currentTime = restart(current);
1866
+ } else {
1867
+ current.pauseVideo?.();
1868
+ state.paused = true;
1869
+ setVideoPlaying(false);
1870
+ }
1871
+ }
1872
+ emit("timeupdate");
1873
+ };
1874
+ const handleReady = (event) => {
1875
+ if (isDisposed) return;
1876
+ const target = event.target;
1877
+ playerRef.current = target ?? null;
1878
+ state.duration = Number(target?.getDuration?.()) || 0;
1879
+ const { isMuted: muted, isPlaying: isPlaying2, playbackRate: rate } = live.current;
1880
+ if (rate !== 1) target?.setPlaybackRate?.(rate);
1881
+ if (muted) {
1882
+ target?.mute?.();
1883
+ } else {
1884
+ target?.unMute?.();
1885
+ target?.setVolume?.(80);
1886
+ }
1887
+ if (live.current.shouldAutoPlay && isPlaying2) {
1888
+ setHighQuality(target);
1889
+ target?.playVideo?.();
1890
+ state.paused = false;
1891
+ setVideoPlaying(true);
1892
+ }
1893
+ if (proxyElement) {
1894
+ setVideoElement(proxyElement);
1895
+ emit("loadedmetadata");
1896
+ emit("durationchange");
1897
+ }
1898
+ progressInterval = window.setInterval(trackProgress, 200);
1899
+ };
1900
+ const handleStateChange = (event) => {
1901
+ if (isDisposed) return;
1902
+ switch (event.data) {
1903
+ case PLAYER_STATE.PLAYING:
1904
+ setHighQuality(event.target);
1905
+ state.paused = false;
1906
+ setIsFrameReady(true);
1907
+ setIsBuffering(false);
1908
+ setVideoPlaying(true);
1909
+ emit("play");
1910
+ emit("playing");
1911
+ break;
1912
+ case PLAYER_STATE.BUFFERING:
1913
+ setIsBuffering(true);
1914
+ break;
1915
+ case PLAYER_STATE.PAUSED:
1916
+ state.paused = true;
1917
+ setIsBuffering(false);
1918
+ setVideoPlaying(false);
1919
+ emit("pause");
1920
+ break;
1921
+ case PLAYER_STATE.ENDED:
1922
+ if (state.loop || live.current.isLoop) {
1923
+ restart(player());
1924
+ } else {
1925
+ state.paused = true;
1926
+ setVideoPlaying(false);
1927
+ emit("ended");
1928
+ }
1929
+ break;
1930
+ }
1931
+ };
1932
+ loadYouTubeIframeApi().then((YT) => {
1933
+ const host = hostRef.current;
1934
+ if (isDisposed || !YT?.Player || !host) return;
1935
+ host.innerHTML = "";
1936
+ const mountTarget = document.createElement("div");
1937
+ host.appendChild(mountTarget);
1938
+ proxyElement = createYouTubeVideoElementProxy({
1939
+ getCurrentTime: () => state.currentTime,
1940
+ getDuration: () => state.duration,
1941
+ getLoop: () => state.loop,
1942
+ getMuted: () => state.muted,
1943
+ getPaused: () => state.paused,
1944
+ getPlaybackRate: () => state.playbackRate,
1945
+ getVolume: () => state.volume,
1946
+ pause: () => {
1947
+ state.paused = true;
1948
+ player()?.pauseVideo?.();
1949
+ setVideoPlaying(false);
1950
+ },
1951
+ play: async () => {
1952
+ state.paused = false;
1953
+ player()?.playVideo?.();
1954
+ setVideoPlaying(true);
1955
+ },
1956
+ seekTo: (seconds) => {
1957
+ state.currentTime = seconds;
1958
+ player()?.seekTo?.(seconds, true);
1959
+ if (!state.paused) player()?.playVideo?.();
1960
+ },
1961
+ setLoop: (loop) => {
1962
+ state.loop = loop;
1963
+ },
1964
+ setMuted: (muted) => {
1965
+ state.muted = muted;
1966
+ if (muted) {
1967
+ player()?.mute?.();
1968
+ return;
1969
+ }
1970
+ player()?.unMute?.();
1971
+ if (state.volume === 0) {
1972
+ state.volume = 0.7;
1973
+ player()?.setVolume?.(70);
1974
+ }
1975
+ },
1976
+ setPlaybackRate: (rate) => {
1977
+ state.playbackRate = rate;
1978
+ player()?.setPlaybackRate?.(rate);
1979
+ },
1980
+ setVolume: (volume) => {
1981
+ state.volume = volume;
1982
+ player()?.setVolume?.(Math.round(volume * 100));
1983
+ if (volume > 0 && state.muted) {
1984
+ state.muted = false;
1985
+ player()?.unMute?.();
1986
+ } else if (volume === 0 && !state.muted) {
1987
+ state.muted = true;
1988
+ player()?.mute?.();
1989
+ }
1990
+ }
1991
+ });
1992
+ const initial = live.current;
1993
+ playerRef.current = new YT.Player(mountTarget, {
1994
+ events: { onReady: handleReady, onStateChange: handleStateChange },
1995
+ host: "https://www.youtube-nocookie.com",
1996
+ playerVars: {
1997
+ autoplay: initial.shouldAutoPlay ? 1 : 0,
1998
+ controls: 0,
1999
+ disablekb: 1,
2000
+ enablejsapi: 1,
2001
+ fs: 0,
2002
+ iv_load_policy: 3,
2003
+ loop: initial.isLoop ? 1 : 0,
2004
+ modestbranding: 1,
2005
+ mute: initial.isMuted ? 1 : 0,
2006
+ origin: window.location.origin,
2007
+ playlist: videoId,
2008
+ playsinline: 1,
2009
+ rel: 0,
2010
+ start: Math.floor(initial.startTime || 0)
2011
+ },
2012
+ videoId
2013
+ });
2014
+ });
2015
+ return () => {
2016
+ isDisposed = true;
2017
+ if (progressInterval !== null) window.clearInterval(progressInterval);
2018
+ try {
2019
+ playerRef.current?.destroy?.();
2020
+ } catch {
2021
+ }
2022
+ playerRef.current = null;
2023
+ setVideoElement(null);
2024
+ };
2025
+ }, [
2026
+ enabled,
2027
+ hostRef,
2028
+ isLoop,
2029
+ isMuted,
2030
+ live,
2031
+ playbackRate,
2032
+ setIsBuffering,
2033
+ setIsFrameReady,
2034
+ setVideoElement,
2035
+ setVideoPlaying,
2036
+ shouldAutoPlay,
2037
+ startTime,
2038
+ videoId
2039
+ ]);
2040
+ useEffect(() => {
2041
+ const current = playerRef.current;
2042
+ if (!enabled || !current) return;
2043
+ try {
2044
+ if (isPlaying) current.playVideo?.();
2045
+ else current.pauseVideo?.();
2046
+ if (isMuted) current.mute?.();
2047
+ else current.unMute?.();
2048
+ if (playbackRate) current.setPlaybackRate?.(playbackRate);
2049
+ } catch {
2050
+ }
2051
+ }, [enabled, isMuted, isPlaying, playbackRate]);
2052
+ }
2053
+
2054
+ // src/modules/background/hooks.ts
2055
+ function useBackgroundOverlayModel() {
2056
+ const {
2057
+ animation,
2058
+ className,
2059
+ fadeEdges,
2060
+ fit,
2061
+ hasBackground,
2062
+ image,
2063
+ imageStyle,
2064
+ isPlaying,
2065
+ isVideo,
2066
+ isYouTube,
2067
+ leftGradient: configuredLeftGradient,
2068
+ noiseStyle,
2069
+ overlay,
2070
+ overlayColor,
2071
+ overlayOpacity,
2072
+ position,
2073
+ rightGradient: configuredRightGradient,
2074
+ video,
2075
+ videoClassName,
2076
+ videoOptions,
2077
+ videoStyle,
2078
+ width
2079
+ } = useBackgroundState();
2080
+ const { setVideoElement, setVideoPlaying } = useBackgroundActions();
2081
+ const options = resolveVideoOptions(videoOptions);
2082
+ const { corp, isMuted, playbackRate } = options;
2083
+ const youtubeConfig = useMemo(
2084
+ () => isYouTube ? parseYouTubeUrlConfig(video) : null,
2085
+ [isYouTube, video]
2086
+ );
2087
+ const startTime = videoOptions?.startTime ?? youtubeConfig?.startTime ?? 0;
2088
+ const endTime = videoOptions?.endTime ?? youtubeConfig?.endTime ?? 0;
2089
+ const backgroundKey = isVideo ? youtubeConfig ? `youtube:${youtubeConfig.videoId}` : video : image;
2090
+ const motionConfig = useMemo(
2091
+ () => getBackgroundMotionConfig(animation),
2092
+ [animation]
2093
+ );
2094
+ const {
2095
+ baseStyle,
2096
+ leftGradient: styleLeft,
2097
+ rightGradient: styleRight
2098
+ } = useMemo(
2099
+ () => getVisualStyle((isVideo ? videoStyle : imageStyle) || {}),
2100
+ [imageStyle, isVideo, videoStyle]
2101
+ );
2102
+ const leftGradient = configuredLeftGradient ?? styleLeft;
2103
+ const rightGradient = configuredRightGradient ?? styleRight;
2104
+ const {
2105
+ opacity: noiseOpacity,
2106
+ mixBlendMode: noiseBlendMode,
2107
+ ...noiseInlineStyle
2108
+ } = noiseStyle || {};
2109
+ const overlayTransitionStyle = useMemo(
2110
+ () => ({
2111
+ transitionDelay: toCssDelay(motionConfig.transition.delay),
2112
+ transitionDuration: toCssDuration(motionConfig.transition.duration),
2113
+ transitionProperty: "opacity",
2114
+ transitionTimingFunction: toCssEasing(motionConfig.transition.ease)
2115
+ }),
2116
+ [motionConfig.transition]
2117
+ );
2118
+ const rawWidth = width ?? videoOptions?.width ?? videoStyle?.width;
2119
+ const resolvedWidth = rawWidth === void 0 || rawWidth === null || rawWidth === "" ? void 0 : typeof rawWidth === "number" ? `${rawWidth}px` : String(rawWidth);
2120
+ const rawFit = fit ?? videoOptions?.fit ?? videoOptions?.objectFit;
2121
+ const theme = useTheme(backgroundTheme);
2122
+ const fitStyle = useMemo(
2123
+ () => rawFit && OBJECT_FITS.includes(rawFit) ? { objectFit: rawFit } : {},
2124
+ [rawFit]
2125
+ );
2126
+ const classNames = resolveVideoClassNames(
2127
+ videoClassName,
2128
+ className,
2129
+ videoOptions?.videoClassName,
2130
+ videoOptions?.className,
2131
+ videoStyle?.className
2132
+ );
2133
+ const hasCustomWidth = Boolean(resolvedWidth || classNames.width);
2134
+ const gradientSettings = useMemo(
2135
+ () => resolveGradientSettings({
2136
+ fadeEdges,
2137
+ hasWidth: hasCustomWidth,
2138
+ leftGradient,
2139
+ rightGradient
2140
+ }),
2141
+ [fadeEdges, hasCustomWidth, leftGradient, rightGradient]
2142
+ );
2143
+ const maskImage = useMemo(
2144
+ () => gradientSettings.enabled ? getEdgeFadeMask({
2145
+ color: overlayColor || DEFAULT_COLOR,
2146
+ leftPercent: gradientSettings.leftPercent,
2147
+ rightPercent: gradientSettings.rightPercent
2148
+ }) : void 0,
2149
+ [gradientSettings, overlayColor]
2150
+ );
2151
+ const framePosition = position === "left" || position === "right" ? position : "center";
2152
+ const videoClasses = cn(theme.slots.video, classNames.other);
2153
+ const objectPosition2 = baseStyle.objectPosition || position || void 0;
2154
+ const sharedVideoStyle = useMemo(
2155
+ () => ({
2156
+ ...classNames.objectStyle,
2157
+ ...fitStyle,
2158
+ ...objectPosition2 ? { objectPosition: objectPosition2 } : {},
2159
+ ...maskImage ? { WebkitMaskImage: maskImage, maskImage } : {},
2160
+ ...baseStyle
2161
+ }),
2162
+ [baseStyle, classNames.objectStyle, fitStyle, maskImage, objectPosition2]
2163
+ );
2164
+ const exitDurationFactor = Number.isFinite(motionConfig.exitDurationFactor) ? Math.max(0, motionConfig.exitDurationFactor) : 0.6;
2165
+ const exitTransition = motionConfig.exit.transition;
2166
+ return {
2167
+ className,
2168
+ hasBackground,
2169
+ image,
2170
+ isPlaying,
2171
+ isVideo,
2172
+ overlay,
2173
+ overlayColor,
2174
+ overlayOpacity,
2175
+ position,
2176
+ video,
2177
+ videoStyle,
2178
+ width,
2179
+ setVideoElement,
2180
+ setVideoPlaying,
2181
+ options,
2182
+ corp,
2183
+ isMuted,
2184
+ playbackRate,
2185
+ youtubeConfig,
2186
+ startTime,
2187
+ endTime,
2188
+ backgroundKey,
2189
+ motionConfig,
2190
+ baseStyle,
2191
+ leftGradient,
2192
+ rightGradient,
2193
+ noiseOpacity,
2194
+ noiseBlendMode,
2195
+ noiseInlineStyle,
2196
+ overlayTransitionStyle,
2197
+ resolvedWidth,
2198
+ classNames,
2199
+ hasCustomWidth,
2200
+ gradientSettings,
2201
+ maskImage,
2202
+ framePosition,
2203
+ videoClasses,
2204
+ sharedVideoStyle,
2205
+ exitDurationFactor,
2206
+ exitTransition,
2207
+ theme
2208
+ };
2209
+ }
2210
+ function useNativeVideoModel({
2211
+ corp,
2212
+ isLoop,
2213
+ isMuted,
2214
+ isPlaying,
2215
+ playbackRate,
2216
+ setVideoElement,
2217
+ setVideoPlaying,
2218
+ shouldAutoPlay,
2219
+ src,
2220
+ style,
2221
+ className
2222
+ }) {
2223
+ const videoRef = useRef(null);
2224
+ const handleEnded = useCallback(() => {
2225
+ const video = videoRef.current;
2226
+ if (!video) return;
2227
+ if (video.loop) {
2228
+ video.currentTime = 0;
2229
+ video.play().catch((error) => report("Background loop play", error, "warn"));
2230
+ return;
2231
+ }
2232
+ video.pause();
2233
+ setVideoPlaying(false);
2234
+ }, [setVideoPlaying]);
2235
+ const handleTimeUpdate = useCallback(() => {
2236
+ const video = videoRef.current;
2237
+ if (video?.duration && corp > 0 && video.currentTime >= video.duration - corp) {
2238
+ handleEnded();
2239
+ }
2240
+ }, [corp, handleEnded]);
2241
+ const handleLoadedData = () => {
2242
+ const video = videoRef.current;
2243
+ if (!video) return;
2244
+ video.playbackRate = playbackRate;
2245
+ if (!shouldAutoPlay) return;
2246
+ if (isMuted) video.muted = true;
2247
+ video.play().then(() => setVideoPlaying(true)).catch((error) => {
2248
+ report("Background autoplay", error, "warn");
2249
+ setVideoPlaying(false);
2250
+ });
2251
+ };
2252
+ useEffect(() => {
2253
+ const video = videoRef.current;
2254
+ setVideoElement(video);
2255
+ return () => {
2256
+ try {
2257
+ video?.pause();
2258
+ } catch {
2259
+ }
2260
+ };
2261
+ }, [src, setVideoElement]);
2262
+ useEffect(() => () => setVideoElement(null), [setVideoElement]);
2263
+ useEffect(() => {
2264
+ applyVideoPlaybackState({
2265
+ isPlaying,
2266
+ playbackRate,
2267
+ setVideoPlaying,
2268
+ videoElement: videoRef.current
2269
+ });
2270
+ }, [isPlaying, playbackRate, setVideoPlaying]);
2271
+ return { videoRef, handleEnded, handleTimeUpdate, handleLoadedData };
2272
+ }
2273
+ var AUDIO_SYNC_EVENTS = [
2274
+ "play",
2275
+ "playing",
2276
+ "pause",
2277
+ "waiting",
2278
+ "volumechange",
2279
+ "ratechange"
2280
+ ];
2281
+ function setElementMuted(video, muted) {
2282
+ video.muted = muted;
2283
+ if (!muted && video.volume === 0) video.volume = 0.8;
2284
+ }
2285
+ function unlockAudioOnGesture(unlock) {
2286
+ const handler = () => {
2287
+ unlock();
2288
+ window.removeEventListener("pointerdown", handler);
2289
+ window.removeEventListener("keydown", handler);
2290
+ };
2291
+ window.addEventListener("pointerdown", handler, { once: true });
2292
+ window.addEventListener("keydown", handler, { once: true });
2293
+ }
2294
+ function useYouTubeBackgroundPlayerModel({
2295
+ codec = "auto",
2296
+ corp = 0,
2297
+ endTime = 0,
2298
+ forceIframe = false,
2299
+ isLoop = false,
2300
+ isMuted = true,
2301
+ isPlaying = true,
2302
+ playbackRate = 1,
2303
+ posterUrl = null,
2304
+ quality = "1080p",
2305
+ setVideoElement,
2306
+ setVideoPlaying,
2307
+ shouldAutoPlay = true,
2308
+ showPoster = false,
2309
+ showSpinner = true,
2310
+ startTime = 0,
2311
+ videoClasses,
2312
+ videoId,
2313
+ videoStyle
2314
+ }) {
2315
+ const [useIframeFallback, setUseIframeFallback] = useState(
2316
+ Boolean(forceIframe)
2317
+ );
2318
+ const [isFrameReady, setIsFrameReady] = useState(false);
2319
+ const [isBuffering, setIsBuffering] = useState(true);
2320
+ const videoRef = useRef(null);
2321
+ const audioRef = useRef(null);
2322
+ const iframeHostRef = useRef(null);
2323
+ const hasLoadedVideoRef = useRef(false);
2324
+ const errorRetryCountRef = useRef(0);
2325
+ const audioErrorRetryCountRef = useRef(0);
2326
+ const retryTimerIdsRef = useRef(/* @__PURE__ */ new Set());
2327
+ const lastAudioSeekAtRef = useRef(0);
2328
+ const live = useRef({
2329
+ corp,
2330
+ endTime,
2331
+ isLoop,
2332
+ isMuted,
2333
+ isPlaying,
2334
+ playbackRate,
2335
+ shouldAutoPlay,
2336
+ startTime
2337
+ });
2338
+ live.current = {
2339
+ corp,
2340
+ endTime,
2341
+ isLoop,
2342
+ isMuted,
2343
+ isPlaying,
2344
+ playbackRate,
2345
+ shouldAutoPlay,
2346
+ startTime
2347
+ };
2348
+ useEffect(() => {
2349
+ setUseIframeFallback(Boolean(forceIframe));
2350
+ setIsFrameReady(false);
2351
+ setIsBuffering(true);
2352
+ hasLoadedVideoRef.current = false;
2353
+ errorRetryCountRef.current = 0;
2354
+ audioErrorRetryCountRef.current = 0;
2355
+ }, [forceIframe, videoId]);
2356
+ const videoStreamUrl = useMemo(
2357
+ () => getYouTubeStreamUrl(videoId, { codec, quality, stream: "video" }),
2358
+ [codec, quality, videoId]
2359
+ );
2360
+ const audioStreamUrl = useMemo(
2361
+ () => getYouTubeStreamUrl(videoId, { stream: "audio" }),
2362
+ [videoId]
2363
+ );
2364
+ const resolvedPoster = showPoster ? posterUrl || getYouTubeThumbnailUrl(videoId, true) : null;
2365
+ const syncCompanionAudio = useCallback((forceSeek = false) => {
2366
+ const video = videoRef.current;
2367
+ const audio = audioRef.current;
2368
+ if (!video || !audio) return;
2369
+ try {
2370
+ const targetRate = Number(video.playbackRate) || 1;
2371
+ if (audio.playbackRate !== targetRate) audio.playbackRate = targetRate;
2372
+ if (audio.readyState < 2 || !Number.isFinite(audio.duration) || audio.duration <= 0) {
2373
+ return;
2374
+ }
2375
+ const volume = Math.max(0, Math.min(1, Number(video.volume) ?? 1));
2376
+ if (Math.abs(audio.volume - volume) > 5e-3) audio.volume = volume;
2377
+ const isSilent = Boolean(video.muted) || volume === 0;
2378
+ if (audio.muted !== isSilent) audio.muted = isSilent;
2379
+ if (video.paused || video.ended || video.seeking) {
2380
+ if (!audio.paused) audio.pause();
2381
+ return;
2382
+ }
2383
+ const now = performance.now();
2384
+ const drift = Math.abs(audio.currentTime - video.currentTime);
2385
+ const maxDrift = isSilent ? 0.5 : 0.35;
2386
+ if (forceSeek || drift > maxDrift && now - lastAudioSeekAtRef.current > 1500) {
2387
+ lastAudioSeekAtRef.current = now;
2388
+ audio.currentTime = video.currentTime;
2389
+ }
2390
+ if (audio.paused) audio.play().catch(() => {
2391
+ });
2392
+ } catch {
2393
+ }
2394
+ }, []);
2395
+ const playWithFallback = useCallback(
2396
+ (video, forceSeek, unlockAudio) => {
2397
+ const onPlayed = () => {
2398
+ setVideoPlaying(true);
2399
+ syncCompanionAudio(forceSeek);
2400
+ };
2401
+ video.play().then(onPlayed).catch((error) => {
2402
+ if (error?.name !== "NotAllowedError") return;
2403
+ video.muted = true;
2404
+ video.play().then(() => {
2405
+ onPlayed();
2406
+ if (!unlockAudio) return;
2407
+ unlockAudioOnGesture(() => {
2408
+ const current = videoRef.current;
2409
+ if (!live.current.isMuted && current) {
2410
+ setElementMuted(current, false);
2411
+ }
2412
+ });
2413
+ }).catch(() => {
2414
+ });
2415
+ });
2416
+ },
2417
+ [setVideoPlaying, syncCompanionAudio]
2418
+ );
2419
+ const scheduleRetry = (callback, delay) => {
2420
+ const timerId = window.setTimeout(() => {
2421
+ retryTimerIdsRef.current.delete(timerId);
2422
+ try {
2423
+ callback();
2424
+ } catch {
2425
+ }
2426
+ }, delay);
2427
+ retryTimerIdsRef.current.add(timerId);
2428
+ };
2429
+ const handleEnded = useCallback(() => {
2430
+ const video = videoRef.current;
2431
+ const audio = audioRef.current;
2432
+ if (!video) return;
2433
+ if (video.loop || live.current.isLoop) {
2434
+ const resetTime = Math.max(0, live.current.startTime || 0);
2435
+ video.currentTime = resetTime;
2436
+ if (audio && audio.readyState >= 2) audio.currentTime = resetTime;
2437
+ video.play().then(() => {
2438
+ setVideoPlaying(true);
2439
+ syncCompanionAudio(true);
2440
+ }).catch(() => {
2441
+ });
2442
+ return;
2443
+ }
2444
+ video.pause();
2445
+ if (audio && !audio.paused) audio.pause();
2446
+ setVideoPlaying(false);
2447
+ }, [setVideoPlaying, syncCompanionAudio]);
2448
+ const handleTimeUpdate = () => {
2449
+ const video = videoRef.current;
2450
+ if (!video) return;
2451
+ if (video.currentTime > 0 && video.readyState >= 2) {
2452
+ setIsFrameReady(true);
2453
+ setIsBuffering(false);
2454
+ }
2455
+ const duration = Number(video.duration) || 0;
2456
+ const { corp: activeCorp, endTime: activeEndTime } = live.current;
2457
+ const effectiveEnd = activeEndTime > 0 ? activeEndTime : activeCorp > 0 && duration > 0 ? duration - activeCorp : 0;
2458
+ if (effectiveEnd > 0 && video.currentTime >= effectiveEnd) handleEnded();
2459
+ };
2460
+ const handlePlay = () => {
2461
+ const video = videoRef.current;
2462
+ hasLoadedVideoRef.current = true;
2463
+ if (video && !live.current.isMuted && video.muted) {
2464
+ setElementMuted(video, false);
2465
+ }
2466
+ if (!video || video.readyState < 2) setIsBuffering(true);
2467
+ setVideoPlaying(true);
2468
+ syncCompanionAudio(false);
2469
+ };
2470
+ const handlePlaying = () => {
2471
+ hasLoadedVideoRef.current = true;
2472
+ setIsFrameReady(true);
2473
+ setIsBuffering(false);
2474
+ setVideoPlaying(true);
2475
+ syncCompanionAudio(false);
2476
+ };
2477
+ const handlePause = () => {
2478
+ const video = videoRef.current;
2479
+ syncCompanionAudio(false);
2480
+ setIsBuffering(false);
2481
+ if (video && !video.seeking && !video.ended && !live.current.isPlaying) {
2482
+ setVideoPlaying(false);
2483
+ }
2484
+ };
2485
+ const handleSeeked = () => {
2486
+ const video = videoRef.current;
2487
+ if (!video) return;
2488
+ setIsFrameReady(true);
2489
+ if (video.readyState >= 2 && (!live.current.isPlaying || !video.paused)) {
2490
+ setIsBuffering(false);
2491
+ }
2492
+ syncCompanionAudio(true);
2493
+ if (live.current.isPlaying && video.paused) {
2494
+ video.play().then(() => {
2495
+ setVideoPlaying(true);
2496
+ syncCompanionAudio(true);
2497
+ }).catch(() => {
2498
+ });
2499
+ }
2500
+ };
2501
+ const handleCanPlay = () => {
2502
+ const video = videoRef.current;
2503
+ if (!video) return;
2504
+ hasLoadedVideoRef.current = true;
2505
+ if (!live.current.isPlaying) {
2506
+ setIsFrameReady(true);
2507
+ setIsBuffering(false);
2508
+ } else if (video.paused) {
2509
+ setElementMuted(video, Boolean(live.current.isMuted));
2510
+ playWithFallback(video, false, true);
2511
+ }
2512
+ };
2513
+ const handleLoadedMetadata = () => {
2514
+ const video = videoRef.current;
2515
+ if (!video) return;
2516
+ hasLoadedVideoRef.current = true;
2517
+ if (startTime > 0 && video.currentTime < startTime) {
2518
+ video.currentTime = startTime;
2519
+ if (audioRef.current) audioRef.current.currentTime = startTime;
2520
+ }
2521
+ };
2522
+ const handleLoadedData = () => {
2523
+ const video = videoRef.current;
2524
+ if (!video) return;
2525
+ hasLoadedVideoRef.current = true;
2526
+ video.playbackRate = playbackRate;
2527
+ setElementMuted(video, Boolean(live.current.isMuted));
2528
+ if (startTime > 0 && video.currentTime < startTime) {
2529
+ video.currentTime = startTime;
2530
+ }
2531
+ if (!live.current.isPlaying) {
2532
+ setIsFrameReady(true);
2533
+ setIsBuffering(false);
2534
+ } else if (video.paused) {
2535
+ playWithFallback(video, true, false);
2536
+ }
2537
+ };
2538
+ const handleError = () => {
2539
+ const video = videoRef.current;
2540
+ if (video && hasLoadedVideoRef.current) {
2541
+ const resumeTime = video.currentTime || 0;
2542
+ scheduleRetry(() => {
2543
+ video.load();
2544
+ video.currentTime = resumeTime;
2545
+ if (live.current.isPlaying) video.play().catch(() => {
2546
+ });
2547
+ }, 150);
2548
+ return;
2549
+ }
2550
+ errorRetryCountRef.current += 1;
2551
+ if (video && errorRetryCountRef.current <= 1) {
2552
+ scheduleRetry(() => video.load(), 200);
2553
+ return;
2554
+ }
2555
+ setUseIframeFallback(true);
2556
+ };
2557
+ const handleAudioError = useCallback(() => {
2558
+ const audio = audioRef.current;
2559
+ if (!audio) return;
2560
+ audioErrorRetryCountRef.current += 1;
2561
+ if (audioErrorRetryCountRef.current <= 1) {
2562
+ scheduleRetry(() => {
2563
+ audio.load();
2564
+ if (videoRef.current) {
2565
+ audio.currentTime = videoRef.current.currentTime || 0;
2566
+ }
2567
+ }, 200);
2568
+ return;
2569
+ }
2570
+ if (!live.current.isMuted) {
2571
+ setUseIframeFallback(true);
2572
+ }
2573
+ }, []);
2574
+ useEffect(() => {
2575
+ if (useIframeFallback) return void 0;
2576
+ const video = videoRef.current;
2577
+ const audio = audioRef.current;
2578
+ const retryTimerIds = retryTimerIdsRef.current;
2579
+ if (!video) {
2580
+ setVideoElement(null);
2581
+ return void 0;
2582
+ }
2583
+ setVideoElement(video);
2584
+ const onSync = () => syncCompanionAudio(false);
2585
+ const onSeeked = () => syncCompanionAudio(true);
2586
+ for (const event of AUDIO_SYNC_EVENTS) {
2587
+ video.addEventListener(event, onSync);
2588
+ }
2589
+ video.addEventListener("seeked", onSeeked);
2590
+ const syncTimer = window.setInterval(onSync, 1e3);
2591
+ return () => {
2592
+ window.clearInterval(syncTimer);
2593
+ retryTimerIds.forEach((timerId) => window.clearTimeout(timerId));
2594
+ retryTimerIds.clear();
2595
+ for (const event of AUDIO_SYNC_EVENTS) {
2596
+ video.removeEventListener(event, onSync);
2597
+ }
2598
+ video.removeEventListener("seeked", onSeeked);
2599
+ try {
2600
+ video.pause();
2601
+ audio?.pause();
2602
+ } catch {
2603
+ }
2604
+ };
2605
+ }, [setVideoElement, syncCompanionAudio, useIframeFallback, videoStreamUrl]);
2606
+ useEffect(() => {
2607
+ const video = videoRef.current;
2608
+ if (useIframeFallback || !video) return;
2609
+ applyVideoPlaybackState({
2610
+ isPlaying,
2611
+ playbackRate,
2612
+ setVideoPlaying,
2613
+ videoElement: video
2614
+ });
2615
+ syncCompanionAudio();
2616
+ }, [
2617
+ isPlaying,
2618
+ playbackRate,
2619
+ setVideoPlaying,
2620
+ syncCompanionAudio,
2621
+ useIframeFallback
2622
+ ]);
2623
+ useEffect(() => {
2624
+ const video = videoRef.current;
2625
+ if (useIframeFallback || !video) return;
2626
+ if (video.muted !== isMuted) setElementMuted(video, isMuted);
2627
+ syncCompanionAudio(true);
2628
+ }, [isMuted, syncCompanionAudio, useIframeFallback]);
2629
+ useYouTubeIframePlayer({
2630
+ enabled: useIframeFallback,
2631
+ hostRef: iframeHostRef,
2632
+ isLoop,
2633
+ isMuted,
2634
+ isPlaying,
2635
+ live,
2636
+ playbackRate,
2637
+ setIsBuffering,
2638
+ setIsFrameReady,
2639
+ setVideoElement,
2640
+ setVideoPlaying,
2641
+ shouldAutoPlay,
2642
+ startTime,
2643
+ videoId
2644
+ });
2645
+ const isCovered = !isFrameReady || useIframeFallback && !isPlaying;
2646
+ const showSpinnerOverlay = showSpinner && (!isFrameReady || isBuffering);
2647
+ return {
2648
+ useIframeFallback,
2649
+ isFrameReady,
2650
+ setIsBuffering,
2651
+ videoRef,
2652
+ audioRef,
2653
+ iframeHostRef,
2654
+ videoStreamUrl,
2655
+ audioStreamUrl,
2656
+ resolvedPoster,
2657
+ syncCompanionAudio,
2658
+ handleEnded,
2659
+ handleTimeUpdate,
2660
+ handlePlay,
2661
+ handlePlaying,
2662
+ handlePause,
2663
+ handleSeeked,
2664
+ handleCanPlay,
2665
+ handleLoadedMetadata,
2666
+ handleLoadedData,
2667
+ handleError,
2668
+ handleAudioError,
2669
+ isCovered,
2670
+ showSpinnerOverlay
2671
+ };
2672
+ }
2673
+ function NativeVideo({
2674
+ corp,
2675
+ isLoop,
2676
+ isMuted,
2677
+ isPlaying,
2678
+ playbackRate,
2679
+ setVideoElement,
2680
+ setVideoPlaying,
2681
+ shouldAutoPlay,
2682
+ src,
2683
+ style,
2684
+ className
2685
+ }) {
2686
+ const { videoRef, handleEnded, handleTimeUpdate, handleLoadedData } = useNativeVideoModel({
2687
+ corp,
2688
+ isLoop,
2689
+ isMuted,
2690
+ isPlaying,
2691
+ playbackRate,
2692
+ setVideoElement,
2693
+ setVideoPlaying,
2694
+ shouldAutoPlay,
2695
+ src,
2696
+ style,
2697
+ className
2698
+ });
2699
+ return /* @__PURE__ */ jsx(
2700
+ "video",
2701
+ {
2702
+ ref: videoRef,
2703
+ src,
2704
+ className,
2705
+ preload: "auto",
2706
+ muted: isMuted,
2707
+ loop: isLoop,
2708
+ playsInline: true,
2709
+ style,
2710
+ onTimeUpdate: handleTimeUpdate,
2711
+ onEnded: handleEnded,
2712
+ onLoadedData: handleLoadedData
2713
+ }
2714
+ );
2715
+ }
2716
+ var BackgroundGradients = memo(function BackgroundGradients2({
2717
+ count = 0,
2718
+ direction,
2719
+ color = DEFAULT_COLOR,
2720
+ theme
2721
+ }) {
2722
+ if (!count || count <= 0) return null;
2723
+ const opacity = Math.min(1, Math.max(0.2, count * 0.25));
2724
+ return /* @__PURE__ */ jsx(
2725
+ "div",
2726
+ {
2727
+ "data-side": direction,
2728
+ className: theme.slots.gradient,
2729
+ style: {
2730
+ ...theme.styles.gradient,
2731
+ opacity,
2732
+ background: generateBaseGradient(direction, color)
2733
+ }
2734
+ }
2735
+ );
2736
+ });
2737
+ var EdgeGradient = memo(function EdgeGradient2({
2738
+ direction,
2739
+ percent = 0,
2740
+ opacity = 0,
2741
+ color,
2742
+ theme
2743
+ }) {
2744
+ if (opacity <= 0) return null;
2745
+ return /* @__PURE__ */ jsx(
2746
+ "div",
2747
+ {
2748
+ "data-side": direction,
2749
+ className: theme.slots.edge,
2750
+ style: {
2751
+ width: `${Math.max(30, percent * 1.15)}%`,
2752
+ opacity,
2753
+ background: generateEdgeGradient(direction, color || DEFAULT_COLOR)
2754
+ }
2755
+ }
2756
+ );
2757
+ });
2758
+ var NoiseOverlay = memo(function NoiseOverlay2({
2759
+ opacity,
2760
+ blendMode,
2761
+ inlineStyle,
2762
+ maskImage,
2763
+ isFixed,
2764
+ theme
2765
+ }) {
2766
+ return /* @__PURE__ */ jsx(
2767
+ "div",
2768
+ {
2769
+ "data-position": isFixed ? "fixed" : "absolute",
2770
+ className: theme.slots.noise,
2771
+ style: {
2772
+ ...theme.styles.noise,
2773
+ ...typeof opacity === "number" ? { opacity } : {},
2774
+ ...typeof blendMode === "string" && blendMode.trim() ? { mixBlendMode: blendMode } : {},
2775
+ ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
2776
+ ...inlineStyle
2777
+ }
2778
+ }
2779
+ );
2780
+ });
2781
+ var SolidOverlay = memo(function SolidOverlay2({
2782
+ opacity = 0,
2783
+ color,
2784
+ transitionStyle,
2785
+ maskImage,
2786
+ theme
2787
+ }) {
2788
+ return /* @__PURE__ */ jsx(
2789
+ "div",
2790
+ {
2791
+ className: theme.slots.solid,
2792
+ style: {
2793
+ opacity,
2794
+ backgroundColor: color,
2795
+ ...maskImage ? { maskImage, WebkitMaskImage: maskImage } : {},
2796
+ ...transitionStyle
2797
+ }
2798
+ }
2799
+ );
2800
+ });
2801
+ var YouTubeBackgroundPlayer = memo(function YouTubeBackgroundPlayer2({
2802
+ codec = "auto",
2803
+ corp = 0,
2804
+ endTime = 0,
2805
+ forceIframe = false,
2806
+ isLoop = false,
2807
+ isMuted = true,
2808
+ isPlaying = true,
2809
+ playbackRate = 1,
2810
+ posterUrl = null,
2811
+ quality = "1080p",
2812
+ setVideoElement,
2813
+ setVideoPlaying,
2814
+ shouldAutoPlay = true,
2815
+ showPoster = false,
2816
+ showSpinner = true,
2817
+ startTime = 0,
2818
+ theme,
2819
+ videoClasses,
2820
+ videoId,
2821
+ videoStyle
2822
+ }) {
2823
+ const {
2824
+ useIframeFallback,
2825
+ isFrameReady,
2826
+ setIsBuffering,
2827
+ videoRef,
2828
+ audioRef,
2829
+ iframeHostRef,
2830
+ videoStreamUrl,
2831
+ audioStreamUrl,
2832
+ resolvedPoster,
2833
+ syncCompanionAudio,
2834
+ handleEnded,
2835
+ handleTimeUpdate,
2836
+ handlePlay,
2837
+ handlePlaying,
2838
+ handlePause,
2839
+ handleSeeked,
2840
+ handleCanPlay,
2841
+ handleLoadedMetadata,
2842
+ handleLoadedData,
2843
+ handleError,
2844
+ handleAudioError,
2845
+ isCovered,
2846
+ showSpinnerOverlay
2847
+ } = useYouTubeBackgroundPlayerModel({
2848
+ codec,
2849
+ corp,
2850
+ endTime,
2851
+ forceIframe,
2852
+ isLoop,
2853
+ isMuted,
2854
+ isPlaying,
2855
+ playbackRate,
2856
+ posterUrl,
2857
+ quality,
2858
+ setVideoElement,
2859
+ setVideoPlaying,
2860
+ shouldAutoPlay,
2861
+ showPoster,
2862
+ showSpinner,
2863
+ startTime,
2864
+ videoClasses,
2865
+ videoId,
2866
+ videoStyle
2867
+ });
2868
+ return /* @__PURE__ */ jsxs("div", { className: theme.slots.youtube, children: [
2869
+ /* @__PURE__ */ jsx("div", { "data-visible": isCovered, className: theme.slots.youtubeCover }),
2870
+ /* @__PURE__ */ jsx(
2871
+ "div",
2872
+ {
2873
+ "data-visible": showSpinnerOverlay,
2874
+ className: theme.slots.youtubeSpinner,
2875
+ children: showSpinner ? /* @__PURE__ */ jsx(Spinner, { size: 30, className: theme.slots.youtubeSpinnerIcon }) : null
2876
+ }
2877
+ ),
2878
+ resolvedPoster ? /* @__PURE__ */ jsx(
2879
+ "div",
2880
+ {
2881
+ "data-visible": isCovered,
2882
+ className: theme.slots.youtubePoster,
2883
+ style: {
2884
+ backgroundImage: `url(${resolvedPoster})`,
2885
+ ...videoStyle
2886
+ }
2887
+ }
2888
+ ) : null,
2889
+ useIframeFallback && !isPlaying ? /* @__PURE__ */ jsx("div", { className: theme.slots.youtubeBlackout }) : null,
2890
+ useIframeFallback ? /* @__PURE__ */ jsx(
2891
+ "div",
2892
+ {
2893
+ "data-visible": isFrameReady,
2894
+ className: theme.slots.youtubeFrame,
2895
+ style: videoStyle,
2896
+ children: /* @__PURE__ */ jsx("div", { ref: iframeHostRef, className: theme.slots.youtubeHost })
2897
+ }
2898
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2899
+ /* @__PURE__ */ jsx(
2900
+ "video",
2901
+ {
2902
+ ref: videoRef,
2903
+ src: videoStreamUrl,
2904
+ "data-visible": isFrameReady,
2905
+ className: cn(videoClasses, theme.slots.youtubeVideo),
2906
+ preload: "auto",
2907
+ muted: isMuted,
2908
+ loop: isLoop,
2909
+ playsInline: true,
2910
+ style: videoStyle,
2911
+ onTimeUpdate: handleTimeUpdate,
2912
+ onEnded: handleEnded,
2913
+ onPlay: handlePlay,
2914
+ onWaiting: () => {
2915
+ setIsBuffering(true);
2916
+ syncCompanionAudio(false);
2917
+ },
2918
+ onPlaying: handlePlaying,
2919
+ onPause: handlePause,
2920
+ onSeeking: () => setIsBuffering(true),
2921
+ onSeeked: handleSeeked,
2922
+ onCanPlay: handleCanPlay,
2923
+ onLoadedMetadata: handleLoadedMetadata,
2924
+ onLoadedData: handleLoadedData,
2925
+ onError: handleError
2926
+ }
2927
+ ),
2928
+ /* @__PURE__ */ jsx(
2929
+ "audio",
2930
+ {
2931
+ ref: audioRef,
2932
+ src: audioStreamUrl,
2933
+ preload: "auto",
2934
+ onCanPlay: () => syncCompanionAudio(true),
2935
+ onError: handleAudioError
2936
+ }
2937
+ )
2938
+ ] })
2939
+ ] });
2940
+ });
2941
+ function BackgroundOverlay() {
2942
+ const {
2943
+ hasBackground,
2944
+ image,
2945
+ isPlaying,
2946
+ isVideo,
2947
+ overlay,
2948
+ overlayColor,
2949
+ overlayOpacity,
2950
+ position,
2951
+ video,
2952
+ setVideoElement,
2953
+ setVideoPlaying,
2954
+ options,
2955
+ corp,
2956
+ isMuted,
2957
+ playbackRate,
2958
+ youtubeConfig,
2959
+ startTime,
2960
+ endTime,
2961
+ backgroundKey,
2962
+ motionConfig,
2963
+ baseStyle,
2964
+ leftGradient,
2965
+ rightGradient,
2966
+ noiseOpacity,
2967
+ noiseBlendMode,
2968
+ noiseInlineStyle,
2969
+ overlayTransitionStyle,
2970
+ resolvedWidth,
2971
+ classNames,
2972
+ hasCustomWidth,
2973
+ gradientSettings,
2974
+ maskImage,
2975
+ framePosition,
2976
+ videoClasses,
2977
+ sharedVideoStyle,
2978
+ exitDurationFactor,
2979
+ exitTransition,
2980
+ theme
2981
+ } = useBackgroundOverlayModel();
2982
+ return /* @__PURE__ */ jsx(AnimatePresence, { mode: "sync", children: hasBackground && /* @__PURE__ */ jsxs(
2983
+ motion.div,
2984
+ {
2985
+ initial: motionConfig.initial,
2986
+ animate: motionConfig.animate,
2987
+ transition: motionConfig.transition,
2988
+ exit: {
2989
+ ...motionConfig.exit,
2990
+ transition: {
2991
+ ...motionConfig.transition,
2992
+ delay: 0,
2993
+ duration: exitTransition?.duration ?? (motionConfig.transition.duration ?? 0.6) * exitDurationFactor,
2994
+ ease: exitTransition?.ease ?? EASING_CURVES.IN_CUBIC
2995
+ }
2996
+ },
2997
+ className: theme.slots.root,
2998
+ style: {
2999
+ willChange: "transform, opacity, filter",
3000
+ ...theme.styles.root
3001
+ },
3002
+ children: [
3003
+ isVideo ? /* @__PURE__ */ jsxs(
3004
+ "div",
3005
+ {
3006
+ "data-position": framePosition,
3007
+ "data-width": classNames.width || resolvedWidth ? void 0 : "full",
3008
+ className: cn(theme.slots.videoFrame, classNames.width),
3009
+ style: {
3010
+ ...theme.styles.videoFrame,
3011
+ ...resolvedWidth ? { width: resolvedWidth } : {}
3012
+ },
3013
+ children: [
3014
+ youtubeConfig ? /* @__PURE__ */ jsx(
3015
+ YouTubeBackgroundPlayer,
3016
+ {
3017
+ videoId: youtubeConfig.videoId,
3018
+ startTime,
3019
+ endTime,
3020
+ corp,
3021
+ isPlaying,
3022
+ isMuted,
3023
+ isLoop: options.isLoop,
3024
+ shouldAutoPlay: options.shouldAutoPlay,
3025
+ showPoster: options.showPoster,
3026
+ showSpinner: options.showSpinner,
3027
+ playbackRate,
3028
+ quality: options.quality,
3029
+ codec: options.codec,
3030
+ forceIframe: options.forceIframe,
3031
+ posterUrl: options.showPoster ? image || null : null,
3032
+ theme,
3033
+ videoClasses,
3034
+ videoStyle: sharedVideoStyle,
3035
+ setVideoElement,
3036
+ setVideoPlaying
3037
+ }
3038
+ ) : /* @__PURE__ */ jsx(
3039
+ NativeVideo,
3040
+ {
3041
+ src: video || void 0,
3042
+ className: videoClasses,
3043
+ style: sharedVideoStyle,
3044
+ corp,
3045
+ isLoop: options.isLoop,
3046
+ isMuted,
3047
+ isPlaying,
3048
+ playbackRate,
3049
+ shouldAutoPlay: options.shouldAutoPlay,
3050
+ setVideoElement,
3051
+ setVideoPlaying
3052
+ }
3053
+ ),
3054
+ /* @__PURE__ */ jsx(
3055
+ EdgeGradient,
3056
+ {
3057
+ theme,
3058
+ direction: "left",
3059
+ percent: gradientSettings.leftPercent,
3060
+ opacity: gradientSettings.leftOpacity,
3061
+ color: overlayColor
3062
+ }
3063
+ ),
3064
+ /* @__PURE__ */ jsx(
3065
+ EdgeGradient,
3066
+ {
3067
+ theme,
3068
+ direction: "right",
3069
+ percent: gradientSettings.rightPercent,
3070
+ opacity: gradientSettings.rightOpacity,
3071
+ color: overlayColor
3072
+ }
3073
+ ),
3074
+ hasCustomWidth && /* @__PURE__ */ jsx(
3075
+ NoiseOverlay,
3076
+ {
3077
+ theme,
3078
+ opacity: noiseOpacity,
3079
+ blendMode: noiseBlendMode,
3080
+ inlineStyle: noiseInlineStyle,
3081
+ maskImage
3082
+ }
3083
+ ),
3084
+ hasCustomWidth && overlay && /* @__PURE__ */ jsx(
3085
+ SolidOverlay,
3086
+ {
3087
+ theme,
3088
+ opacity: overlayOpacity,
3089
+ color: overlayColor,
3090
+ transitionStyle: overlayTransitionStyle,
3091
+ maskImage
3092
+ }
3093
+ )
3094
+ ]
3095
+ }
3096
+ ) : /* @__PURE__ */ jsx(
3097
+ "div",
3098
+ {
3099
+ className: theme.slots.image,
3100
+ style: {
3101
+ backgroundImage: image ? `url(${image})` : void 0,
3102
+ backgroundPosition: position,
3103
+ ...baseStyle
3104
+ }
3105
+ }
3106
+ ),
3107
+ (!isVideo || !hasCustomWidth) && /* @__PURE__ */ jsxs(Fragment, { children: [
3108
+ /* @__PURE__ */ jsx(
3109
+ BackgroundGradients,
3110
+ {
3111
+ theme,
3112
+ count: leftGradient,
3113
+ direction: "left",
3114
+ color: overlayColor
3115
+ }
3116
+ ),
3117
+ /* @__PURE__ */ jsx(
3118
+ BackgroundGradients,
3119
+ {
3120
+ theme,
3121
+ count: rightGradient,
3122
+ direction: "right",
3123
+ color: overlayColor
3124
+ }
3125
+ ),
3126
+ /* @__PURE__ */ jsx(
3127
+ NoiseOverlay,
3128
+ {
3129
+ theme,
3130
+ isFixed: true,
3131
+ opacity: noiseOpacity,
3132
+ blendMode: noiseBlendMode,
3133
+ inlineStyle: noiseInlineStyle
3134
+ }
3135
+ ),
3136
+ overlay && /* @__PURE__ */ jsx(
3137
+ SolidOverlay,
3138
+ {
3139
+ theme,
3140
+ opacity: overlayOpacity,
3141
+ color: overlayColor,
3142
+ transitionStyle: overlayTransitionStyle
3143
+ }
3144
+ )
3145
+ ] })
3146
+ ]
3147
+ },
3148
+ backgroundKey
3149
+ ) });
3150
+ }
3151
+ function useBackgroundPage(_slice, page) {
3152
+ const actions = useBackgroundActions();
3153
+ return useMemo(
3154
+ () => ({
3155
+ ...actions,
3156
+ set: (background) => page.set({ background })
3157
+ }),
3158
+ [actions, page]
3159
+ );
3160
+ }
3161
+ var backgroundModule = defineModule({
3162
+ id: "background",
3163
+ context: BackgroundContext,
3164
+ Provider: BackgroundProvider,
3165
+ Backdrop: BackgroundOverlay,
3166
+ uses: ["media"],
3167
+ registry: {
3168
+ cleanupDelayMs: 600,
3169
+ keyPolicy: "singleton",
3170
+ lifecycle: "immediate",
3171
+ singletonKey: BACKGROUND_REGISTRY_KEY
3172
+ },
3173
+ page: {
3174
+ select: (config) => selectPageBackground(config.background),
3175
+ entries: (slice) => [
3176
+ { key: BACKGROUND_REGISTRY_KEY, value: slice }
3177
+ ],
3178
+ use: useBackgroundPage
3179
+ }
3180
+ });
3181
+ function defineBackground(definition = {}) {
3182
+ const { id = "background", ...config } = typeof definition === "string" ? { image: definition } : definition;
3183
+ return Object.freeze({
3184
+ config,
3185
+ id,
3186
+ use: function useDefinedBackground(overrides = {}, options = {}) {
3187
+ const patch = typeof overrides === "string" ? { image: overrides } : overrides;
3188
+ return useBackground({ ...config, ...patch }, options);
3189
+ }
3190
+ });
3191
+ }
3192
+
3193
+ export { BACKGROUND_MEDIA_ID, BackgroundContext, BackgroundOverlay, BackgroundProvider, DEFAULT_BACKGROUND, backgroundModule, backgroundTheme, defineBackground, extractYouTubeVideoId, getYouTubeStreamUrl, getYouTubeThumbnailUrl, isDirectVideoUrl, isYouTubeUrl, parseYouTubeUrlConfig, useBackground, useBackgroundActions, useBackgroundRegistration, useBackgroundState };
3194
+ //# sourceMappingURL=index.js.map
3195
+ //# sourceMappingURL=index.js.map