@shohojdhara/atomix 0.3.3 → 0.3.5

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 (489) hide show
  1. package/README.md +46 -28
  2. package/dist/atomix.css +15 -9
  3. package/dist/atomix.css.map +1 -0
  4. package/dist/atomix.min.css +15108 -11
  5. package/dist/atomix.min.css.map +1 -0
  6. package/dist/charts.d.ts +1929 -0
  7. package/dist/charts.js +6482 -0
  8. package/dist/charts.js.map +1 -0
  9. package/dist/core.d.ts +1289 -0
  10. package/dist/core.js +3357 -0
  11. package/dist/core.js.map +1 -0
  12. package/dist/forms.d.ts +1085 -0
  13. package/dist/forms.js +2450 -0
  14. package/dist/forms.js.map +1 -0
  15. package/dist/heavy.d.ts +636 -0
  16. package/dist/heavy.js +4550 -0
  17. package/dist/heavy.js.map +1 -0
  18. package/dist/index.d.ts +5196 -4618
  19. package/dist/index.esm.js +4240 -2776
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +4057 -2571
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/dist/layout.d.ts +300 -0
  26. package/dist/layout.js +336 -0
  27. package/dist/layout.js.map +1 -0
  28. package/dist/theme.d.ts +1992 -0
  29. package/dist/theme.js +5348 -0
  30. package/dist/theme.js.map +1 -0
  31. package/package.json +63 -68
  32. package/scripts/atomix-cli.js +879 -15
  33. package/scripts/cli/__tests__/cli-commands.test.js +204 -0
  34. package/scripts/cli/__tests__/utils.test.js +201 -0
  35. package/scripts/cli/__tests__/vitest.config.js +26 -0
  36. package/scripts/cli/interactive-init.js +37 -45
  37. package/scripts/cli/theme-bridge.js +129 -0
  38. package/scripts/cli/token-manager.js +32 -7
  39. package/scripts/cli/utils.js +347 -0
  40. package/scripts/sync-theme-config.js +22 -22
  41. package/src/components/Accordion/Accordion.tsx +5 -54
  42. package/src/components/Accordion/index.ts +1 -1
  43. package/src/components/Avatar/Avatar.tsx +3 -3
  44. package/src/components/Badge/Badge.tsx +3 -3
  45. package/src/components/Breadcrumb/Breadcrumb.tsx +3 -3
  46. package/src/components/Button/Button.tsx +36 -1
  47. package/src/components/Card/ElevationCard.tsx +1 -1
  48. package/src/components/Chart/AnimatedChart.tsx +19 -17
  49. package/src/components/Chart/AreaChart.tsx +5 -1
  50. package/src/components/Chart/BarChart.tsx +1 -0
  51. package/src/components/Chart/BubbleChart.tsx +6 -5
  52. package/src/components/Chart/ChartToolbar.tsx +1 -0
  53. package/src/components/Chart/FunnelChart.tsx +1 -1
  54. package/src/components/Chart/RadarChart.tsx +19 -12
  55. package/src/components/Chart/ScatterChart.tsx +3 -3
  56. package/src/components/Chart/TreemapChart.tsx +2 -1
  57. package/src/components/Chart/WaterfallChart.tsx +0 -1
  58. package/src/components/Chart/types.ts +12 -2
  59. package/src/components/Chart/utils.ts +4 -3
  60. package/src/components/DataTable/DataTable.tsx +3 -3
  61. package/src/components/Dropdown/Dropdown.tsx +12 -9
  62. package/src/components/Footer/FooterSection.tsx +3 -3
  63. package/src/components/Form/Checkbox.tsx +3 -3
  64. package/src/components/Form/Input.tsx +4 -2
  65. package/src/components/Form/Radio.tsx +3 -3
  66. package/src/components/Form/Select.tsx +3 -3
  67. package/src/components/Form/Textarea.tsx +4 -2
  68. package/src/components/List/List.stories.tsx +3 -3
  69. package/src/components/List/List.tsx +3 -3
  70. package/src/components/List/ListGroup.tsx +3 -1
  71. package/src/components/Modal/Modal.tsx +3 -3
  72. package/src/components/Navigation/Menu/MegaMenu.tsx +9 -3
  73. package/src/components/Navigation/Menu/Menu.tsx +9 -3
  74. package/src/components/Pagination/Pagination.tsx +6 -5
  75. package/src/components/PhotoViewer/PhotoViewerImage.tsx +2 -2
  76. package/src/components/Popover/Popover.tsx +4 -4
  77. package/src/components/Progress/Progress.tsx +6 -2
  78. package/src/components/Rating/Rating.tsx +5 -2
  79. package/src/components/Slider/Slider.tsx +10 -9
  80. package/src/components/Spinner/Spinner.tsx +3 -3
  81. package/src/components/Tabs/Tabs.tsx +3 -3
  82. package/src/components/Tooltip/Tooltip.tsx +3 -3
  83. package/src/components/index.ts +5 -2
  84. package/src/layouts/MasonryGrid/MasonryGrid.tsx +2 -2
  85. package/src/lib/composables/useChartPerformance.ts +102 -78
  86. package/src/lib/composables/useChartScale.ts +10 -0
  87. package/src/lib/composables/useHero.ts +9 -2
  88. package/src/lib/composables/useHeroBackgroundSlider.ts +5 -3
  89. package/src/lib/composables/useSideMenu.ts +1 -0
  90. package/src/lib/composables/useVideoPlayer.ts +3 -2
  91. package/src/lib/config/index.ts +275 -0
  92. package/src/lib/config/loader.ts +147 -0
  93. package/src/lib/hooks/index.ts +0 -1
  94. package/src/lib/hooks/useComponentCustomization.ts +10 -14
  95. package/src/lib/hooks/usePerformanceMonitor.ts +149 -0
  96. package/src/lib/index.ts +1 -0
  97. package/src/lib/patterns/index.ts +2 -2
  98. package/src/lib/patterns/slots.tsx +2 -2
  99. package/src/lib/theme/composeTheme.ts +1 -6
  100. package/src/lib/theme/config/index.ts +1 -1
  101. package/src/lib/theme/config/loader.ts +75 -41
  102. package/src/lib/theme/config/types.ts +21 -7
  103. package/src/lib/theme/config/validator.ts +1 -1
  104. package/src/lib/theme/constants.ts +12 -2
  105. package/src/lib/theme/core/ThemeEngine.ts +8 -0
  106. package/src/lib/theme/core/ThemeValidator.ts +5 -2
  107. package/src/lib/theme/createTheme.ts +0 -1
  108. package/src/lib/theme/createThemeFromConfig.ts +132 -0
  109. package/src/lib/theme/devtools/CLI.ts +161 -76
  110. package/src/lib/theme/devtools/Comparator.tsx +343 -0
  111. package/src/lib/theme/devtools/IMPROVEMENTS.md +429 -0
  112. package/src/lib/theme/devtools/Inspector.tsx +22 -7
  113. package/src/lib/theme/devtools/LiveEditor.tsx +399 -0
  114. package/src/lib/theme/devtools/README.md +433 -0
  115. package/src/lib/theme/devtools/index.ts +12 -11
  116. package/src/lib/theme/generateCSSVariables.ts +80 -39
  117. package/src/lib/theme/i18n/rtl.ts +2 -1
  118. package/src/lib/theme/index.ts +18 -2
  119. package/src/lib/theme/runtime/ThemeApplicator.ts +28 -11
  120. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +3 -3
  121. package/src/lib/theme/runtime/ThemeManager.test.ts +17 -1
  122. package/src/lib/theme/runtime/ThemeManager.ts +11 -7
  123. package/src/lib/theme/types.ts +42 -43
  124. package/src/lib/theme-tools.ts +8 -68
  125. package/src/lib/types/components.ts +252 -109
  126. package/src/lib/types/partProps.ts +0 -16
  127. package/src/lib/utils/fontPreloader.ts +148 -0
  128. package/src/lib/utils/index.ts +11 -0
  129. package/src/lib/utils/memoryMonitor.ts +189 -0
  130. package/src/styles/01-settings/_settings.fonts.scss +2 -5
  131. package/src/styles/01-settings/_settings.navbar.scss +1 -1
  132. package/src/styles/03-generic/_generated-root.css +26 -0
  133. package/src/styles/06-components/_components.navbar.scss +6 -5
  134. package/src/themes/README.md +1 -2
  135. package/src/themes/themes.config.js +30 -181
  136. package/dist/themes/applemix.css +0 -16576
  137. package/dist/themes/applemix.css.map +0 -1
  138. package/dist/themes/applemix.min.css +0 -73
  139. package/dist/themes/boomdevs.css +0 -16007
  140. package/dist/themes/boomdevs.css.map +0 -1
  141. package/dist/themes/boomdevs.min.css +0 -406
  142. package/dist/themes/esrar.css +0 -18424
  143. package/dist/themes/esrar.css.map +0 -1
  144. package/dist/themes/esrar.min.css +0 -221
  145. package/dist/themes/flashtrade.css +0 -17596
  146. package/dist/themes/flashtrade.css.map +0 -1
  147. package/dist/themes/flashtrade.min.css +0 -196
  148. package/dist/themes/mashroom.css +0 -31082
  149. package/dist/themes/mashroom.css.map +0 -1
  150. package/dist/themes/mashroom.min.css +0 -450
  151. package/dist/themes/shaj-default.css +0 -17200
  152. package/dist/themes/shaj-default.css.map +0 -1
  153. package/dist/themes/shaj-default.min.css +0 -502
  154. package/scripts/build-themes.js +0 -208
  155. package/src/components/AtomixGlass/atomixGLass.old.tsx +0 -1263
  156. package/src/lib/theme/__tests__/ThemeBuilder.test.ts +0 -223
  157. package/src/lib/theme/builders/ThemeBuilder.ts +0 -372
  158. package/src/lib/theme/errors.test.ts +0 -207
  159. package/src/lib/theme/generators/CSSGenerator.ts +0 -311
  160. package/src/lib/theme/generators/ConfigGenerator.ts +0 -287
  161. package/src/lib/theme/generators/TypeGenerator.ts +0 -228
  162. package/src/lib/theme/generators/index.ts +0 -21
  163. package/src/lib/theme/monitoring/ThemeAnalytics.ts +0 -409
  164. package/src/lib/theme/monitoring/index.ts +0 -17
  165. package/src/lib/theme/overrides/ComponentOverrides.ts +0 -243
  166. package/src/lib/theme/overrides/index.ts +0 -15
  167. package/src/lib/theme/whitelabel/WhiteLabelManager.ts +0 -364
  168. package/src/lib/theme/whitelabel/index.ts +0 -13
  169. package/src/themes/THEME_CHECKLIST.md +0 -74
  170. package/src/themes/applemix/01-settings/_index.scss +0 -24
  171. package/src/themes/applemix/01-settings/_settings.animations.scss +0 -0
  172. package/src/themes/applemix/01-settings/_settings.background.scss +0 -6
  173. package/src/themes/applemix/01-settings/_settings.colors.scss +0 -75
  174. package/src/themes/applemix/01-settings/_settings.config.scss +0 -15
  175. package/src/themes/applemix/01-settings/_settings.typography.scss +0 -30
  176. package/src/themes/applemix/02-tools/_index.scss +0 -4
  177. package/src/themes/applemix/03-generic/_index.scss +0 -7
  178. package/src/themes/applemix/04-elements/_index.scss +0 -7
  179. package/src/themes/applemix/05-objects/_index.scss +0 -7
  180. package/src/themes/applemix/06-components/_index.scss +0 -15
  181. package/src/themes/applemix/99-utilities/_index.scss +0 -7
  182. package/src/themes/applemix/README.md +0 -378
  183. package/src/themes/applemix/index.scss +0 -33
  184. package/src/themes/boomdevs/01-settings/_index.scss +0 -38
  185. package/src/themes/boomdevs/01-settings/_settings.accordion.scss +0 -12
  186. package/src/themes/boomdevs/01-settings/_settings.animations.scss +0 -11
  187. package/src/themes/boomdevs/01-settings/_settings.avatar.scss +0 -9
  188. package/src/themes/boomdevs/01-settings/_settings.badge.scss +0 -11
  189. package/src/themes/boomdevs/01-settings/_settings.border-radius.scss +0 -16
  190. package/src/themes/boomdevs/01-settings/_settings.border.scss +0 -10
  191. package/src/themes/boomdevs/01-settings/_settings.box-shadow.scss +0 -14
  192. package/src/themes/boomdevs/01-settings/_settings.breadcrumb.scss +0 -13
  193. package/src/themes/boomdevs/01-settings/_settings.breakpoints.scss +0 -15
  194. package/src/themes/boomdevs/01-settings/_settings.button.scss +0 -9
  195. package/src/themes/boomdevs/01-settings/_settings.callout.scss +0 -9
  196. package/src/themes/boomdevs/01-settings/_settings.card.scss +0 -11
  197. package/src/themes/boomdevs/01-settings/_settings.checkbox.scss +0 -9
  198. package/src/themes/boomdevs/01-settings/_settings.colors.scss +0 -145
  199. package/src/themes/boomdevs/01-settings/_settings.dropdown.scss +0 -11
  200. package/src/themes/boomdevs/01-settings/_settings.grid.scss +0 -16
  201. package/src/themes/boomdevs/01-settings/_settings.input.scss +0 -14
  202. package/src/themes/boomdevs/01-settings/_settings.link.scss +0 -11
  203. package/src/themes/boomdevs/01-settings/_settings.list.scss +0 -10
  204. package/src/themes/boomdevs/01-settings/_settings.modal.scss +0 -16
  205. package/src/themes/boomdevs/01-settings/_settings.navbar.scss +0 -16
  206. package/src/themes/boomdevs/01-settings/_settings.pagination.scss +0 -13
  207. package/src/themes/boomdevs/01-settings/_settings.progress.scss +0 -11
  208. package/src/themes/boomdevs/01-settings/_settings.rating.scss +0 -10
  209. package/src/themes/boomdevs/01-settings/_settings.spacing.scss +0 -33
  210. package/src/themes/boomdevs/01-settings/_settings.spinner.scss +0 -11
  211. package/src/themes/boomdevs/01-settings/_settings.steps.scss +0 -12
  212. package/src/themes/boomdevs/01-settings/_settings.tabs.scss +0 -12
  213. package/src/themes/boomdevs/01-settings/_settings.todo.scss +0 -15
  214. package/src/themes/boomdevs/01-settings/_settings.toggle.scss +0 -14
  215. package/src/themes/boomdevs/01-settings/_settings.tooltip.scss +0 -13
  216. package/src/themes/boomdevs/01-settings/_settings.typography.scss +0 -58
  217. package/src/themes/boomdevs/01-settings/_settings.video-player.scss +0 -12
  218. package/src/themes/boomdevs/02-tools/_index.scss +0 -7
  219. package/src/themes/boomdevs/03-generic/_index.scss +0 -7
  220. package/src/themes/boomdevs/04-elements/_index.scss +0 -7
  221. package/src/themes/boomdevs/05-objects/_index.scss +0 -7
  222. package/src/themes/boomdevs/06-components/_components.button.scss +0 -11
  223. package/src/themes/boomdevs/06-components/_index.scss +0 -11
  224. package/src/themes/boomdevs/99-utilities/_index.scss +0 -7
  225. package/src/themes/boomdevs/index.scss +0 -26
  226. package/src/themes/esrar/01-settings/_index.scss +0 -15
  227. package/src/themes/esrar/01-settings/_settings.colors.scss +0 -91
  228. package/src/themes/esrar/02-tools/_index.scss +0 -8
  229. package/src/themes/esrar/02-tools/_tools.animations.scss +0 -342
  230. package/src/themes/esrar/06-components/_components.accordion.scss +0 -49
  231. package/src/themes/esrar/06-components/_components.avatar-group.scss +0 -14
  232. package/src/themes/esrar/06-components/_components.avatar.scss +0 -61
  233. package/src/themes/esrar/06-components/_components.badge.scss +0 -117
  234. package/src/themes/esrar/06-components/_components.breadcrumb.scss +0 -65
  235. package/src/themes/esrar/06-components/_components.btn-group.scss +0 -19
  236. package/src/themes/esrar/06-components/_components.button.scss +0 -224
  237. package/src/themes/esrar/06-components/_components.callout.scss +0 -51
  238. package/src/themes/esrar/06-components/_components.card.scss +0 -134
  239. package/src/themes/esrar/06-components/_components.chart.scss +0 -24
  240. package/src/themes/esrar/06-components/_components.checkbox-group.scss +0 -26
  241. package/src/themes/esrar/06-components/_components.checkbox.scss +0 -71
  242. package/src/themes/esrar/06-components/_components.color-mode-toggle.scss +0 -29
  243. package/src/themes/esrar/06-components/_components.countdown.scss +0 -67
  244. package/src/themes/esrar/06-components/_components.data-table.scss +0 -22
  245. package/src/themes/esrar/06-components/_components.datepicker.scss +0 -20
  246. package/src/themes/esrar/06-components/_components.dropdown.scss +0 -272
  247. package/src/themes/esrar/06-components/_components.edge-panel.scss +0 -10
  248. package/src/themes/esrar/06-components/_components.form-group.scss +0 -15
  249. package/src/themes/esrar/06-components/_components.form.scss +0 -66
  250. package/src/themes/esrar/06-components/_components.hero.scss +0 -251
  251. package/src/themes/esrar/06-components/_components.icon.scss +0 -33
  252. package/src/themes/esrar/06-components/_components.image-gallery.scss +0 -29
  253. package/src/themes/esrar/06-components/_components.input.scss +0 -91
  254. package/src/themes/esrar/06-components/_components.list-group.scss +0 -26
  255. package/src/themes/esrar/06-components/_components.modal.scss +0 -148
  256. package/src/themes/esrar/06-components/_components.notification.scss +0 -80
  257. package/src/themes/esrar/06-components/_components.pagination.scss +0 -84
  258. package/src/themes/esrar/06-components/_components.popover.scss +0 -10
  259. package/src/themes/esrar/06-components/_components.progress.scss +0 -64
  260. package/src/themes/esrar/06-components/_components.rating.scss +0 -26
  261. package/src/themes/esrar/06-components/_components.skeleton.scss +0 -15
  262. package/src/themes/esrar/06-components/_components.slider.scss +0 -90
  263. package/src/themes/esrar/06-components/_components.spinner.scss +0 -71
  264. package/src/themes/esrar/06-components/_components.steps.scss +0 -76
  265. package/src/themes/esrar/06-components/_components.tab.scss +0 -58
  266. package/src/themes/esrar/06-components/_components.tag.scss +0 -21
  267. package/src/themes/esrar/06-components/_components.timeline.scss +0 -19
  268. package/src/themes/esrar/06-components/_components.toast.scss +0 -91
  269. package/src/themes/esrar/06-components/_components.toggle.scss +0 -74
  270. package/src/themes/esrar/06-components/_components.tooltip.scss +0 -45
  271. package/src/themes/esrar/06-components/_components.upload.scss +0 -102
  272. package/src/themes/esrar/06-components/_index.scss +0 -42
  273. package/src/themes/esrar/index.scss +0 -30
  274. package/src/themes/flashtrade/01-settings/_index.scss +0 -19
  275. package/src/themes/flashtrade/01-settings/_settings.animations.scss +0 -11
  276. package/src/themes/flashtrade/01-settings/_settings.background.scss +0 -9
  277. package/src/themes/flashtrade/01-settings/_settings.colors.scss +0 -79
  278. package/src/themes/flashtrade/01-settings/_settings.config.scss +0 -16
  279. package/src/themes/flashtrade/01-settings/_settings.typography.scss +0 -35
  280. package/src/themes/flashtrade/02-tools/_index.scss +0 -8
  281. package/src/themes/flashtrade/03-generic/_index.scss +0 -8
  282. package/src/themes/flashtrade/04-elements/_index.scss +0 -12
  283. package/src/themes/flashtrade/05-objects/_index.scss +0 -8
  284. package/src/themes/flashtrade/06-components/_components.badge.scss +0 -156
  285. package/src/themes/flashtrade/06-components/_components.button.scss +0 -135
  286. package/src/themes/flashtrade/06-components/_components.card.scss +0 -214
  287. package/src/themes/flashtrade/06-components/_components.navbar.scss +0 -227
  288. package/src/themes/flashtrade/06-components/_index.scss +0 -13
  289. package/src/themes/flashtrade/99-utilities/_index.scss +0 -9
  290. package/src/themes/flashtrade/99-utilities/_utilities.trading.scss +0 -187
  291. package/src/themes/flashtrade/README.md +0 -386
  292. package/src/themes/flashtrade/demo.html +0 -272
  293. package/src/themes/flashtrade/index.scss +0 -36
  294. package/src/themes/mashroom/01-settings/_index.scss +0 -69
  295. package/src/themes/mashroom/01-settings/_settings.accordion.scss +0 -32
  296. package/src/themes/mashroom/01-settings/_settings.animations.scss +0 -26
  297. package/src/themes/mashroom/01-settings/_settings.avatar-group.scss +0 -22
  298. package/src/themes/mashroom/01-settings/_settings.avatar.scss +0 -57
  299. package/src/themes/mashroom/01-settings/_settings.badge.scss +0 -19
  300. package/src/themes/mashroom/01-settings/_settings.border-radius.scss +0 -24
  301. package/src/themes/mashroom/01-settings/_settings.border.scss +0 -14
  302. package/src/themes/mashroom/01-settings/_settings.box-shadow.scss +0 -40
  303. package/src/themes/mashroom/01-settings/_settings.breadcrumb.scss +0 -0
  304. package/src/themes/mashroom/01-settings/_settings.breakpoints.scss +0 -17
  305. package/src/themes/mashroom/01-settings/_settings.btn-group.scss +0 -5
  306. package/src/themes/mashroom/01-settings/_settings.button.scss +0 -50
  307. package/src/themes/mashroom/01-settings/_settings.callout.scss +0 -81
  308. package/src/themes/mashroom/01-settings/_settings.card.scss +0 -52
  309. package/src/themes/mashroom/01-settings/_settings.checkbox-group.scss +0 -5
  310. package/src/themes/mashroom/01-settings/_settings.checkbox.scss +0 -23
  311. package/src/themes/mashroom/01-settings/_settings.color-mode.scss +0 -7
  312. package/src/themes/mashroom/01-settings/_settings.colors.scss +0 -180
  313. package/src/themes/mashroom/01-settings/_settings.config.scss +0 -4
  314. package/src/themes/mashroom/01-settings/_settings.countdown.scss +0 -20
  315. package/src/themes/mashroom/01-settings/_settings.data-table.scss +0 -56
  316. package/src/themes/mashroom/01-settings/_settings.datepicker.scss +0 -45
  317. package/src/themes/mashroom/01-settings/_settings.design-tokens.scss +0 -3
  318. package/src/themes/mashroom/01-settings/_settings.dropdown.scss +0 -45
  319. package/src/themes/mashroom/01-settings/_settings.edge-panel.scss +0 -24
  320. package/src/themes/mashroom/01-settings/_settings.fonts.scss +0 -8
  321. package/src/themes/mashroom/01-settings/_settings.form-group.scss +0 -14
  322. package/src/themes/mashroom/01-settings/_settings.form.scss +0 -6
  323. package/src/themes/mashroom/01-settings/_settings.grid.scss +0 -23
  324. package/src/themes/mashroom/01-settings/_settings.hero.scss +0 -41
  325. package/src/themes/mashroom/01-settings/_settings.input.scss +0 -51
  326. package/src/themes/mashroom/01-settings/_settings.link.scss +0 -13
  327. package/src/themes/mashroom/01-settings/_settings.list-group.scss +0 -16
  328. package/src/themes/mashroom/01-settings/_settings.list.scss +0 -13
  329. package/src/themes/mashroom/01-settings/_settings.masonry-grid.scss +0 -23
  330. package/src/themes/mashroom/01-settings/_settings.menu.scss +0 -50
  331. package/src/themes/mashroom/01-settings/_settings.messages.scss +0 -98
  332. package/src/themes/mashroom/01-settings/_settings.modal.scss +0 -41
  333. package/src/themes/mashroom/01-settings/_settings.nav.scss +0 -20
  334. package/src/themes/mashroom/01-settings/_settings.navbar.scss +0 -54
  335. package/src/themes/mashroom/01-settings/_settings.pagination.scss +0 -30
  336. package/src/themes/mashroom/01-settings/_settings.photoviewer.scss +0 -45
  337. package/src/themes/mashroom/01-settings/_settings.popover.scss +0 -20
  338. package/src/themes/mashroom/01-settings/_settings.position.scss +0 -9
  339. package/src/themes/mashroom/01-settings/_settings.progress.scss +0 -17
  340. package/src/themes/mashroom/01-settings/_settings.rating.scss +0 -11
  341. package/src/themes/mashroom/01-settings/_settings.river.scss +0 -50
  342. package/src/themes/mashroom/01-settings/_settings.sectionintro.scss +0 -31
  343. package/src/themes/mashroom/01-settings/_settings.select.scss +0 -47
  344. package/src/themes/mashroom/01-settings/_settings.side-menu.scss +0 -79
  345. package/src/themes/mashroom/01-settings/_settings.skeleton.scss +0 -24
  346. package/src/themes/mashroom/01-settings/_settings.spacing.scss +0 -66
  347. package/src/themes/mashroom/01-settings/_settings.spinner.scss +0 -34
  348. package/src/themes/mashroom/01-settings/_settings.steps.scss +0 -33
  349. package/src/themes/mashroom/01-settings/_settings.tabs.scss +0 -33
  350. package/src/themes/mashroom/01-settings/_settings.testimonials.scss +0 -24
  351. package/src/themes/mashroom/01-settings/_settings.todo.scss +0 -52
  352. package/src/themes/mashroom/01-settings/_settings.toggle.scss +0 -49
  353. package/src/themes/mashroom/01-settings/_settings.tooltip.scss +0 -20
  354. package/src/themes/mashroom/01-settings/_settings.typography.scss +0 -95
  355. package/src/themes/mashroom/01-settings/_settings.upload.scss +0 -96
  356. package/src/themes/mashroom/01-settings/_settings.z-layers.scss +0 -19
  357. package/src/themes/mashroom/02-tools/_index.scss +0 -8
  358. package/src/themes/mashroom/02-tools/_tools.psychedelic-gradients.scss +0 -78
  359. package/src/themes/mashroom/02-tools/_tools.trippy-effects.scss +0 -114
  360. package/src/themes/mashroom/03-generic/_index.scss +0 -6
  361. package/src/themes/mashroom/04-elements/_index.scss +0 -6
  362. package/src/themes/mashroom/05-objects/_index.scss +0 -6
  363. package/src/themes/mashroom/06-components/_components.accordion.scss +0 -187
  364. package/src/themes/mashroom/06-components/_components.avatar-group.scss +0 -276
  365. package/src/themes/mashroom/06-components/_components.avatar.scss +0 -114
  366. package/src/themes/mashroom/06-components/_components.badge.scss +0 -152
  367. package/src/themes/mashroom/06-components/_components.breadcrumb.scss +0 -162
  368. package/src/themes/mashroom/06-components/_components.btn-group.scss +0 -404
  369. package/src/themes/mashroom/06-components/_components.button.scss +0 -160
  370. package/src/themes/mashroom/06-components/_components.callout.scss +0 -140
  371. package/src/themes/mashroom/06-components/_components.card.scss +0 -225
  372. package/src/themes/mashroom/06-components/_components.checkbox.scss +0 -186
  373. package/src/themes/mashroom/06-components/_components.color-mode-toggle.scss +0 -308
  374. package/src/themes/mashroom/06-components/_components.countdown.scss +0 -402
  375. package/src/themes/mashroom/06-components/_components.data-table.scss +0 -354
  376. package/src/themes/mashroom/06-components/_components.datepicker.scss +0 -349
  377. package/src/themes/mashroom/06-components/_components.dropdown.scss +0 -334
  378. package/src/themes/mashroom/06-components/_components.edge-panel.scss +0 -413
  379. package/src/themes/mashroom/06-components/_components.form-group.scss +0 -433
  380. package/src/themes/mashroom/06-components/_components.form.scss +0 -358
  381. package/src/themes/mashroom/06-components/_components.hero.scss +0 -151
  382. package/src/themes/mashroom/06-components/_components.input.scss +0 -147
  383. package/src/themes/mashroom/06-components/_components.list-group.scss +0 -456
  384. package/src/themes/mashroom/06-components/_components.list.scss +0 -145
  385. package/src/themes/mashroom/06-components/_components.menu.scss +0 -497
  386. package/src/themes/mashroom/06-components/_components.messages.scss +0 -277
  387. package/src/themes/mashroom/06-components/_components.modal.scss +0 -264
  388. package/src/themes/mashroom/06-components/_components.nav.scss +0 -181
  389. package/src/themes/mashroom/06-components/_components.navbar.scss +0 -538
  390. package/src/themes/mashroom/06-components/_components.pagination.scss +0 -400
  391. package/src/themes/mashroom/06-components/_components.photoviewer.scss +0 -498
  392. package/src/themes/mashroom/06-components/_components.popover.scss +0 -383
  393. package/src/themes/mashroom/06-components/_components.product-review.scss +0 -408
  394. package/src/themes/mashroom/06-components/_components.progress.scss +0 -249
  395. package/src/themes/mashroom/06-components/_components.rating.scss +0 -300
  396. package/src/themes/mashroom/06-components/_components.river.scss +0 -570
  397. package/src/themes/mashroom/06-components/_components.sectionintro.scss +0 -546
  398. package/src/themes/mashroom/06-components/_components.select.scss +0 -455
  399. package/src/themes/mashroom/06-components/_components.side-menu.scss +0 -635
  400. package/src/themes/mashroom/06-components/_components.skeleton.scss +0 -447
  401. package/src/themes/mashroom/06-components/_components.slider.scss +0 -414
  402. package/src/themes/mashroom/06-components/_components.spinner.scss +0 -198
  403. package/src/themes/mashroom/06-components/_components.steps.scss +0 -350
  404. package/src/themes/mashroom/06-components/_components.tabs.scss +0 -269
  405. package/src/themes/mashroom/06-components/_components.testimonials.scss +0 -561
  406. package/src/themes/mashroom/06-components/_components.toggle.scss +0 -231
  407. package/src/themes/mashroom/06-components/_components.tooltip.scss +0 -167
  408. package/src/themes/mashroom/06-components/_components.upload.scss +0 -537
  409. package/src/themes/mashroom/06-components/_components.video-player.scss +0 -560
  410. package/src/themes/mashroom/06-components/_index.scss +0 -55
  411. package/src/themes/mashroom/99-utilities/_index.scss +0 -6
  412. package/src/themes/mashroom/index.scss +0 -26
  413. package/src/themes/shaj-default/01-settings/_index.scss +0 -69
  414. package/src/themes/shaj-default/01-settings/_settings.accordion.scss +0 -38
  415. package/src/themes/shaj-default/01-settings/_settings.animations.scss +0 -32
  416. package/src/themes/shaj-default/01-settings/_settings.avatar-group.scss +0 -28
  417. package/src/themes/shaj-default/01-settings/_settings.avatar.scss +0 -63
  418. package/src/themes/shaj-default/01-settings/_settings.badge.scss +0 -25
  419. package/src/themes/shaj-default/01-settings/_settings.border-radius.scss +0 -24
  420. package/src/themes/shaj-default/01-settings/_settings.border.scss +0 -20
  421. package/src/themes/shaj-default/01-settings/_settings.box-shadow.scss +0 -46
  422. package/src/themes/shaj-default/01-settings/_settings.breadcrumb.scss +0 -0
  423. package/src/themes/shaj-default/01-settings/_settings.breakpoints.scss +0 -23
  424. package/src/themes/shaj-default/01-settings/_settings.btn-group.scss +0 -11
  425. package/src/themes/shaj-default/01-settings/_settings.button.scss +0 -56
  426. package/src/themes/shaj-default/01-settings/_settings.callout.scss +0 -87
  427. package/src/themes/shaj-default/01-settings/_settings.card.scss +0 -52
  428. package/src/themes/shaj-default/01-settings/_settings.checkbox-group.scss +0 -11
  429. package/src/themes/shaj-default/01-settings/_settings.checkbox.scss +0 -29
  430. package/src/themes/shaj-default/01-settings/_settings.color-mode.scss +0 -13
  431. package/src/themes/shaj-default/01-settings/_settings.colors.scss +0 -91
  432. package/src/themes/shaj-default/01-settings/_settings.config.scss +0 -4
  433. package/src/themes/shaj-default/01-settings/_settings.countdown.scss +0 -26
  434. package/src/themes/shaj-default/01-settings/_settings.data-table.scss +0 -62
  435. package/src/themes/shaj-default/01-settings/_settings.datepicker.scss +0 -51
  436. package/src/themes/shaj-default/01-settings/_settings.design-tokens.scss +0 -9
  437. package/src/themes/shaj-default/01-settings/_settings.dropdown.scss +0 -51
  438. package/src/themes/shaj-default/01-settings/_settings.edge-panel.scss +0 -30
  439. package/src/themes/shaj-default/01-settings/_settings.fonts.scss +0 -13
  440. package/src/themes/shaj-default/01-settings/_settings.form-group.scss +0 -20
  441. package/src/themes/shaj-default/01-settings/_settings.form.scss +0 -12
  442. package/src/themes/shaj-default/01-settings/_settings.grid.scss +0 -29
  443. package/src/themes/shaj-default/01-settings/_settings.hero.scss +0 -47
  444. package/src/themes/shaj-default/01-settings/_settings.input.scss +0 -57
  445. package/src/themes/shaj-default/01-settings/_settings.link.scss +0 -19
  446. package/src/themes/shaj-default/01-settings/_settings.list-group.scss +0 -22
  447. package/src/themes/shaj-default/01-settings/_settings.list.scss +0 -19
  448. package/src/themes/shaj-default/01-settings/_settings.masonry-grid.scss +0 -29
  449. package/src/themes/shaj-default/01-settings/_settings.menu.scss +0 -56
  450. package/src/themes/shaj-default/01-settings/_settings.messages.scss +0 -104
  451. package/src/themes/shaj-default/01-settings/_settings.modal.scss +0 -47
  452. package/src/themes/shaj-default/01-settings/_settings.nav.scss +0 -26
  453. package/src/themes/shaj-default/01-settings/_settings.navbar.scss +0 -60
  454. package/src/themes/shaj-default/01-settings/_settings.pagination.scss +0 -36
  455. package/src/themes/shaj-default/01-settings/_settings.photoviewer.scss +0 -51
  456. package/src/themes/shaj-default/01-settings/_settings.popover.scss +0 -26
  457. package/src/themes/shaj-default/01-settings/_settings.position.scss +0 -15
  458. package/src/themes/shaj-default/01-settings/_settings.progress.scss +0 -23
  459. package/src/themes/shaj-default/01-settings/_settings.rating.scss +0 -17
  460. package/src/themes/shaj-default/01-settings/_settings.river.scss +0 -56
  461. package/src/themes/shaj-default/01-settings/_settings.sectionintro.scss +0 -37
  462. package/src/themes/shaj-default/01-settings/_settings.select.scss +0 -53
  463. package/src/themes/shaj-default/01-settings/_settings.side-menu.scss +0 -85
  464. package/src/themes/shaj-default/01-settings/_settings.skeleton.scss +0 -30
  465. package/src/themes/shaj-default/01-settings/_settings.spacing.scss +0 -72
  466. package/src/themes/shaj-default/01-settings/_settings.spinner.scss +0 -24
  467. package/src/themes/shaj-default/01-settings/_settings.steps.scss +0 -39
  468. package/src/themes/shaj-default/01-settings/_settings.tabs.scss +0 -39
  469. package/src/themes/shaj-default/01-settings/_settings.testimonials.scss +0 -30
  470. package/src/themes/shaj-default/01-settings/_settings.todo.scss +0 -58
  471. package/src/themes/shaj-default/01-settings/_settings.toggle.scss +0 -55
  472. package/src/themes/shaj-default/01-settings/_settings.tooltip.scss +0 -26
  473. package/src/themes/shaj-default/01-settings/_settings.typography.scss +0 -101
  474. package/src/themes/shaj-default/01-settings/_settings.upload.scss +0 -102
  475. package/src/themes/shaj-default/01-settings/_settings.z-layers.scss +0 -25
  476. package/src/themes/shaj-default/02-tools/_index.scss +0 -0
  477. package/src/themes/shaj-default/03-generic/_generic.root.scss +0 -0
  478. package/src/themes/shaj-default/03-generic/_index.scss +0 -2
  479. package/src/themes/shaj-default/04-elements/_index.scss +0 -0
  480. package/src/themes/shaj-default/05-objects/_index.scss +0 -0
  481. package/src/themes/shaj-default/06-components/_components.button.scss +0 -55
  482. package/src/themes/shaj-default/06-components/_components.card.scss +0 -57
  483. package/src/themes/shaj-default/06-components/_components.input.scss +0 -58
  484. package/src/themes/shaj-default/06-components/_components.navbar.scss +0 -99
  485. package/src/themes/shaj-default/06-components/_components.tooltip.scss +0 -0
  486. package/src/themes/shaj-default/06-components/_index.scss +0 -13
  487. package/src/themes/shaj-default/99-utilities/_index.scss +0 -0
  488. package/src/themes/shaj-default/index.scss +0 -25
  489. package/theme.config.ts +0 -360
package/dist/heavy.js ADDED
@@ -0,0 +1,4550 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+
3
+ import React, { memo, forwardRef, useId, useState, useRef, useEffect, useMemo, useCallback, useImperativeHandle, Children, isValidElement } from "react";
4
+
5
+ import * as PhosphorIcons from "@phosphor-icons/react";
6
+
7
+ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Download, Share, ArrowsIn, ArrowsOut } from "@phosphor-icons/react";
8
+
9
+ /**
10
+ * Default theme colors for components
11
+ */
12
+ /**
13
+ * Button-specific constants
14
+ */ const BUTTON = {
15
+ BASE_CLASS: "c-btn",
16
+ ICON_CLASS: "c-btn__icon",
17
+ LABEL_CLASS: "c-btn__label",
18
+ SPINNER_CLASS: "c-btn__spinner",
19
+ VARIANT_PREFIX: "c-btn--",
20
+ CLASSES: {
21
+ BASE: "c-btn",
22
+ LOADING: "c-btn--loading",
23
+ FULL_WIDTH: "c-btn--full-width",
24
+ BLOCK: "c-btn--block",
25
+ ACTIVE: "c-btn--active",
26
+ SELECTED: "c-btn--selected"
27
+ }
28
+ }, VIDEO_PLAYER_CLASSES_BASE = "c-video-player", VIDEO_PLAYER_CLASSES_VIDEO = "c-video-player__video", VIDEO_PLAYER_CLASSES_YOUTUBE = "c-video-player--youtube", VIDEO_PLAYER_CLASSES_LOADING = "c-video-player__loading", VIDEO_PLAYER_CLASSES_SPINNER = "c-video-player__spinner", VIDEO_PLAYER_CLASSES_CONTROLS = "c-video-player__controls", VIDEO_PLAYER_CLASSES_CONTROLS_VISIBLE = "c-video-player__controls--visible", VIDEO_PLAYER_CLASSES_PROGRESS_CONTAINER = "c-video-player__progress-container", VIDEO_PLAYER_CLASSES_PROGRESS_BAR = "c-video-player__progress-bar", VIDEO_PLAYER_CLASSES_PROGRESS_BUFFERED = "c-video-player__progress-buffered", VIDEO_PLAYER_CLASSES_PROGRESS_PLAYED = "c-video-player__progress-played", VIDEO_PLAYER_CLASSES_PROGRESS_THUMB = "c-video-player__progress-thumb", VIDEO_PLAYER_CLASSES_CONTROLS_ROW = "c-video-player__controls-row", VIDEO_PLAYER_CLASSES_CONTROLS_LEFT = "c-video-player__controls-left", VIDEO_PLAYER_CLASSES_CONTROLS_RIGHT = "c-video-player__controls-right", VIDEO_PLAYER_CLASSES_CONTROL_BUTTON = "c-video-player__control-button", VIDEO_PLAYER_CLASSES_VOLUME_CONTAINER = "c-video-player__volume-container", VIDEO_PLAYER_CLASSES_VOLUME_SLIDER = "c-video-player__volume-slider", VIDEO_PLAYER_CLASSES_VOLUME_BAR = "c-video-player__volume-bar", VIDEO_PLAYER_CLASSES_VOLUME_FILL = "c-video-player__volume-fill", VIDEO_PLAYER_CLASSES_TIME_DISPLAY = "c-video-player__time-display", VIDEO_PLAYER_CLASSES_SETTINGS_CONTAINER = "c-video-player__settings-container", VIDEO_PLAYER_CLASSES_SETTINGS_MENU = "c-video-player__settings-menu", VIDEO_PLAYER_CLASSES_SETTINGS_TABS = "c-video-player__settings-tabs", VIDEO_PLAYER_CLASSES_SETTINGS_TAB = "c-video-player__settings-tab", VIDEO_PLAYER_CLASSES_SETTINGS_TAB_ACTIVE = "c-video-player__settings-tab--active", VIDEO_PLAYER_CLASSES_SETTINGS_CONTENT = "c-video-player__settings-content", VIDEO_PLAYER_CLASSES_SETTINGS_OPTIONS = "c-video-player__settings-options", VIDEO_PLAYER_CLASSES_SETTINGS_OPTION = "c-video-player__settings-option", VIDEO_PLAYER_CLASSES_SETTINGS_OPTION_ACTIVE = "c-video-player__settings-option--active", VIDEO_PLAYER_CLASSES_AMBIENT = "c-video-player--ambient", VIDEO_PLAYER_CLASSES_AMBIENT_CANVAS = "c-video-player__ambient-canvas", VIDEO_PLAYER_CLASSES_GLASS = "c-video-player--glass", VIDEO_PLAYER_CLASSES_GLASS_OVERLAY = "c-video-player__glass-overlay", VIDEO_PLAYER_CLASSES_GLASS_CONTENT = "c-video-player__glass-content", ATOMIX_GLASS = {
29
+ BASE_CLASS: "c-atomix-glass",
30
+ CONTAINER_CLASS: "c-atomix-glass__container",
31
+ INNER_CLASS: "c-atomix-glass__inner",
32
+ FILTER_CLASS: "c-atomix-glass__filter",
33
+ FILTER_OVERLAY_CLASS: "c-atomix-glass__filter-overlay",
34
+ FILTER_SHADOW_CLASS: "c-atomix-glass__filter-shadow",
35
+ CONTENT_CLASS: "c-atomix-glass__content",
36
+ BORDER_1_CLASS: "c-atomix-glass__border-1",
37
+ BORDER_2_CLASS: "c-atomix-glass__border-2",
38
+ HOVER_1_CLASS: "c-atomix-glass__hover-1",
39
+ HOVER_2_CLASS: "c-atomix-glass__hover-2",
40
+ HOVER_3_CLASS: "c-atomix-glass__hover-3",
41
+ BASE_LAYER_CLASS: "c-atomix-glass__base",
42
+ OVERLAY_LAYER_CLASS: "c-atomix-glass__overlay",
43
+ OVERLAY_HIGHLIGHT_CLASS: "c-atomix-glass__overlay-highlight",
44
+ BACKGROUND_LAYER_CLASS: "c-atomix-glass__background-layer",
45
+ BACKGROUND_LAYER_DARK_CLASS: "c-atomix-glass__background-layer--dark",
46
+ BACKGROUND_LAYER_BLACK_CLASS: "c-atomix-glass__background-layer--black",
47
+ BACKGROUND_LAYER_OVER_LIGHT_CLASS: "c-atomix-glass__background-layer--over-light",
48
+ BACKGROUND_LAYER_HIDDEN_CLASS: "c-atomix-glass__background-layer--hidden",
49
+ VARIANT_PREFIX: "c-atomix-glass--",
50
+ MODE_PREFIX: "c-atomix-glass--",
51
+ CLASSES: {
52
+ BASE: "c-atomix-glass",
53
+ CONTAINER: "c-atomix-glass__container",
54
+ INNER: "c-atomix-glass__inner",
55
+ FILTER: "c-atomix-glass__filter",
56
+ CONTENT: "c-atomix-glass__content",
57
+ ACTIVE: "active",
58
+ OVER_LIGHT: "c-atomix-glass__container--over-light",
59
+ // Mode variants
60
+ STANDARD: "c-atomix-glass--standard",
61
+ POLAR: "c-atomix-glass--polar",
62
+ PROMINENT: "c-atomix-glass--prominent",
63
+ SHADER: "c-atomix-glass--shader"
64
+ },
65
+ DEFAULTS: {
66
+ DISPLACEMENT_SCALE: 20,
67
+ BLUR_AMOUNT: 1,
68
+ SATURATION: 140,
69
+ ABERRATION_INTENSITY: 2.5,
70
+ ELASTICITY: .05,
71
+ CORNER_RADIUS: 16,
72
+ // Default border-radius matching design system
73
+ PADDING: "0 0",
74
+ MODE: "standard",
75
+ OVER_LIGHT: !1,
76
+ ENABLE_OVER_LIGHT_LAYERS: !0
77
+ },
78
+ CONSTANTS: {
79
+ ACTIVATION_ZONE: 200,
80
+ MIN_BLUR: .1,
81
+ MOUSE_INFLUENCE_DIVISOR: 100,
82
+ EDGE_FADE_PIXELS: 2,
83
+ DEFAULT_CORNER_RADIUS: 16,
84
+ // Fallback value matching design system
85
+ MAX_SIZE: 4096,
86
+ // Maximum width/height for glass size
87
+ // Gradient calculation constants
88
+ GRADIENT: {
89
+ BASE_ANGLE: 135,
90
+ // Base angle for border gradients (degrees)
91
+ ANGLE_MULTIPLIER: 1.2,
92
+ // Multiplier for mouse influence on angle
93
+ BORDER_STOP_1: {
94
+ MIN: 10,
95
+ // Minimum percentage for border stop 1
96
+ BASE: 33,
97
+ // Base percentage for border stop 1
98
+ MULTIPLIER: .3
99
+ },
100
+ BORDER_STOP_2: {
101
+ MAX: 90,
102
+ // Maximum percentage for border stop 2
103
+ BASE: 66,
104
+ // Base percentage for border stop 2
105
+ MULTIPLIER: .4
106
+ },
107
+ BORDER_OPACITY: {
108
+ BASE_1: .12,
109
+ // Base opacity for border gradient 1
110
+ BASE_2: .4,
111
+ // Base opacity for border gradient 2
112
+ BASE_3: .32,
113
+ // Base opacity for border gradient 3
114
+ BASE_4: .6,
115
+ // Base opacity for border gradient 4
116
+ MULTIPLIER_LOW: .008,
117
+ // Low multiplier for mouse influence on opacity
118
+ MULTIPLIER_HIGH: .012
119
+ },
120
+ CENTER_POSITION: 50,
121
+ // Center position percentage (50%)
122
+ HOVER_POSITION: {
123
+ DIVISOR_1: 2,
124
+ // Divisor for hover 1 position calculation
125
+ DIVISOR_2: 1.5,
126
+ // Divisor for hover 2 position calculation
127
+ MULTIPLIER_3: 1
128
+ },
129
+ BASE_LAYER_MULTIPLIER: .5
130
+ },
131
+ // Gradient opacity values for hover effects
132
+ GRADIENT_OPACITY: {
133
+ HOVER_1: {
134
+ BLACK_START: .3,
135
+ // Start opacity for black hover 1
136
+ BLACK_MID: .1,
137
+ // Mid opacity for black hover 1
138
+ BLACK_STOP: 30,
139
+ // Stop percentage for black hover 1
140
+ BLACK_END: 60,
141
+ // End percentage for black hover 1
142
+ WHITE_START: .5,
143
+ // Start opacity for white hover 1
144
+ WHITE_STOP: 50
145
+ },
146
+ HOVER_2: {
147
+ BLACK_START: .4,
148
+ // Start opacity for black hover 2
149
+ BLACK_MID: .15,
150
+ // Mid opacity for black hover 2
151
+ BLACK_STOP: 40,
152
+ // Stop percentage for black hover 2
153
+ BLACK_END: 80,
154
+ // End percentage for black hover 2
155
+ WHITE_START: 1,
156
+ // Start opacity for white hover 2
157
+ WHITE_STOP: 80
158
+ },
159
+ HOVER_3: {
160
+ BLACK_START: .5,
161
+ // Start opacity for black hover 3
162
+ BLACK_MID: .2,
163
+ // Mid opacity for black hover 3
164
+ BLACK_STOP: 50,
165
+ // Stop percentage for black hover 3
166
+ BLACK_END: 100,
167
+ // End percentage for black hover 3
168
+ WHITE_START: 1,
169
+ // Start opacity for white hover 3
170
+ WHITE_STOP: 100
171
+ }
172
+ },
173
+ // Base and overlay gradient constants
174
+ BASE_GRADIENT: {
175
+ ANGLE: 135,
176
+ // Gradient angle in degrees
177
+ BLACK_START_BASE: .15,
178
+ // Base start opacity for black
179
+ BLACK_START_MULTIPLIER: .003,
180
+ // Multiplier for mouse X influence on start
181
+ BLACK_MID_BASE: .1,
182
+ // Base mid opacity for black
183
+ BLACK_MID_MULTIPLIER: .002,
184
+ // Multiplier for mouse Y influence on mid
185
+ BLACK_MID_STOP: 50,
186
+ // Mid stop percentage
187
+ BLACK_END_BASE: .18,
188
+ // Base end opacity for black
189
+ BLACK_END_MULTIPLIER: .004,
190
+ // Multiplier for mouse X influence on end
191
+ WHITE_OPACITY: .1
192
+ },
193
+ OVERLAY_GRADIENT: {
194
+ BLACK_START_BASE: .12,
195
+ // Base start opacity for black overlay
196
+ BLACK_START_MULTIPLIER: .003,
197
+ // Multiplier for mouse X influence on start
198
+ BLACK_MID: .06,
199
+ // Mid opacity for black overlay
200
+ BLACK_MID_STOP: 40,
201
+ // Mid stop percentage
202
+ BLACK_END_BASE: .15,
203
+ // Base end opacity for black overlay
204
+ BLACK_END_MULTIPLIER: .003,
205
+ // Multiplier for mouse Y influence on end
206
+ WHITE_OPACITY: .05
207
+ },
208
+ // Overlay highlight constants
209
+ OVERLAY_HIGHLIGHT: {
210
+ POSITION_X: 20,
211
+ // X position percentage
212
+ POSITION_Y: 20,
213
+ // Y position percentage
214
+ WHITE_OPACITY: .4,
215
+ // White opacity in gradient
216
+ STOP: 60,
217
+ // Stop percentage
218
+ OPACITY_MULTIPLIER: .7
219
+ },
220
+ // Displacement and aberration multipliers
221
+ MULTIPLIERS: {
222
+ SHADER_DISPLACEMENT: .8,
223
+ // Displacement scale multiplier for shader mode
224
+ OVER_LIGHT_DISPLACEMENT: .6,
225
+ // Displacement scale multiplier for over-light mode
226
+ SHADER_ABERRATION: .7
227
+ },
228
+ // Saturation constants
229
+ SATURATION: {
230
+ HIGH_CONTRAST: 200
231
+ }
232
+ }
233
+ }, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS, calculateDistance = (pos1, pos2) => {
234
+ if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
235
+ const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
236
+ return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
237
+ }, calculateElementCenter = rect => rect ? {
238
+ x: rect.left + rect.width / 2,
239
+ y: rect.top + rect.height / 2
240
+ } : {
241
+ x: 0,
242
+ y: 0
243
+ }, calculateMouseInfluence = mouseOffset => {
244
+ if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
245
+ // More responsive calculation for overlight effects
246
+ const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$1.MOUSE_INFLUENCE_DIVISOR;
247
+ return Math.min(1.5, influence);
248
+ // Cap influence for better control
249
+ }, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$1.MIN_BLUR : Math.max(CONSTANTS$1.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$1.MAX_SIZE && size.height <= CONSTANTS$1.MAX_SIZE, parseBorderRadiusValue = value => {
250
+ if ("number" == typeof value) return Math.max(0, value);
251
+ if ("string" != typeof value || !value.trim()) return CONSTANTS$1.DEFAULT_CORNER_RADIUS;
252
+ const trimmedValue = value.trim();
253
+ // Handle px values
254
+ if (trimmedValue.endsWith("px")) {
255
+ const parsed = parseFloat(trimmedValue);
256
+ return isNaN(parsed) ? CONSTANTS$1.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
257
+ }
258
+ // Handle rem values (assume 16px = 1rem)
259
+ if (trimmedValue.endsWith("rem")) {
260
+ const parsed = parseFloat(trimmedValue);
261
+ return isNaN(parsed) ? CONSTANTS$1.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
262
+ }
263
+ // Handle em values (assume 16px = 1em for simplicity)
264
+ if (trimmedValue.endsWith("em")) {
265
+ const parsed = parseFloat(trimmedValue);
266
+ return isNaN(parsed) ? CONSTANTS$1.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
267
+ }
268
+ // Handle percentage (convert to approximate px value, assuming 200px container)
269
+ if (trimmedValue.endsWith("%")) {
270
+ const parsed = parseFloat(trimmedValue);
271
+ return isNaN(parsed) ? CONSTANTS$1.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
272
+ }
273
+ // Handle unitless numbers
274
+ const numValue = parseFloat(trimmedValue);
275
+ return isNaN(numValue) ? CONSTANTS$1.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
276
+ }, extractBorderRadiusFromElement = element => {
277
+ if (!element || !element.props) return null;
278
+ // Check inline styles first (highest priority)
279
+ if (element.props.style) {
280
+ const radiusFromStyle = (style => {
281
+ if (!style) return null;
282
+ // Check various border-radius properties
283
+ const borderRadius = style.borderRadius || style.borderTopLeftRadius || style.borderTopRightRadius || style.borderBottomLeftRadius || style.borderBottomRightRadius;
284
+ return void 0 !== borderRadius ? parseBorderRadiusValue(borderRadius) : null;
285
+ })(element.props.style);
286
+ if (null !== radiusFromStyle && radiusFromStyle > 0) return radiusFromStyle;
287
+ }
288
+ // If element has children, recursively check them
289
+ if (element.props.children) {
290
+ const childRadius = extractBorderRadiusFromChildren(element.props.children);
291
+ if (childRadius > 0 && childRadius !== CONSTANTS$1.DEFAULT_CORNER_RADIUS) return childRadius;
292
+ }
293
+ return null;
294
+ }, extractBorderRadiusFromChildren = children => {
295
+ if (!children) return CONSTANTS$1.DEFAULT_CORNER_RADIUS;
296
+ try {
297
+ const childArray = React.Children.toArray(children);
298
+ for (let i = 0; i < childArray.length; i++) {
299
+ const child = childArray[i];
300
+ if ( React.isValidElement(child)) {
301
+ const radius = extractBorderRadiusFromElement(child);
302
+ if (null !== radius) return radius;
303
+ }
304
+ }
305
+ } catch (error) {
306
+ // Silently handle errors
307
+ }
308
+ return CONSTANTS$1.DEFAULT_CORNER_RADIUS;
309
+ }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
310
+ switch (mode) {
311
+ case "standard":
312
+ return displacementMap;
313
+
314
+ case "polar":
315
+ return polarDisplacementMap;
316
+
317
+ case "prominent":
318
+ return prominentDisplacementMap;
319
+
320
+ case "shader":
321
+ return shaderMapUrl || displacementMap;
322
+
323
+ default:
324
+ return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
325
+ }
326
+ }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
327
+ style: {
328
+ position: "absolute",
329
+ width: "100%",
330
+ height: "100%",
331
+ inset: 0
332
+ },
333
+ "aria-hidden": "true",
334
+ suppressHydrationWarning: !0,
335
+ children: jsxs("defs", {
336
+ children: [ jsxs("radialGradient", {
337
+ id: `${id}-edge-mask`,
338
+ cx: "50%",
339
+ cy: "50%",
340
+ r: "50%",
341
+ children: [ jsx("stop", {
342
+ offset: "0%",
343
+ stopColor: "black",
344
+ stopOpacity: "0"
345
+ }), jsx("stop", {
346
+ offset: `${Math.max(30, 80 - 2 * aberrationIntensity)}%`,
347
+ stopColor: "black",
348
+ stopOpacity: "0"
349
+ }), jsx("stop", {
350
+ offset: "100%",
351
+ stopColor: "white",
352
+ stopOpacity: "1"
353
+ }) ]
354
+ }), jsxs("filter", {
355
+ id: id,
356
+ x: "-35%",
357
+ y: "-35%",
358
+ width: "170%",
359
+ height: "170%",
360
+ colorInterpolationFilters: "sRGB",
361
+ children: [ jsx("feImage", {
362
+ id: "feimage",
363
+ x: "0",
364
+ y: "0",
365
+ width: "100%",
366
+ height: "100%",
367
+ result: "DISPLACEMENT_MAP",
368
+ href: getDisplacementMap(mode, "data:image/jpeg;base64,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cUAUAkEkziomgGgkoxZGgxZFQFQlYnQHRdPfj/10KCSCKESCNiVkViPSLpD0h6I0Q0I0A2IoBWBIJIBKBIJoJIJ2R2J0JWBUJ0JUB0XTv479dFZDYiglYigkhEgjZFQjRFQjRFQjQigFYigHYigmgEgmglYlYnQlQlYlQHQlQnQ9P/kf1yVkNiNCNkNiVENiNiViNEViNkVCVgKCViViViSCViSCVgdCViVCViVCdgVCVCdD1D+U/XBWQ2I0I2Q2JUQ2I0JWQ0I2JUQ2JUI2JUI2J0JWJWJWA2R0BWJ0I2JUJ2BUJUJ0P//EABkQAQEBAQEBAAAAAAAAAAAAAAECABEDEP/aAAgBAQABAgB1atWrVq1atWrVq1atWrVq1atWrVq1atWrVq+OrVq1atWrVq1atWrVq1atWrVq1atWrVq1atXxVppppppdWrVq1atWrVq1NNNNNNNNNNNPVWmmmmms6tWrVq1atWpppppppppppppp6q0000uc51atWrVq1ammmmmmmmmmmmmt1Vpppc5znVq1atWrVqaaaaaaaaaaaaaeqtNLnOc51atWrVq1ammmmmmmmmmmmmnqrS5znOc6tWrVq16222mmmmmmlVppp6tKuc5znOrVq1a9TbbbbTTTTTSq000qtLnOc5zq1atWrW0222200000qqqtKqrnOc5zq1atTbbbbbbbbTTTSqqqqqq5znOc6tTTTbbbbbbbbTTTSqqqqrlVznOctNNNtttttttttNNNNKqqqrqznKqrTTTTbbbbbbbbbTTTSqqqqrqznOc5aaaabbbbbbbbbaaaaVVVVVdWc5znVq1NNttttttttttNNKqqqqudWc5znVq16tbbbbbbbbbbTTSqqqq5XVnOc6tWrVrb1tttttttttNNKqqqqrWrK5VWmmm2230bbbbbbaaaXOc5zlVa1KuVVppptttt9G22222mmlzlVznK6tWVVWmmmm2222222222mlznOc5znLWppVVWmmm22222229bTWrOc5znOcq1qaaVpWmm222222229erVqznOc5znKtatStK0rTbTTbbbberXr1as5znOc5aVpppppWlabaabbbb1ta9WrVnOc5znU0rTTTTTTTTTbTTbbbTWvVq1as5znOdTTStNNNNNNNNNtNNtttN6tWvVq1ZznOrU00rTTTTTTTTTTTTTbTWvVq1atWrOc6tTTTStNNNNNNNNNNtNNtNa9WrVq1Z1Z1NNNNNK1q1NNNNNNNNNNNtNatWrVq1atWrU00000rWrVq1atWrVq1alaaa1atWrVq1NNNammmmla1atWrVq1aterVq16tWrVnVqa1NK1qaaaVX/xAAWEAADAAAAAAAAAAAAAAAAAAAhgJD/2gAIAQEAAz8AaExf/8QAGhEBAQEBAQEBAAAAAAAAAAAAAQISEQADEP/aAAgBAgEBAgDx48ePHjx48ePHjx48ePHjx48ePHjx48ePHj86IiIiIiInjx48ePHjx48IiIiIj0oooooooooRERER73ve60UUUUUUVrWiiiiiihERERER73ve97ooooorRWiiiiihKERERER73ve973RRRRWtFFFFFFCIiIiIiPe973ve60UUVrRRRRRRQiIlCIiI973ve973pRRWiiiiiiiiiiiiiiihEe973ve973RRWtFFFFFFFFFFFFFFFFFFa13ve973WitaKKKKKKKKKKKKKKKKKK1rWtd1rutFa1oooooooooooosssooorWta1rWta1rRRRRRRRRRRZZZZZZZZZWta1rWta1rRRRRRRRRZZZZZZZZZZZZe9a1rWta1rWitaKLLLLLLLLLLLLLLLLL3rWta1rWtFbLLLLLLLLLLLLLLLLLLLL3vWta1rWita1ssssssss+hZZZZZZZZe961rWta0Vre97LLLLLLLLLLLPoWWWWWXrWta1oorWta3ssss+hZZZZ9Cyyyyyyyyiita1orWta1ve9llllllllllllllllFFa0VorWta1ve9llllllllllllllllllFFFaK1rWta1rWiyyyyyyyyyyyyiiiiiiitFFa1rWta1oosoosssssoooosoooorRRRWta1rWta0UUUUUWUUUUUUUUUUUVoooorWta1rWtaKKKKKKmiiiiiiiiiiiiiiitd73ve61oSiiipoqaKKKKKKKKKK0UUUVrve973vREREZoSihEooooorRRRRWtd73ve9EREREREoSiiiiitFllllla73ve9ERERERESiiiiiitH0PoWWWWVrXe96IiIiMoiJRRRRRRWjwlFFllllFFd6IiIiIlCUUUUUUUUUePHjx48ePCIiIiIiIiUUUUUUUUUUUePHjx48ePHjx48ePHjx48IiUUUUUUJRRRX//xAAWEQADAAAAAAAAAAAAAAAAAAABYJD/2gAIAQIBAz8AtEV7/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAECEP/aAAgBAwEBAgCtNNNNNNNNNNNNNNNNNNNNNNNNNNNNNcrTTTTTTTTTTTTTTTTTTTTTTTTTTTTTXKrTTTTTTTU000000000000000000001FVpppppqampqaaaaaaaaaaaaaaaaaaaa5Vaaaaampqampqammmmmmmmmmmlaaaaaaiq0001NTU1NTU1NTTTTTTTTTTSqqtNNNcqtNNSyzU1LNTU1NTTTTTTTTTSqqq001ytNLLLLNTU1NTU1NTbbbTTTTTSqqq001ytNLLLLLNTU1NTU3NttttNNNNNKqq001KrSyyyyyzU1NTU3Nzc02220000qqqqrSqqyyyyyzU1NTU3Nzc3NttttNNNKqqqqqqssssss1NTU3Nzc3NzbbbbTTTSqqqqqqrLLLLLNTU1Nzc3Nzc22220000qqqqqqqqssss1NTU3Nzc3NzbbbbbTTSqqqqqqqqqqzU1NTc3Nzc3Nzbc22000qqqqqqqqqqqtTU3Nzc3Nzc3NtzbTTSqqqqrKqqqqqtNNzc23Nzc3Nzc3NTU1KqqqrKqqqqqtNNNNttzc3Nzc3NzU1NLLLLLKqqqqqqqq0022223Nzc3NzU1NSyyyyyyqqqqqqqrTTbbbbc3Nzc3NTU1LLLLLLKsqqqqqqrTTTTbbbc3Nzc1NTUsssssssqqqqqqrTTTTTbbbTc3NTU1NTUsssssqqqqqqqq0000222023NTU1NTUsssssqqqqqqqq000000003NTU1NTU1LLLLLNKrTSqqqqtNNNNNNtNNTU1NSzUssss00qq0qqqqrTTTTTTTTTU1NTUs1LLLNNNKrTTTSqqq00000000001NTU1LNTU0000qtNNNKqqqtNNNNNNNNTU1NTUs1NNNNNKss1NNNK00qtK0000001NNTU0s000000qq000001NKrStNNNNK1NNNNStNNNNNKqtNNNNNNNK0000000rU0000rTTTTTSq00000rTTTTTTTTTTTTTTTTStNNNNKr/xAAUEQEAAAAAAAAAAAAAAAAAAACg/9oACAEDAQM/AAAf/9k=", "data:image/jpeg;base64,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", "data:image/png;base64,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", shaderMapUrl),
369
+ preserveAspectRatio: "xMidYMid slice"
370
+ }), jsx("feColorMatrix", {
371
+ in: "DISPLACEMENT_MAP",
372
+ type: "matrix",
373
+ values: "0.3 0.3 0.3 0 0\n 0.3 0.3 0.3 0 0\n 0.3 0.3 0.3 0 0\n 0 0 0 1 0",
374
+ result: "EDGE_INTENSITY"
375
+ }), jsx("feComponentTransfer", {
376
+ in: "EDGE_INTENSITY",
377
+ result: "EDGE_MASK",
378
+ children: jsx("feFuncA", {
379
+ type: "discrete",
380
+ tableValues: `0 ${.05 * aberrationIntensity} 1`
381
+ })
382
+ }), jsx("feOffset", {
383
+ in: "SourceGraphic",
384
+ dx: "0",
385
+ dy: "0",
386
+ result: "CENTER_ORIGINAL"
387
+ }), jsx("feDisplacementMap", {
388
+ in: "SourceGraphic",
389
+ in2: "DISPLACEMENT_MAP",
390
+ scale: displacementScale * ("shader" === mode ? 1 : -1),
391
+ xChannelSelector: "R",
392
+ yChannelSelector: "B",
393
+ result: "RED_DISPLACED"
394
+ }), jsx("feColorMatrix", {
395
+ in: "RED_DISPLACED",
396
+ type: "matrix",
397
+ values: "1 0 0 0 0\n 0 0 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
398
+ result: "RED_CHANNEL"
399
+ }), jsx("feDisplacementMap", {
400
+ in: "SourceGraphic",
401
+ in2: "DISPLACEMENT_MAP",
402
+ scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
403
+ xChannelSelector: "R",
404
+ yChannelSelector: "B",
405
+ result: "GREEN_DISPLACED"
406
+ }), jsx("feColorMatrix", {
407
+ in: "GREEN_DISPLACED",
408
+ type: "matrix",
409
+ values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
410
+ result: "GREEN_CHANNEL"
411
+ }), jsx("feDisplacementMap", {
412
+ in: "SourceGraphic",
413
+ in2: "DISPLACEMENT_MAP",
414
+ scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
415
+ xChannelSelector: "R",
416
+ yChannelSelector: "B",
417
+ result: "BLUE_DISPLACED"
418
+ }), jsx("feColorMatrix", {
419
+ in: "BLUE_DISPLACED",
420
+ type: "matrix",
421
+ values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
422
+ result: "BLUE_CHANNEL"
423
+ }), jsx("feBlend", {
424
+ in: "GREEN_CHANNEL",
425
+ in2: "BLUE_CHANNEL",
426
+ mode: "screen",
427
+ result: "GB_COMBINED"
428
+ }), jsx("feBlend", {
429
+ in: "RED_CHANNEL",
430
+ in2: "GB_COMBINED",
431
+ mode: "screen",
432
+ result: "RGB_COMBINED"
433
+ }), jsx("feGaussianBlur", {
434
+ in: "RGB_COMBINED",
435
+ result: "ABERRATED_BLURRED",
436
+ stdDeviation: blurAmount * aberrationIntensity * .05
437
+ }), jsx("feComposite", {
438
+ in: "ABERRATED_BLURRED",
439
+ in2: "EDGE_MASK",
440
+ operator: "in",
441
+ result: "EDGE_ABERRATION"
442
+ }), jsx("feComponentTransfer", {
443
+ in: "EDGE_MASK",
444
+ result: "INVERTED_MASK",
445
+ children: jsx("feFuncA", {
446
+ type: "table",
447
+ tableValues: "1 0"
448
+ })
449
+ }), jsx("feComposite", {
450
+ in: "CENTER_ORIGINAL",
451
+ in2: "INVERTED_MASK",
452
+ operator: "in",
453
+ result: "CENTER_CLEAN"
454
+ }), jsx("feComposite", {
455
+ in: "EDGE_ABERRATION",
456
+ in2: "CENTER_CLEAN",
457
+ operator: "over"
458
+ }) ]
459
+ }) ]
460
+ })
461
+ });
462
+
463
+ /**
464
+ * Badge-specific constants
465
+ */ GlassFilterComponent.displayName = "GlassFilter";
466
+
467
+ // Memoize component to prevent unnecessary re-renders
468
+ const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount)), sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
469
+ x: 0,
470
+ y: 0
471
+ }, globalMousePosition: globalMousePosition = {
472
+ x: 0,
473
+ y: 0
474
+ }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, active: active = !1, isHovered: isHovered = !1, isActive: isActive = !1, overLight: overLight = !1, cornerRadius: cornerRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
475
+ width: 0,
476
+ height: 0
477
+ }, onClick: onClick, mode: mode = "standard", effectiveDisableEffects: effectiveDisableEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", enableLiquidBlur: enableLiquidBlur = !1, elasticity: elasticity = 0, contentRef: contentRef}, ref) => {
478
+ // Use React's useId() for SSR compatibility
479
+ // Note: In Next.js, IDs may differ between server and client
480
+ // We'll suppress hydration warnings on elements that use this ID
481
+ const filterId = useId(), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null);
482
+ // Lazy load shader utilities only when shader mode is needed
483
+ useEffect((() => {
484
+ "shader" === mode ?
485
+ // Dynamic import shader utilities
486
+ Promise.resolve().then((() => shaderUtils)).then((shaderUtils => {
487
+ shaderUtilsRef.current = {
488
+ ShaderDisplacementGenerator: shaderUtils.ShaderDisplacementGenerator,
489
+ fragmentShaders: shaderUtils.fragmentShaders
490
+ };
491
+ })).catch((error => {
492
+ console.warn("AtomixGlassContainer: Error loading shader utilities", error);
493
+ })) :
494
+ // Clear shader utils when not in shader mode to free memory
495
+ shaderUtilsRef.current = null;
496
+ }), [ mode ]),
497
+ // Generate shader map with debouncing and caching
498
+ useEffect((() => {
499
+ // Enhanced validation for shader mode
500
+ if ("shader" === mode && glassSize && validateGlassSize(glassSize) && shaderUtilsRef.current) {
501
+ // Create cache key from size and variant
502
+ const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
503
+ const entry = sharedShaderCache.get(key);
504
+ return entry ? (
505
+ // Update access timestamp for LRU
506
+ entry.timestamp = Date.now(), entry.url) : null;
507
+ })(cacheKey);
508
+ // Check shared cache first
509
+ if (cachedUrl) return void setShaderMapUrl(cachedUrl);
510
+ // Clear any pending debounce
511
+ shaderDebounceTimeoutRef.current && clearTimeout(shaderDebounceTimeoutRef.current);
512
+ // Debounce shader generation to avoid blocking on rapid size changes
513
+ const generateShader = () => {
514
+ if (shaderUtilsRef.current) try {
515
+ const {ShaderDisplacementGenerator: ShaderDisplacementGenerator, fragmentShaders: fragmentShaders} = shaderUtilsRef.current;
516
+ shaderGeneratorRef.current?.destroy();
517
+ const selectedShader = fragmentShaders[shaderVariant] || fragmentShaders.liquidGlass;
518
+ shaderGeneratorRef.current = new ShaderDisplacementGenerator({
519
+ width: glassSize.width,
520
+ height: glassSize.height,
521
+ fragment: selectedShader
522
+ });
523
+ // Use requestIdleCallback if available for non-blocking generation
524
+ const generate = () => {
525
+ const url = shaderGeneratorRef.current?.updateShader() || "";
526
+ ((key, url) => {
527
+ // Evict oldest entries if at capacity
528
+ if (sharedShaderCache.size >= 15) {
529
+ const entries = Array.from(sharedShaderCache.entries());
530
+ // Sort by timestamp (oldest first)
531
+ entries.sort(((a, b) => a[1].timestamp - b[1].timestamp));
532
+ // Remove oldest entry
533
+ const oldestEntry = entries[0];
534
+ oldestEntry && sharedShaderCache.delete(oldestEntry[0]);
535
+ }
536
+ sharedShaderCache.set(key, {
537
+ url: url,
538
+ timestamp: Date.now()
539
+ }),
540
+ // Development mode: log cache size
541
+ "production" !== process.env.NODE_ENV && sharedShaderCache.size;
542
+ })(cacheKey, url), setShaderMapUrl(url);
543
+ };
544
+ "undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
545
+ timeout: 1e3
546
+ }) :
547
+ // Fallback to setTimeout for browsers without requestIdleCallback
548
+ setTimeout(generate, 0);
549
+ } catch (error) {
550
+ console.warn("AtomixGlassContainer: Error generating shader map", error), setShaderMapUrl("");
551
+ } else
552
+ // Shader utils not loaded yet, retry after a short delay
553
+ shaderDebounceTimeoutRef.current = setTimeout(generateShader, 100);
554
+ };
555
+ // Debounce with 300ms delay
556
+ shaderDebounceTimeoutRef.current = setTimeout(generateShader, 300);
557
+ } else
558
+ // Not in shader mode, clear URL
559
+ setShaderMapUrl("");
560
+ // Cleanup function with error handling
561
+ return () => {
562
+ shaderDebounceTimeoutRef.current && (clearTimeout(shaderDebounceTimeoutRef.current),
563
+ shaderDebounceTimeoutRef.current = null);
564
+ try {
565
+ shaderGeneratorRef.current?.destroy();
566
+ } catch (error) {
567
+ console.warn("AtomixGlassContainer: Error during shader cleanup", error);
568
+ } finally {
569
+ shaderGeneratorRef.current = null;
570
+ }
571
+ };
572
+ }), [ mode, glassSize, shaderVariant ]);
573
+ // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
574
+ const [rectCache, setRectCache] = useState(null);
575
+ useEffect((() => {
576
+ if (!ref || "function" == typeof ref) return;
577
+ const element = ref.current;
578
+ if (element) try {
579
+ setRectCache(element.getBoundingClientRect());
580
+ } catch (error) {
581
+ console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
582
+ }
583
+ }), [ ref, glassSize ]);
584
+ // Pre-calculate static multipliers outside useMemo
585
+ const liquidBlur = useMemo((() => {
586
+ const defaultBlur = {
587
+ baseBlur: blurAmount,
588
+ edgeBlur: 1.25 * blurAmount,
589
+ centerBlur: 1.1 * blurAmount,
590
+ flowBlur: 1.2 * blurAmount
591
+ };
592
+ // Enhanced validation for liquid blur
593
+ if (!enableLiquidBlur || !rectCache || !globalMousePosition || "number" != typeof globalMousePosition.x || "number" != typeof globalMousePosition.y || isNaN(globalMousePosition.x) || isNaN(globalMousePosition.y)) return defaultBlur;
594
+ try {
595
+ // Cache center and distance calculations
596
+ const center = calculateElementCenter(rectCache), distance = calculateDistance(globalMousePosition, center), maxDistance = Math.sqrt(rectCache.width * rectCache.width + rectCache.height * rectCache.height) / 2, normalizedDistance = Math.min(distance / maxDistance, 1), mouseInfluence = calculateMouseInfluence(mouseOffset), baseBlur = blurAmount + mouseInfluence * blurAmount * .4, edgeBlur = baseBlur * (.8 + .6 * (1.5 * normalizedDistance + .3 * mouseInfluence)), centerBlur = baseBlur * (.3 + .4 * (.3 * (1 - normalizedDistance) + .2 * mouseInfluence)), deltaX = globalMousePosition.x - center.x, deltaY = globalMousePosition.y - center.y, flowDirection = Math.atan2(deltaY, deltaX), flowBlur = baseBlur * (.4 + .6 * (.5 * Math.sin(flowDirection + mouseInfluence * Math.PI) + .5)), stateMultiplier = (isHovered ? 1.2 : 1) * (isActive ? 1.4 : 1);
597
+ return {
598
+ baseBlur: clampBlur(baseBlur * stateMultiplier),
599
+ edgeBlur: clampBlur(edgeBlur * stateMultiplier),
600
+ centerBlur: clampBlur(centerBlur * stateMultiplier),
601
+ flowBlur: clampBlur(flowBlur * stateMultiplier)
602
+ };
603
+ } catch (error) {
604
+ return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
605
+ defaultBlur;
606
+ }
607
+ }), [ enableLiquidBlur, blurAmount, globalMousePosition, mouseOffset, isHovered, isActive, rectCache, style, glassSize ]), backdropStyle = useMemo((() => {
608
+ try {
609
+ const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), validatedBaseBlur = "number" != typeof liquidBlur.baseBlur || isNaN(liquidBlur.baseBlur) ? 0 : liquidBlur.baseBlur, validatedEdgeBlur = "number" != typeof liquidBlur.edgeBlur || isNaN(liquidBlur.edgeBlur) ? 0 : liquidBlur.edgeBlur, validatedCenterBlur = "number" != typeof liquidBlur.centerBlur || isNaN(liquidBlur.centerBlur) ? 0 : liquidBlur.centerBlur, validatedFlowBlur = "number" != typeof liquidBlur.flowBlur || isNaN(liquidBlur.flowBlur) ? 0 : liquidBlur.flowBlur, area = rectCache ? rectCache.width * rectCache.height : 0;
610
+ // Validate blur values before using them
611
+ return !enableLiquidBlur || effectiveReducedMotion || effectiveDisableEffects || area > 18e4 ? {
612
+ backdropFilter: `blur(${clampBlur(Math.max(validatedBaseBlur, .8 * validatedEdgeBlur, 1.1 * validatedCenterBlur, .9 * validatedFlowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(1.05) brightness(1.05)`
613
+ } : {
614
+ backdropFilter: `${[ `blur(${validatedBaseBlur}px)`, `blur(${validatedEdgeBlur}px)`, `blur(${validatedCenterBlur}px)`, `blur(${validatedFlowBlur}px)` ].join(" ")} saturate(${Math.min(dynamicSaturation, 200)}%) contrast(1.05) brightness(1.05)`
615
+ };
616
+ // Single-pass fallback: stronger radius to match perceived blur of multi-pass
617
+ } catch (error) {
618
+ return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
619
+ {
620
+ backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
621
+ };
622
+ }
623
+ }), [ filterId, liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveDisableEffects, enableLiquidBlur ]), containerVars = useMemo((() => {
624
+ try {
625
+ // Safe extraction of mouse offset values
626
+ const mx = mouseOffset && "number" == typeof mouseOffset.x && !isNaN(mouseOffset.x) ? mouseOffset.x : 0, my = mouseOffset && "number" == typeof mouseOffset.y && !isNaN(mouseOffset.y) ? mouseOffset.y : 0;
627
+ return {
628
+ "--atomix-glass-container-width": `${glassSize?.width}`,
629
+ "--atomix-glass-container-height": `${glassSize?.height}`,
630
+ "--atomix-glass-container-padding": padding || "0 0",
631
+ "--atomix-glass-container-radius": `${"number" != typeof cornerRadius || isNaN(cornerRadius) ? 0 : cornerRadius}px`,
632
+ "--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
633
+ "--atomix-glass-container-shadow": overLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${.4 + .002 * mx})`, `inset 0 -1px 0 rgba(0, 0, 0, ${.2 + .001 * Math.abs(my)})`, `inset 0 0 20px rgba(0, 0, 0, ${.08 + .001 * Math.abs(mx + my)})`, `0 2px 12px rgba(0, 0, 0, ${.12 + .002 * Math.abs(my)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset",
634
+ "--atomix-glass-container-shadow-opacity": effectiveDisableEffects ? 0 : 1,
635
+ // Background and shadow values use design token-aligned RGB values
636
+ "--atomix-glass-container-bg": overLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none",
637
+ "--atomix-glass-container-text-shadow": overLight ? "0px 2px 12px rgba(0, 0, 0, 0)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
638
+ "--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
639
+ };
640
+ } catch (error) {
641
+ return console.warn("AtomixGlassContainer: Error generating container variables", error),
642
+ {
643
+ "--atomix-glass-container-padding": "0 0",
644
+ "--atomix-glass-container-radius": "0px",
645
+ "--atomix-glass-container-backdrop": "none",
646
+ "--atomix-glass-container-shadow": "none",
647
+ "--atomix-glass-container-shadow-opacity": 1,
648
+ "--atomix-glass-container-bg": "none",
649
+ "--atomix-glass-container-text-shadow": "none"
650
+ };
651
+ }
652
+ }), [ glassSize, padding, cornerRadius, backdropStyle, mouseOffset, overLight, effectiveDisableEffects ]);
653
+ return jsx("div", {
654
+ ref: ref,
655
+ className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${active ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
656
+ style: {
657
+ ...style,
658
+ ...containerVars
659
+ },
660
+ onClick: onClick,
661
+ children: jsxs("div", {
662
+ className: ATOMIX_GLASS.INNER_CLASS,
663
+ style: {
664
+ padding: "var(--atomix-glass-container-padding)",
665
+ boxShadow: "var(--atomix-glass-container-box-shadow)"
666
+ },
667
+ onMouseEnter: onMouseEnter,
668
+ onMouseLeave: onMouseLeave,
669
+ onMouseDown: onMouseDown,
670
+ onMouseUp: onMouseUp,
671
+ children: [ jsxs("div", {
672
+ className: ATOMIX_GLASS.FILTER_CLASS,
673
+ children: [ jsx(GlassFilter, {
674
+ blurAmount: blurAmount,
675
+ mode: mode,
676
+ id: filterId,
677
+ displacementScale: "number" != typeof displacementScale || isNaN(displacementScale) ? 0 : displacementScale,
678
+ aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
679
+ shaderMapUrl: shaderMapUrl
680
+ }), jsx("div", {
681
+ className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
682
+ suppressHydrationWarning: !0,
683
+ style: {
684
+ filter: `url(#${filterId})`,
685
+ backdropFilter: "var(--atomix-glass-container-backdrop)",
686
+ borderRadius: "var(--atomix-glass-container-radius)"
687
+ }
688
+ }), jsx("div", {
689
+ className: ATOMIX_GLASS.FILTER_SHADOW_CLASS,
690
+ style: {
691
+ boxShadow: "var(--atomix-glass-container-shadow)",
692
+ opacity: "var(--atomix-glass-container-shadow-opacity)",
693
+ background: "var(--atomix-glass-container-bg)",
694
+ borderRadius: "var(--atomix-glass-container-radius)"
695
+ }
696
+ }) ]
697
+ }), jsx("div", {
698
+ ref: contentRef,
699
+ className: ATOMIX_GLASS.CONTENT_CLASS,
700
+ style: {
701
+ position: "relative",
702
+ textShadow: "var(--atomix-glass-container-text-shadow)",
703
+ ...elasticity > 0 ? {
704
+ zIndex: 100
705
+ } : {}
706
+ },
707
+ children: children
708
+ }) ]
709
+ })
710
+ });
711
+ }));
712
+
713
+ // Module-level shared shader cache with LRU eviction
714
+ AtomixGlassContainer.displayName = "AtomixGlassContainer";
715
+
716
+ // Singleton instance
717
+ const globalMouseTracker = new
718
+ /**
719
+ * Global mouse tracker singleton
720
+ * Tracks mouse position at document level and distributes to subscribers
721
+ * Reduces event processing overhead when multiple AtomixGlass instances are present
722
+ */
723
+ class {
724
+ constructor() {
725
+ this.listeners = new Set, this.position = {
726
+ x: 0,
727
+ y: 0
728
+ }, this.rafId = null, this.lastEvent = null, this.isTracking = !1,
729
+ /**
730
+ * Handle mouse move event
731
+ */
732
+ this.handleMouseMove = e => {
733
+ this.lastEvent = e,
734
+ // Use requestAnimationFrame to throttle updates
735
+ null === this.rafId && (this.rafId = requestAnimationFrame((() => {
736
+ this.lastEvent && (this.position = {
737
+ x: this.lastEvent.clientX,
738
+ y: this.lastEvent.clientY
739
+ },
740
+ // Notify all subscribers
741
+ this.listeners.forEach((callback => {
742
+ try {
743
+ callback(this.position);
744
+ } catch (error) {
745
+ console.error("GlobalMouseTracker: Error in subscriber callback", error);
746
+ }
747
+ }))), this.rafId = null;
748
+ })));
749
+ };
750
+ }
751
+ /**
752
+ * Subscribe to mouse position updates
753
+ * @param callback Function to call when mouse position changes
754
+ * @returns Unsubscribe function
755
+ */ subscribe(callback) {
756
+ // Return unsubscribe function
757
+ return this.listeners.add(callback),
758
+ // Start tracking if this is the first subscriber
759
+ 1 === this.listeners.size && this.startTracking(),
760
+ // Immediately notify with current position
761
+ callback(this.position), () => {
762
+ this.unsubscribe(callback);
763
+ };
764
+ }
765
+ /**
766
+ * Unsubscribe from mouse position updates
767
+ */ unsubscribe(callback) {
768
+ this.listeners.delete(callback),
769
+ // Stop tracking if no more subscribers
770
+ 0 === this.listeners.size && this.stopTracking();
771
+ }
772
+ /**
773
+ * Start tracking mouse movement
774
+ */ startTracking() {
775
+ this.isTracking || (this.isTracking = !0,
776
+ // Use document-level listener for global tracking
777
+ document.addEventListener("mousemove", this.handleMouseMove, {
778
+ passive: !0
779
+ }));
780
+ }
781
+ /**
782
+ * Stop tracking mouse movement
783
+ */ stopTracking() {
784
+ this.isTracking && (this.isTracking = !1, document.removeEventListener("mousemove", this.handleMouseMove),
785
+ // Cancel any pending RAF
786
+ null !== this.rafId && (cancelAnimationFrame(this.rafId), this.rafId = null), this.lastEvent = null);
787
+ }
788
+ /**
789
+ * Get current mouse position (synchronous)
790
+ */ getPosition() {
791
+ return {
792
+ ...this.position
793
+ };
794
+ }
795
+ /**
796
+ * Get number of active subscribers (for debugging)
797
+ */ getSubscriberCount() {
798
+ return this.listeners.size;
799
+ }
800
+ }, {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
801
+ parentElement && backgroundDetectionCache.set(parentElement, {
802
+ result: result,
803
+ timestamp: Date.now(),
804
+ config: overLightConfig,
805
+ threshold: threshold
806
+ });
807
+ };
808
+
809
+ /**
810
+ * Composable hook for AtomixGlass component logic
811
+ * Manages all state, calculations, and event handlers
812
+ */
813
+ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadius: cornerRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, disableEffects: disableEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugCornerRadius: debugCornerRadius = !1, debugOverLight: debugOverLight = !1, enablePerformanceMonitoring: enablePerformanceMonitoring = !1, children: children}) {
814
+ // State
815
+ const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), [glassSize, setGlassSize] = useState({
816
+ width: 270,
817
+ height: 69
818
+ }), [internalGlobalMousePosition, setInternalGlobalMousePosition] = useState({
819
+ x: 0,
820
+ y: 0
821
+ }), [internalMouseOffset, setInternalMouseOffset] = useState({
822
+ x: 0,
823
+ y: 0
824
+ }), [dynamicCornerRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveCornerRadius = useMemo((() => void 0 !== cornerRadius ? Math.max(0, cornerRadius) : Math.max(0, dynamicCornerRadius)), [ cornerRadius, dynamicCornerRadius, debugCornerRadius ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveDisableEffects = useMemo((() => disableEffects || effectiveReducedMotion), [ disableEffects, effectiveReducedMotion ]), globalMousePosition = useMemo((() => externalGlobalMousePosition || internalGlobalMousePosition), [ externalGlobalMousePosition, internalGlobalMousePosition ]), mouseOffset = useMemo((() => externalMouseOffset || internalMouseOffset), [ externalMouseOffset, internalMouseOffset ]);
825
+ // Extract border-radius from children
826
+ useEffect((() => {
827
+ const extractRadius = () => {
828
+ try {
829
+ let extractedRadius = null, extractionSource = "default";
830
+ if (contentRef.current) {
831
+ const firstChild = contentRef.current.firstElementChild;
832
+ if (firstChild) {
833
+ const domRadius = (element => {
834
+ if (!element || "undefined" == typeof window) return null;
835
+ try {
836
+ const computedStyles = window.getComputedStyle(element), borderRadius = computedStyles.borderRadius || computedStyles.borderTopLeftRadius || computedStyles.borderTopRightRadius || computedStyles.borderBottomLeftRadius || computedStyles.borderBottomRightRadius;
837
+ if (borderRadius && "0px" !== borderRadius && "auto" !== borderRadius) {
838
+ const parsed = parseBorderRadiusValue(borderRadius);
839
+ return parsed > 0 ? parsed : null;
840
+ }
841
+ return null;
842
+ } catch (error) {
843
+ return null;
844
+ }
845
+ })(firstChild);
846
+ null !== domRadius && domRadius > 0 && (extractedRadius = domRadius, extractionSource = "DOM element");
847
+ }
848
+ }
849
+ if (null === extractedRadius) {
850
+ const childRadius = extractBorderRadiusFromChildren(children);
851
+ childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS && (extractedRadius = childRadius,
852
+ extractionSource = "React children");
853
+ }
854
+ null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : process.env.NODE_ENV;
855
+ } catch (error) {
856
+ "production" !== process.env.NODE_ENV && debugCornerRadius && console.error("[AtomixGlass] Error extracting corner radius:", error);
857
+ }
858
+ };
859
+ extractRadius();
860
+ const timeoutId = setTimeout(extractRadius, 100);
861
+ return () => clearTimeout(timeoutId);
862
+ }), [ children, debugCornerRadius, contentRef ]),
863
+ // Media query handlers and background detection
864
+ useEffect((() => {
865
+ if (("auto" === overLight || "object" == typeof overLight && null !== overLight) && glassRef.current) {
866
+ const element = glassRef.current, cachedResult = ((parentElement, overLightConfig) => {
867
+ if (!parentElement) return null;
868
+ const cached = backgroundDetectionCache.get(parentElement);
869
+ return cached && ((config1, config2) => {
870
+ // Primitive comparison for boolean and 'auto'
871
+ if ("object" != typeof config1 || null === config1) return config1 === config2;
872
+ // Both must be objects at this point
873
+ if ("object" != typeof config2 || null === config2) return !1;
874
+ const obj1 = config1, obj2 = config2, props = [ "threshold", "opacity", "contrast", "brightness", "saturationBoost" ];
875
+ for (const prop of props) {
876
+ const val1 = obj1[prop], val2 = obj2[prop];
877
+ // If both are undefined, they're equal for this property
878
+ if (void 0 !== val1 || void 0 !== val2) {
879
+ // If one is undefined and the other isn't, they're different
880
+ if (void 0 === val1 || void 0 === val2) return !1;
881
+ // Compare numeric values (handle NaN and floating point precision)
882
+ if ("number" == typeof val1 && "number" == typeof val2) {
883
+ // Use Number.isNaN for proper NaN comparison
884
+ if (Number.isNaN(val1) && Number.isNaN(val2)) continue;
885
+ if (Number.isNaN(val1) || Number.isNaN(val2)) return !1;
886
+ // Compare with small epsilon for floating point numbers
887
+ if (Math.abs(val1 - val2) > Number.EPSILON) return !1;
888
+ } else if (val1 !== val2) return !1;
889
+ }
890
+ }
891
+ return !0;
892
+ })(cached.config, overLightConfig) ? (
893
+ // Update timestamp for LRU-like behavior (though WeakMap doesn't support LRU)
894
+ cached.timestamp = Date.now(), cached.result) : null;
895
+ })(element.parentElement, overLight);
896
+ if (null !== cachedResult) return void setDetectedOverLight(cachedResult);
897
+ const timeoutId = setTimeout((() => {
898
+ try {
899
+ if (!element) return void setDetectedOverLight(!1);
900
+ // Validate window context
901
+ if ("undefined" == typeof window || "function" != typeof window.getComputedStyle) return void setDetectedOverLight(!1);
902
+ let totalLuminance = 0, validSamples = 0, hasValidBackground = !1, currentElement = element.parentElement, depth = 0;
903
+ const maxDepth = 20, maxSamples = 10;
904
+ // Limit traversal depth to prevent infinite loops and performance issues
905
+ for (;currentElement && validSamples < maxSamples && depth < maxDepth; ) {
906
+ try {
907
+ const computedStyle = window.getComputedStyle(currentElement);
908
+ if (!computedStyle) {
909
+ currentElement = currentElement.parentElement, depth++;
910
+ continue;
911
+ }
912
+ const bgColor = computedStyle.backgroundColor, bgImage = computedStyle.backgroundImage;
913
+ // Check for solid color backgrounds
914
+ if (bgColor && "rgba(0, 0, 0, 0)" !== bgColor && "transparent" !== bgColor && "initial" !== bgColor && "none" !== bgColor) {
915
+ const rgb = bgColor.match(/\d+/g);
916
+ if (rgb && rgb.length >= 3) {
917
+ const r = Number(rgb[0]), g = Number(rgb[1]), b = Number(rgb[2]);
918
+ // Validate RGB values are valid numbers
919
+ if (!isNaN(r) && !isNaN(g) && !isNaN(b) && isFinite(r) && isFinite(g) && isFinite(b) && r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 && (r > 10 || g > 10 || b > 10)) {
920
+ const luminance = (.299 * r + .587 * g + .114 * b) / 255;
921
+ !isNaN(luminance) && isFinite(luminance) && (totalLuminance += luminance, validSamples++,
922
+ hasValidBackground = !0);
923
+ }
924
+ }
925
+ }
926
+ // Check for image backgrounds
927
+ bgImage && "none" !== bgImage && "initial" !== bgImage && (
928
+ // For image backgrounds, assume medium luminance
929
+ totalLuminance += .5, validSamples++, hasValidBackground = !0);
930
+ } catch (styleError) {
931
+ process.env.NODE_ENV;
932
+ }
933
+ // Move to parent element for next iteration
934
+ if (!currentElement) break;
935
+ // Exit loop if currentElement becomes null
936
+ currentElement = currentElement.parentElement, depth++;
937
+ }
938
+ // More conservative detection with better error handling
939
+ if (hasValidBackground && validSamples > 0) {
940
+ const avgLuminance = totalLuminance / validSamples;
941
+ if (!isNaN(avgLuminance) && isFinite(avgLuminance)) {
942
+ let threshold = .7;
943
+ // Conservative threshold for overlight
944
+ // If overLight is an object, use its threshold property with validation
945
+ if ("object" == typeof overLight && null !== overLight) {
946
+ const objConfig = overLight;
947
+ if (void 0 !== objConfig.threshold) {
948
+ const configThreshold = "number" == typeof objConfig.threshold && !isNaN(objConfig.threshold) && isFinite(objConfig.threshold) ? objConfig.threshold : .7;
949
+ threshold = Math.min(.9, Math.max(.1, configThreshold));
950
+ }
951
+ }
952
+ const isOverLightDetected = avgLuminance > threshold;
953
+ // Cache the result in shared cache
954
+ setCachedBackgroundDetection(element.parentElement, overLight, isOverLightDetected, threshold),
955
+ setDetectedOverLight(isOverLightDetected);
956
+ } else {
957
+ // Invalid luminance calculation, default to false
958
+ const result = !1, threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
959
+ setCachedBackgroundDetection(element.parentElement, overLight, result, threshold),
960
+ setDetectedOverLight(result);
961
+ }
962
+ } else {
963
+ // Default to false if no valid background found
964
+ const result = !1, threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
965
+ setCachedBackgroundDetection(element.parentElement, overLight, result, threshold),
966
+ setDetectedOverLight(result);
967
+ }
968
+ } catch (error) {
969
+ // Enhanced error logging with context
970
+ "development" === process.env.NODE_ENV && console.warn("AtomixGlass: Error detecting background brightness:", error);
971
+ const result = !1;
972
+ if (element && element.parentElement) {
973
+ const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
974
+ setCachedBackgroundDetection(element.parentElement, overLight, result, threshold);
975
+ }
976
+ setDetectedOverLight(result);
977
+ }
978
+ }), 150);
979
+ return () => clearTimeout(timeoutId);
980
+ }
981
+ if ("boolean" == typeof overLight &&
982
+ // For boolean values, disable auto-detection
983
+ // Cache is automatically managed by WeakMap (no manual clearing needed)
984
+ setDetectedOverLight(!1), "function" == typeof window.matchMedia) try {
985
+ const mediaQueryReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"), mediaQueryHighContrast = window.matchMedia("(prefers-contrast: high)");
986
+ setUserPrefersReducedMotion(mediaQueryReducedMotion.matches), setUserPrefersHighContrast(mediaQueryHighContrast.matches);
987
+ const handleReducedMotionChange = e => {
988
+ setUserPrefersReducedMotion(e.matches);
989
+ }, handleHighContrastChange = e => {
990
+ setUserPrefersHighContrast(e.matches);
991
+ };
992
+ return mediaQueryReducedMotion.addEventListener ? (mediaQueryReducedMotion.addEventListener("change", handleReducedMotionChange),
993
+ mediaQueryHighContrast.addEventListener("change", handleHighContrastChange)) : mediaQueryReducedMotion.addListener && (mediaQueryReducedMotion.addListener(handleReducedMotionChange),
994
+ mediaQueryHighContrast.addListener(handleHighContrastChange)), () => {
995
+ try {
996
+ mediaQueryReducedMotion.removeEventListener ? (mediaQueryReducedMotion.removeEventListener("change", handleReducedMotionChange),
997
+ mediaQueryHighContrast.removeEventListener("change", handleHighContrastChange)) : mediaQueryReducedMotion.removeListener && (mediaQueryReducedMotion.removeListener(handleReducedMotionChange),
998
+ mediaQueryHighContrast.removeListener(handleHighContrastChange));
999
+ } catch (cleanupError) {
1000
+ console.error("AtomixGlass: Error cleaning up media query listeners:", cleanupError);
1001
+ }
1002
+ };
1003
+ } catch (error) {
1004
+ return void console.error("AtomixGlass: Error setting up media queries:", error);
1005
+ }
1006
+ }), [ overLight, glassRef, debugOverLight ]);
1007
+ // Mouse tracking using shared global tracker
1008
+ // Cache bounding rect to avoid repeated getBoundingClientRect calls
1009
+ const cachedRectRef = useRef(null), updateRectRef = useRef(null), handleGlobalMousePosition = useCallback((globalPos => {
1010
+ if (externalGlobalMousePosition && externalMouseOffset)
1011
+ // External mouse position provided, skip internal tracking
1012
+ return;
1013
+ if (effectiveDisableEffects) return;
1014
+ const container = mouseContainer?.current || glassRef.current;
1015
+ if (!container) return;
1016
+ enablePerformanceMonitoring && performance.now();
1017
+ // Use cached rect if available, otherwise get new one
1018
+ let rect = cachedRectRef.current;
1019
+ if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
1020
+ cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
1021
+ const center = calculateElementCenter(rect), newOffset = {
1022
+ x: (globalPos.x - center.x) / rect.width * 100,
1023
+ y: (globalPos.y - center.y) / rect.height * 100
1024
+ };
1025
+ // Calculate offset relative to this container
1026
+ // React 18 automatically batches these updates
1027
+ setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "production" !== process.env.NODE_ENV && enablePerformanceMonitoring && performance.now();
1028
+ }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects, enablePerformanceMonitoring ]);
1029
+ // Subscribe to shared mouse tracker
1030
+ useEffect((() => {
1031
+ if (externalGlobalMousePosition && externalMouseOffset)
1032
+ // External mouse position provided, don't subscribe
1033
+ return;
1034
+ if (effectiveDisableEffects)
1035
+ // Effects disabled, don't subscribe
1036
+ return;
1037
+ // Subscribe to shared tracker
1038
+ const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition), container = mouseContainer?.current || glassRef.current;
1039
+ // Update cached rect when container size changes
1040
+ let resizeObserver = null;
1041
+ return container && "undefined" != typeof ResizeObserver && (resizeObserver = new ResizeObserver((() => {
1042
+ null !== updateRectRef.current && cancelAnimationFrame(updateRectRef.current), updateRectRef.current = requestAnimationFrame((() => {
1043
+ const container = mouseContainer?.current || glassRef.current;
1044
+ container && (cachedRectRef.current = container.getBoundingClientRect()), updateRectRef.current = null;
1045
+ }));
1046
+ })), resizeObserver.observe(container)), () => {
1047
+ unsubscribe(), null !== updateRectRef.current && (cancelAnimationFrame(updateRectRef.current),
1048
+ updateRectRef.current = null), resizeObserver && resizeObserver.disconnect();
1049
+ };
1050
+ }), [ handleGlobalMousePosition, mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects ]);
1051
+ // Transform calculations
1052
+ const calculateDirectionalScale = useCallback((() => {
1053
+ if (!(globalMousePosition.x && globalMousePosition.y && glassRef.current && validateGlassSize(glassSize))) return "scale(1)";
1054
+ const rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), deltaX = globalMousePosition.x - center.x, deltaY = globalMousePosition.y - center.y, edgeDistanceX = Math.max(0, Math.abs(deltaX) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(deltaY) - glassSize.height / 2), edgeDistance = calculateDistance({
1055
+ x: edgeDistanceX,
1056
+ y: edgeDistanceY
1057
+ }, {
1058
+ x: 0,
1059
+ y: 0
1060
+ });
1061
+ if (edgeDistance > CONSTANTS.ACTIVATION_ZONE) return "scale(1)";
1062
+ const fadeInFactor = 1 - edgeDistance / CONSTANTS.ACTIVATION_ZONE, centerDistance = calculateDistance(globalMousePosition, center);
1063
+ if (0 === centerDistance) return "scale(1)";
1064
+ const normalizedX = deltaX / centerDistance, normalizedY = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * fadeInFactor, scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * .3 - Math.abs(normalizedY) * stretchIntensity * .15, scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * .3 - Math.abs(normalizedX) * stretchIntensity * .15;
1065
+ return `scaleX(${Math.max(.8, scaleX)}) scaleY(${Math.max(.8, scaleY)})`;
1066
+ }), [ globalMousePosition, elasticity, glassSize, glassRef ]), calculateFadeInFactor = useCallback((() => {
1067
+ if (!(globalMousePosition.x && globalMousePosition.y && glassRef.current && validateGlassSize(glassSize))) return 0;
1068
+ const rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), edgeDistanceX = Math.max(0, Math.abs(globalMousePosition.x - center.x) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(globalMousePosition.y - center.y) - glassSize.height / 2), edgeDistance = calculateDistance({
1069
+ x: edgeDistanceX,
1070
+ y: edgeDistanceY
1071
+ }, {
1072
+ x: 0,
1073
+ y: 0
1074
+ });
1075
+ return edgeDistance > CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / CONSTANTS.ACTIVATION_ZONE;
1076
+ }), [ globalMousePosition, glassSize, glassRef ]), calculateElasticTranslation = useCallback((() => {
1077
+ if (!glassRef.current) return {
1078
+ x: 0,
1079
+ y: 0
1080
+ };
1081
+ const fadeInFactor = calculateFadeInFactor(), rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect);
1082
+ return {
1083
+ x: (globalMousePosition.x - center.x) * elasticity * .1 * fadeInFactor,
1084
+ y: (globalMousePosition.y - center.y) * elasticity * .1 * fadeInFactor
1085
+ };
1086
+ }), [ globalMousePosition, elasticity, calculateFadeInFactor, glassRef ]), elasticTranslation = useMemo((() => effectiveDisableEffects ? {
1087
+ x: 0,
1088
+ y: 0
1089
+ } : calculateElasticTranslation()), [ calculateElasticTranslation, effectiveDisableEffects ]), directionalScale = useMemo((() => effectiveDisableEffects ? "scale(1)" : calculateDirectionalScale()), [ calculateDirectionalScale, effectiveDisableEffects ]), transformStyle = useMemo((() => effectiveDisableEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : directionalScale}`), [ elasticTranslation, isActive, onClick, directionalScale, effectiveDisableEffects ]);
1090
+ // Size management
1091
+ useEffect((() => {
1092
+ const isValidElement = element => null !== element && element instanceof HTMLElement && element.isConnected;
1093
+ let rafId = null, lastSize = {
1094
+ width: 0,
1095
+ height: 0
1096
+ }, lastCornerRadius = effectiveCornerRadius;
1097
+ const updateGlassSize = (forceUpdate = !1) => {
1098
+ null !== rafId && cancelAnimationFrame(rafId), rafId = requestAnimationFrame((() => {
1099
+ if (!isValidElement(glassRef.current)) return void (rafId = null);
1100
+ const rect = glassRef.current.getBoundingClientRect();
1101
+ if (rect.width <= 0 || rect.height <= 0) return void (rafId = null);
1102
+ // Measure actual rendered size without artificial offsets to avoid feedback loops
1103
+ const newSize = {
1104
+ width: Math.round(rect.width),
1105
+ height: Math.round(rect.height)
1106
+ }, cornerRadiusChanged = lastCornerRadius !== effectiveCornerRadius, dimensionsChanged = Math.abs(newSize.width - lastSize.width) > 1 || Math.abs(newSize.height - lastSize.height) > 1;
1107
+ var size;
1108
+ (forceUpdate || cornerRadiusChanged || dimensionsChanged) && validateGlassSize(size = newSize) && size.width <= CONSTANTS.MAX_SIZE && size.height <= CONSTANTS.MAX_SIZE && (lastSize = newSize,
1109
+ lastCornerRadius = effectiveCornerRadius, setGlassSize(newSize)), rafId = null;
1110
+ }));
1111
+ };
1112
+ let resizeTimeoutId = null;
1113
+ const debouncedResizeHandler = () => {
1114
+ resizeTimeoutId && clearTimeout(resizeTimeoutId), resizeTimeoutId = setTimeout((() => updateGlassSize(!1)), 16);
1115
+ }, initialTimeoutId = setTimeout((() => updateGlassSize(!0)), 0);
1116
+ let resizeObserver = null, resizeDebounceTimeout = null;
1117
+ // ResizeObserver has 98%+ browser support, no need for fallback
1118
+ if ("undefined" != typeof ResizeObserver && isValidElement(glassRef.current)) try {
1119
+ resizeObserver = new ResizeObserver((entries => {
1120
+ for (const entry of entries) if (entry.target === glassRef.current) {
1121
+ // Update cached rect when size changes
1122
+ glassRef.current && (cachedRectRef.current = glassRef.current.getBoundingClientRect()),
1123
+ // Debounce resize updates to match RAF timing (16ms)
1124
+ resizeDebounceTimeout && clearTimeout(resizeDebounceTimeout), resizeDebounceTimeout = setTimeout((() => updateGlassSize(!1)), 16);
1125
+ break;
1126
+ }
1127
+ })), resizeObserver.observe(glassRef.current);
1128
+ } catch (error) {
1129
+ console.warn("AtomixGlass: ResizeObserver not available, using window resize only", error);
1130
+ }
1131
+ return window.addEventListener("resize", debouncedResizeHandler, {
1132
+ passive: !0
1133
+ }), () => {
1134
+ clearTimeout(initialTimeoutId), null !== rafId && cancelAnimationFrame(rafId), resizeTimeoutId && clearTimeout(resizeTimeoutId),
1135
+ resizeDebounceTimeout && clearTimeout(resizeDebounceTimeout), window.removeEventListener("resize", debouncedResizeHandler),
1136
+ resizeObserver?.disconnect();
1137
+ };
1138
+ }), [ effectiveCornerRadius, glassRef ]);
1139
+ // OverLight config
1140
+ /**
1141
+ * Get effective overLight value based on configuration
1142
+ * - boolean: returns the boolean value directly
1143
+ * - 'auto': returns detectedOverLight (auto-detected from background)
1144
+ * - object: returns detectedOverLight (auto-detected, but config object provides customization)
1145
+ */
1146
+ const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), overLightConfig = useMemo((() => {
1147
+ const isOverLight = getEffectiveOverLight(), mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, baseConfig = {
1148
+ isOverLight: isOverLight,
1149
+ threshold: .7,
1150
+ opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
1151
+ contrast: Math.min(1.8, Math.max(1, 1.4 + .3 * mouseInfluence)),
1152
+ brightness: Math.min(1.2, Math.max(.7, .85 + .15 * mouseInfluence)),
1153
+ saturationBoost: Math.min(2, Math.max(1, 1.3 + .4 * mouseInfluence)),
1154
+ shadowIntensity: Math.min(1.5, Math.max(.5, .9 + .5 * mouseInfluence)),
1155
+ borderOpacity: Math.min(1, Math.max(.3, .7 + .3 * mouseInfluence))
1156
+ };
1157
+ if ("object" == typeof overLight && null !== overLight) {
1158
+ const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), finalConfig = {
1159
+ ...baseConfig,
1160
+ threshold: validatedThreshold,
1161
+ opacity: validatedOpacity * hoverIntensity * activeIntensity,
1162
+ contrast: validatedContrast + .3 * mouseInfluence,
1163
+ brightness: validatedBrightness + .15 * mouseInfluence,
1164
+ saturationBoost: validatedSaturationBoost + .4 * mouseInfluence
1165
+ };
1166
+ // Validate and apply object config values with proper clamping
1167
+ return process.env.NODE_ENV, finalConfig;
1168
+ }
1169
+ // Debug logging for non-object configs
1170
+ return process.env.NODE_ENV, baseConfig;
1171
+ }), [ overLight, getEffectiveOverLight, mouseOffset, isHovered, isActive, validateConfigValue, debugOverLight ]), handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
1172
+ !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
1173
+ }), [ onClick ]), handleMouseMove = useCallback((_e => {}), []);
1174
+ /**
1175
+ * Validate and clamp a numeric config value
1176
+ * @param value - The value to validate
1177
+ * @param min - Minimum allowed value
1178
+ * @param max - Maximum allowed value
1179
+ * @param defaultValue - Default value if validation fails
1180
+ * @returns Validated and clamped value
1181
+ */ return {
1182
+ // State
1183
+ isHovered: isHovered,
1184
+ isActive: isActive,
1185
+ glassSize: glassSize,
1186
+ dynamicCornerRadius: dynamicCornerRadius,
1187
+ effectiveCornerRadius: effectiveCornerRadius,
1188
+ effectiveReducedMotion: effectiveReducedMotion,
1189
+ effectiveHighContrast: effectiveHighContrast,
1190
+ effectiveDisableEffects: effectiveDisableEffects,
1191
+ detectedOverLight: detectedOverLight,
1192
+ globalMousePosition: globalMousePosition,
1193
+ mouseOffset: mouseOffset,
1194
+ // OverLight config
1195
+ overLightConfig: overLightConfig,
1196
+ // Transform calculations
1197
+ elasticTranslation: elasticTranslation,
1198
+ directionalScale: directionalScale,
1199
+ transformStyle: transformStyle,
1200
+ // Event handlers
1201
+ handleMouseEnter: handleMouseEnter,
1202
+ handleMouseLeave: handleMouseLeave,
1203
+ handleMouseDown: handleMouseDown,
1204
+ handleMouseUp: handleMouseUp,
1205
+ handleMouseMove: handleMouseMove,
1206
+ handleKeyDown: handleKeyDown
1207
+ };
1208
+ }
1209
+
1210
+ /**
1211
+ * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
1212
+ *
1213
+ * Features:
1214
+ * - Hardware-accelerated glass effects with SVG filters
1215
+ * - Mouse-responsive liquid distortion
1216
+ * - Dynamic border-radius extraction from children CSS properties
1217
+ * - Automatic light/dark theme detection via overLight prop
1218
+ * - Accessibility and performance optimizations
1219
+ * - Multiple displacement modes (standard, polar, prominent, shader)
1220
+ * - Design token integration for consistent theming
1221
+ * - Focus ring support for keyboard navigation
1222
+ * - Responsive breakpoints for mobile optimization
1223
+ * - Enhanced ARIA attributes for screen readers
1224
+ *
1225
+ * Design System Compliance:
1226
+ * - Uses design tokens for opacity, spacing, and colors
1227
+ * - Follows BEM methodology for class naming
1228
+ * - Implements focus-ring mixin for accessibility
1229
+ * - Supports reduced motion and high contrast preferences
1230
+ *
1231
+ * @example
1232
+ * // Basic usage with dynamic border-radius extraction
1233
+ * <AtomixGlass>
1234
+ * <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
1235
+ * </AtomixGlass>
1236
+ *
1237
+ * @example
1238
+ * // Manual border-radius override
1239
+ * <AtomixGlass cornerRadius={20}>
1240
+ * <div>Content with 20px glass radius</div>
1241
+ * </AtomixGlass>
1242
+ *
1243
+ * @example
1244
+ * // Interactive glass with click handler
1245
+ * <AtomixGlass onClick={() => console.log('Clicked')} aria-label="Glass card">
1246
+ * <div>Clickable content</div>
1247
+ * </AtomixGlass>
1248
+ *
1249
+ * @example
1250
+ * // OverLight - Boolean mode (explicit control)
1251
+ * <AtomixGlass overLight={true}>
1252
+ * <div>Content on light background</div>
1253
+ * </AtomixGlass>
1254
+ *
1255
+ * @example
1256
+ * // OverLight - Auto-detection mode
1257
+ * <AtomixGlass overLight="auto">
1258
+ * <div>Content with auto-detected background</div>
1259
+ * </AtomixGlass>
1260
+ *
1261
+ * @example
1262
+ * // OverLight - Object config with custom settings
1263
+ * <AtomixGlass
1264
+ * overLight={{
1265
+ * threshold: 0.8,
1266
+ * opacity: 0.6,
1267
+ * contrast: 1.8,
1268
+ * brightness: 1.0,
1269
+ * saturationBoost: 1.5
1270
+ * }}
1271
+ * >
1272
+ * <div>Content with custom overLight config</div>
1273
+ * </AtomixGlass>
1274
+ *
1275
+ * @example
1276
+ * // Debug mode for overLight detection
1277
+ * <AtomixGlass overLight="auto" debugOverLight={true}>
1278
+ * <div>Content with debug logging enabled</div>
1279
+ * </AtomixGlass>
1280
+ */ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, cornerRadius: cornerRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, disableEffects: disableEffects = !1, enableLiquidBlur: enableLiquidBlur = !1, enableBorderEffect: enableBorderEffect = !0, enableOverLightLayers: enableOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, enablePerformanceMonitoring: enablePerformanceMonitoring = !1, debugCornerRadius: debugCornerRadius = !1, debugOverLight: debugOverLight = !1}) {
1281
+ const glassRef = useRef(null), contentRef = useRef(null), opacityCacheRef = useRef(null), {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveCornerRadius: effectiveCornerRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveDisableEffects: effectiveDisableEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
1282
+ glassRef: glassRef,
1283
+ contentRef: contentRef,
1284
+ cornerRadius: cornerRadius,
1285
+ globalMousePosition: externalGlobalMousePosition,
1286
+ mouseOffset: externalMouseOffset,
1287
+ mouseContainer: mouseContainer,
1288
+ overLight: overLight,
1289
+ reducedMotion: reducedMotion,
1290
+ highContrast: highContrast,
1291
+ disableEffects: disableEffects,
1292
+ elasticity: elasticity,
1293
+ onClick: onClick,
1294
+ debugCornerRadius: debugCornerRadius,
1295
+ debugOverLight: debugOverLight,
1296
+ enablePerformanceMonitoring: enablePerformanceMonitoring,
1297
+ children: children
1298
+ }), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight;
1299
+ // Read CSS custom properties once on mount and cache them
1300
+ useEffect((() => {
1301
+ if ("undefined" != typeof window && glassRef.current && !opacityCacheRef.current) try {
1302
+ const computedStyle = window.getComputedStyle(glassRef.current), opacity50Value = computedStyle.getPropertyValue("--atomix-opacity-50").trim(), opacity40Value = computedStyle.getPropertyValue("--atomix-opacity-40").trim(), opacity80Value = computedStyle.getPropertyValue("--atomix-opacity-80").trim(), opacity0Value = computedStyle.getPropertyValue("--atomix-opacity-0").trim(), parseOpacity = (value, defaultValue) => {
1303
+ if (!value) return defaultValue;
1304
+ const parsed = parseFloat(value);
1305
+ return isNaN(parsed) ? defaultValue : parsed;
1306
+ };
1307
+ opacityCacheRef.current = {
1308
+ opacity50: parseOpacity(opacity50Value, .5),
1309
+ opacity40: parseOpacity(opacity40Value, .4),
1310
+ opacity80: parseOpacity(opacity80Value, .8),
1311
+ opacity0: parseOpacity(opacity0Value, 0)
1312
+ };
1313
+ } catch (error) {
1314
+ // Fallback to defaults if reading fails
1315
+ opacityCacheRef.current = {
1316
+ opacity50: .5,
1317
+ opacity40: .4,
1318
+ opacity80: .8,
1319
+ opacity0: 0
1320
+ };
1321
+ }
1322
+ }), []);
1323
+ // Calculate base style with transforms (only dynamic values)
1324
+ const baseStyle = useMemo((() => ({
1325
+ ...style,
1326
+ ...0 !== elasticity && !effectiveDisableEffects && {
1327
+ transform: transformStyle
1328
+ }
1329
+ })), [ style, transformStyle, effectiveDisableEffects, elasticity ]), componentClassName = useMemo((() => [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveDisableEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" ")), [ effectiveReducedMotion, effectiveHighContrast, effectiveDisableEffects, className ]), baseStylePosition = baseStyle.position, baseStyleTop = baseStyle.top, baseStyleLeft = baseStyle.left, positionStyles = useMemo((() => ({
1330
+ position: baseStylePosition || "absolute",
1331
+ top: baseStyleTop || 0,
1332
+ left: baseStyleLeft || 0
1333
+ })), [ baseStylePosition, baseStyleTop, baseStyleLeft ]), baseStyleWidth = baseStyle.width, baseStyleHeight = baseStyle.height, glassSizeWidth = glassSize.width, glassSizeHeight = glassSize.height, adjustedSize = useMemo((() => ({
1334
+ width: "fixed" !== baseStylePosition ? "100%" : baseStyleWidth || Math.max(glassSizeWidth, 0),
1335
+ height: "fixed" !== baseStylePosition ? "100%" : baseStyleHeight || Math.max(glassSizeHeight, 0)
1336
+ })), [ baseStylePosition, baseStyleWidth, baseStyleHeight, glassSizeWidth, glassSizeHeight ]), mouseOffsetX = mouseOffset.x, mouseOffsetY = mouseOffset.y, GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, gradientCalculations = useMemo((() => {
1337
+ const mx = mouseOffsetX, my = mouseOffsetY, borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), borderOpacity1 = GRADIENT.BORDER_OPACITY.BASE_1 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity2 = GRADIENT.BORDER_OPACITY.BASE_2 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, borderOpacity3 = GRADIENT.BORDER_OPACITY.BASE_3 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity4 = GRADIENT.BORDER_OPACITY.BASE_4 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, hover1X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1, hover1Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1, hover2X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2, hover2Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2, hover3X = GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3, hover3Y = GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3, baseX = GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER, baseY = GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER;
1338
+ return {
1339
+ isOverLight: isOverLight,
1340
+ mx: mx,
1341
+ my: my,
1342
+ borderGradientAngle: borderGradientAngle,
1343
+ borderStop1: borderStop1,
1344
+ borderStop2: borderStop2,
1345
+ borderOpacity1: borderOpacity1,
1346
+ borderOpacity2: borderOpacity2,
1347
+ borderOpacity3: borderOpacity3,
1348
+ borderOpacity4: borderOpacity4,
1349
+ hover1X: hover1X,
1350
+ hover1Y: hover1Y,
1351
+ hover2X: hover2X,
1352
+ hover2Y: hover2Y,
1353
+ hover3X: hover3X,
1354
+ hover3Y: hover3Y,
1355
+ baseX: baseX,
1356
+ baseY: baseY
1357
+ };
1358
+ }), [ mouseOffsetX, mouseOffsetY, isOverLight ]), overLightOpacity = overLightConfig.opacity, opacityValues = useMemo((() => {
1359
+ // Use cached values if available, otherwise fallback to defaults
1360
+ const opacity50 = opacityCacheRef.current?.opacity50 ?? .5, opacity40 = opacityCacheRef.current?.opacity40 ?? .4, opacity80 = opacityCacheRef.current?.opacity80 ?? .8, opacity0 = opacityCacheRef.current?.opacity0 ?? 0;
1361
+ // Dynamic multiplier for overlay
1362
+ return {
1363
+ hover1: isHovered || isActive ? opacity50 : opacity0,
1364
+ hover2: isActive ? opacity50 : opacity0,
1365
+ hover3: isHovered ? opacity40 : isActive ? opacity80 : opacity0,
1366
+ base: isOverLight ? overLightOpacity || opacity40 : opacity0,
1367
+ over: isOverLight ? 1.1 * (overLightOpacity || opacity40) : opacity0
1368
+ };
1369
+ }), [ isHovered, isActive, isOverLight, overLightOpacity ]), gradientIsOverLight = gradientCalculations.isOverLight, gradientMx = gradientCalculations.mx, gradientMy = gradientCalculations.my, gradientBorderGradientAngle = gradientCalculations.borderGradientAngle, gradientBorderStop1 = gradientCalculations.borderStop1, gradientBorderStop2 = gradientCalculations.borderStop2, gradientBorderOpacity1 = gradientCalculations.borderOpacity1, gradientBorderOpacity2 = gradientCalculations.borderOpacity2, gradientBorderOpacity3 = gradientCalculations.borderOpacity3, gradientBorderOpacity4 = gradientCalculations.borderOpacity4, gradientHover1X = gradientCalculations.hover1X, gradientHover1Y = gradientCalculations.hover1Y, gradientHover2X = gradientCalculations.hover2X, gradientHover2Y = gradientCalculations.hover2Y, gradientHover3X = gradientCalculations.hover3X, gradientHover3Y = gradientCalculations.hover3Y, gradientBaseX = gradientCalculations.baseX, gradientBaseY = gradientCalculations.baseY, positionStylesPosition = positionStyles.position, positionStylesTop = positionStyles.top, positionStylesLeft = positionStyles.left, adjustedSizeWidth = adjustedSize.width, adjustedSizeHeight = adjustedSize.height, baseStyleTransform = baseStyle.transform, opacityValuesHover1 = opacityValues.hover1, opacityValuesHover2 = opacityValues.hover2, opacityValuesHover3 = opacityValues.hover3, opacityValuesBase = opacityValues.base, opacityValuesOver = opacityValues.over, glassVars = useMemo((() => {
1370
+ // RGB color values for rgba() functions
1371
+ // Note: CSS doesn't support rgba(var(--rgb), opacity) syntax, so we use direct values
1372
+ // These values align with design tokens: --atomix-white-rgb and --atomix-black-rgb
1373
+ // The actual RGB values are defined in SCSS and should match these fallbacks
1374
+ // TODO: Consider reading from CSS custom properties if browser support improves
1375
+ const whiteColor = "255, 255, 255";
1376
+ // Matches --atomix-white-rgb design token
1377
+ // Matches --atomix-black-rgb design token
1378
+ return {
1379
+ // Standard CSS custom properties for dynamic values
1380
+ "--atomix-glass-radius": `${effectiveCornerRadius}px`,
1381
+ "--atomix-glass-transform": baseStyleTransform || "none",
1382
+ "--atomix-glass-position": positionStylesPosition,
1383
+ "--atomix-glass-top": "fixed" !== positionStylesTop ? `${positionStylesTop}px` : "0",
1384
+ "--atomix-glass-left": "fixed" !== positionStylesLeft ? `${positionStylesLeft}px` : "0",
1385
+ "--atomix-glass-width": "fixed" !== baseStylePosition ? adjustedSizeWidth : `${adjustedSizeWidth}px`,
1386
+ "--atomix-glass-height": "fixed" !== baseStylePosition ? adjustedSizeHeight : `${adjustedSizeHeight}px`,
1387
+ // Border width: Use spacing token for consistency
1388
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
1389
+ "--atomix-glass-blend-mode": gradientIsOverLight ? "multiply" : "overlay",
1390
+ // Dynamic gradients and backgrounds
1391
+ // Note: RGB values use design token-aligned constants (white: 255,255,255; black: 0,0,0)
1392
+ "--atomix-glass-border-gradient-1": `linear-gradient(${gradientBorderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${gradientBorderOpacity1}) ${gradientBorderStop1}%, rgba(${whiteColor}, ${gradientBorderOpacity2}) ${gradientBorderStop2}%, rgba(${whiteColor}, 0) 100%)`,
1393
+ "--atomix-glass-border-gradient-2": `linear-gradient(${gradientBorderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${gradientBorderOpacity3}) ${gradientBorderStop1}%, rgba(${whiteColor}, ${gradientBorderOpacity4}) ${gradientBorderStop2}%, rgba(${whiteColor}, 0) 100%)`,
1394
+ "--atomix-glass-hover-1-opacity": opacityValuesHover1,
1395
+ "--atomix-glass-hover-1-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover1X}% ${gradientHover1Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover1X}% ${gradientHover1Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
1396
+ "--atomix-glass-hover-2-opacity": opacityValuesHover2,
1397
+ "--atomix-glass-hover-2-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover2X}% ${gradientHover2Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover2X}% ${gradientHover2Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
1398
+ "--atomix-glass-hover-3-opacity": opacityValuesHover3,
1399
+ "--atomix-glass-hover-3-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover3X}% ${gradientHover3Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover3X}% ${gradientHover3Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
1400
+ "--atomix-glass-base-opacity": opacityValuesBase,
1401
+ "--atomix-glass-base-gradient": gradientIsOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + gradientMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + gradientMy * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + Math.abs(gradientMx) * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
1402
+ "--atomix-glass-overlay-opacity": opacityValuesOver,
1403
+ "--atomix-glass-overlay-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientBaseX}% ${gradientBaseY}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + Math.abs(gradientMx) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + Math.abs(gradientMy) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
1404
+ };
1405
+ }), [
1406
+ // Position styles - only specific properties
1407
+ positionStylesPosition, positionStylesTop, positionStylesLeft,
1408
+ // Adjusted size - only specific properties
1409
+ adjustedSizeWidth, adjustedSizeHeight,
1410
+ // Base style - only transform property
1411
+ baseStyleTransform, baseStylePosition,
1412
+ // Other values
1413
+ effectiveCornerRadius, effectiveReducedMotion,
1414
+ // Gradient calculations - extracted properties
1415
+ gradientIsOverLight, gradientMx, gradientMy, gradientBorderGradientAngle, gradientBorderStop1, gradientBorderStop2, gradientBorderOpacity1, gradientBorderOpacity2, gradientBorderOpacity3, gradientBorderOpacity4, gradientHover1X, gradientHover1Y, gradientHover2X, gradientHover2Y, gradientHover3X, gradientHover3Y, gradientBaseX, gradientBaseY,
1416
+ // Opacity values - extracted properties
1417
+ opacityValuesHover1, opacityValuesHover2, opacityValuesHover3, opacityValuesBase, opacityValuesOver ]);
1418
+ // Build className with state modifiers
1419
+ return jsxs("div", {
1420
+ className: componentClassName,
1421
+ style: glassVars,
1422
+ role: role || (onClick ? "button" : void 0),
1423
+ tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
1424
+ "aria-label": ariaLabel,
1425
+ "aria-describedby": ariaDescribedBy,
1426
+ "aria-disabled": !(!onClick || !effectiveDisableEffects) || !onClick && void 0,
1427
+ "aria-pressed": !(!onClick || !isActive) || !onClick && void 0,
1428
+ onKeyDown: onClick ? handleKeyDown : void 0,
1429
+ children: [ jsx(AtomixGlassContainer, {
1430
+ ref: glassRef,
1431
+ contentRef: contentRef,
1432
+ className: className,
1433
+ style: baseStyle,
1434
+ cornerRadius: effectiveCornerRadius,
1435
+ displacementScale: effectiveDisableEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : overLightConfig.isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
1436
+ blurAmount: effectiveDisableEffects ? 0 : blurAmount,
1437
+ saturation: effectiveHighContrast ? ATOMIX_GLASS.CONSTANTS.SATURATION.HIGH_CONTRAST : overLightConfig.isOverLight ? saturation * overLightConfig.saturationBoost : saturation,
1438
+ aberrationIntensity: effectiveDisableEffects ? 0 : "shader" === mode ? aberrationIntensity * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_ABERRATION : aberrationIntensity,
1439
+ glassSize: glassSize,
1440
+ padding: padding,
1441
+ mouseOffset: effectiveDisableEffects ? {
1442
+ x: 0,
1443
+ y: 0
1444
+ } : mouseOffset,
1445
+ globalMousePosition: effectiveDisableEffects ? {
1446
+ x: 0,
1447
+ y: 0
1448
+ } : globalMousePosition,
1449
+ onMouseEnter: handleMouseEnter,
1450
+ onMouseLeave: handleMouseLeave,
1451
+ onMouseDown: handleMouseDown,
1452
+ onMouseUp: handleMouseUp,
1453
+ active: isActive,
1454
+ isHovered: isHovered,
1455
+ isActive: isActive,
1456
+ overLight: overLightConfig.isOverLight,
1457
+ onClick: onClick,
1458
+ mode: mode,
1459
+ transform: baseStyle.transform,
1460
+ effectiveDisableEffects: effectiveDisableEffects,
1461
+ effectiveReducedMotion: effectiveReducedMotion,
1462
+ shaderVariant: shaderVariant,
1463
+ elasticity: elasticity,
1464
+ enableLiquidBlur: enableLiquidBlur,
1465
+ children: children
1466
+ }), Boolean(onClick) && jsxs(Fragment, {
1467
+ children: [ jsx("div", {
1468
+ className: ATOMIX_GLASS.HOVER_1_CLASS
1469
+ }), jsx("div", {
1470
+ className: ATOMIX_GLASS.HOVER_2_CLASS
1471
+ }), jsx("div", {
1472
+ className: ATOMIX_GLASS.HOVER_3_CLASS
1473
+ }) ]
1474
+ }), jsx("div", {
1475
+ className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" "),
1476
+ style: {
1477
+ ...positionStyles,
1478
+ height: adjustedSize.height,
1479
+ width: adjustedSize.width,
1480
+ borderRadius: `${effectiveCornerRadius}px`,
1481
+ transform: baseStyle.transform
1482
+ }
1483
+ }), jsx("div", {
1484
+ className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" "),
1485
+ style: {
1486
+ ...positionStyles,
1487
+ height: adjustedSize.height,
1488
+ width: adjustedSize.width,
1489
+ borderRadius: `${effectiveCornerRadius}px`,
1490
+ transform: baseStyle.transform
1491
+ }
1492
+ }), shouldRenderOverLightLayers && jsxs(Fragment, {
1493
+ children: [ jsx("div", {
1494
+ className: ATOMIX_GLASS.BASE_LAYER_CLASS
1495
+ }), jsx("div", {
1496
+ className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
1497
+ }), jsx("div", {
1498
+ className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS,
1499
+ style: {
1500
+ opacity: opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
1501
+ background: `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
1502
+ }
1503
+ }) ]
1504
+ }), enableBorderEffect && jsxs(Fragment, {
1505
+ children: [ jsx("span", {
1506
+ className: ATOMIX_GLASS.BORDER_1_CLASS
1507
+ }), jsx("span", {
1508
+ className: ATOMIX_GLASS.BORDER_2_CLASS
1509
+ }) ]
1510
+ }) ]
1511
+ });
1512
+ }
1513
+
1514
+ // Adapted from https://github.com/shuding/liquid-glass
1515
+ // Constants
1516
+ const smoothStep = (a, b, t) => {
1517
+ // Add input validation
1518
+ if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
1519
+ const clamped = Math.max(0, Math.min(1, (t - a) / (b - a)));
1520
+ return clamped * clamped * (3 - 2 * clamped);
1521
+ }, calculateLength = (x, y) => {
1522
+ // Add input validation and error handling
1523
+ if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
1524
+ // Prevent potential overflow
1525
+ const maxX = Math.max(Math.abs(x), Math.abs(y));
1526
+ if (0 === maxX) return 0;
1527
+ const scaledX = x / maxX, scaledY = y / maxX;
1528
+ return maxX * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
1529
+ }, roundedRectSDF = (x, y, width, height, radius) => {
1530
+ // Add input validation
1531
+ if ("number" != typeof x || "number" != typeof y || "number" != typeof width || "number" != typeof height || "number" != typeof radius) return 0;
1532
+ const qx = Math.abs(x) - width + radius, qy = Math.abs(y) - height + radius;
1533
+ return Math.min(Math.max(qx, qy), 0) + calculateLength(Math.max(qx, 0), Math.max(qy, 0)) - radius;
1534
+ }, createTexture = (x, y) => ({
1535
+ x: "number" != typeof x || isNaN(x) ? .5 : Math.max(0, Math.min(1, x)),
1536
+ y: "number" != typeof y || isNaN(y) ? .5 : Math.max(0, Math.min(1, y))
1537
+ }), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), clampValue = (value, min, max) =>
1538
+ // Add input validation
1539
+ "number" != typeof value || "number" != typeof min || "number" != typeof max || isNaN(value) ? min : isNaN(min) ? 0 : isNaN(max) ? 1 : Math.max(min, Math.min(max, value)), easeInOutCubic = t => {
1540
+ // Add input validation
1541
+ if ("number" != typeof t || isNaN(t)) return 0;
1542
+ const clampedT = Math.max(0, Math.min(1, t));
1543
+ return clampedT < .5 ? 4 * clampedT * clampedT * clampedT : 1 - Math.pow(-2 * clampedT + 2, 3) / 2;
1544
+ }, easeOutQuart = t => {
1545
+ // Add input validation
1546
+ if ("number" != typeof t || isNaN(t)) return 0;
1547
+ const clampedT = Math.max(0, Math.min(1, t));
1548
+ return 1 - Math.pow(1 - clampedT, 4);
1549
+ }, noise2D = (x, y) => {
1550
+ // Add input validation
1551
+ if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
1552
+ const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = easeInOutCubic(xf), v = easeInOutCubic(yf), hash = (i, j) => {
1553
+ // Add input validation
1554
+ if ("number" != typeof i || "number" != typeof j) return 0;
1555
+ const n = i + 57 * j, hashed = 43758.5453 * Math.sin(12.9898 * n + 78.233);
1556
+ // Use a more stable hash function
1557
+ return hashed - Math.floor(hashed);
1558
+ }, a = hash(X, Y), b = hash(X + 1, Y), c = hash(X, Y + 1), x1 = a + u * (b - a);
1559
+ return x1 + v * (c + u * (hash(X + 1, Y + 1) - c) - x1);
1560
+ }, fbm = (x, y, octaves = 4) => {
1561
+ // Add input validation
1562
+ if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
1563
+ // Clamp octaves to prevent performance issues
1564
+ const clampedOctaves = Math.max(1, Math.min(8, Math.floor(octaves)));
1565
+ let value = 0, amplitude = .5, frequency = 1;
1566
+ for (let i = 0; i < clampedOctaves; i++) value += amplitude * noise2D(x * frequency, y * frequency),
1567
+ frequency *= 2, amplitude *= .5;
1568
+ return value;
1569
+ }, calculateParallaxOffset = (x, y, depth, mouseX = 0, mouseY = 0) => {
1570
+ // Add input validation
1571
+ if ("number" != typeof x || "number" != typeof y || "number" != typeof depth || "number" != typeof mouseX || "number" != typeof mouseY || isNaN(x) || isNaN(y) || isNaN(depth) || isNaN(mouseX) || isNaN(mouseY)) return {
1572
+ x: 0,
1573
+ y: 0
1574
+ };
1575
+ const parallaxStrength = Math.min(.02 * depth, .1);
1576
+ // Limit strength to prevent extreme values
1577
+ // Calculate offset based on view angle (simulated by mouse position)
1578
+ return {
1579
+ x: (x - mouseX) * parallaxStrength,
1580
+ y: (y - mouseY) * parallaxStrength
1581
+ };
1582
+ }, fragmentShaders = {
1583
+ liquidGlass: (uv, mousePosition) => {
1584
+ if (!validateVec2(uv)) return {
1585
+ x: .5,
1586
+ y: .5
1587
+ };
1588
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothStep(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
1589
+ // Add input validation
1590
+ if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y) || isNaN(strength)) return {
1591
+ x: 0,
1592
+ y: 0
1593
+ };
1594
+ const distance = calculateLength(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
1595
+ // Limit distance to prevent extreme values
1596
+ return {
1597
+ x: x * (1 + distortion),
1598
+ y: y * (1 + distortion)
1599
+ };
1600
+ })(ix, iy, .4 * .1), refractionX = 1.2 * (radialDist.x - ix) * baseDisplacement, refractionY = 1.2 * (radialDist.y - iy) * baseDisplacement, flowX = .018 * Math.sin(8 * (ix + 2 * mouseX) + 2 * time), flowY = .018 * Math.cos(8 * (iy + 2 * mouseY) + 1.5 * time), rippleEffect = (.015 * Math.sin(12 * (ix - mouseX) + 12 * (iy - mouseY) + 3 * time) + .012 * Math.cos(10 * (ix + mouseX) - 10 * (iy - mouseY) - 2 * time)) * mouseFalloff * mouseDistance, depthEffect = (Math.sin(15 * ix + time) * Math.cos(15 * iy - time) * .008 + Math.sin(20 * ix - .5 * time) * Math.cos(20 * iy + .5 * time) * .006) * baseDisplacement, liquidFlow = .85 * (flowX + flowY + .025 * organicFlow), totalDistortionX = refractionX + liquidFlow + rippleEffect + depthEffect, totalDistortionY = refractionY + .8 * liquidFlow + .9 * rippleEffect + depthEffect, chromaticOffset = ((x, y, intensity) => {
1601
+ // Add input validation
1602
+ if ("number" != typeof x || "number" != typeof y || "number" != typeof intensity || isNaN(x) || isNaN(y) || isNaN(intensity)) return {
1603
+ x: 0,
1604
+ y: 0
1605
+ };
1606
+ const distance = calculateLength(x, y);
1607
+ // Prevent division by zero and extreme values
1608
+ if (0 === distance) return {
1609
+ x: 0,
1610
+ y: 0
1611
+ };
1612
+ const angle = Math.atan2(y, x);
1613
+ return {
1614
+ x: Math.cos(angle) * distance * intensity,
1615
+ y: Math.sin(angle) * distance * intensity
1616
+ };
1617
+ })(ix, iy, .015 * baseDisplacement), scaled = smoothStep(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
1618
+ return createTexture(clampValue(finalX * scaled + .5, 0, 1), clampValue(finalY * scaled + .5, 0, 1));
1619
+ },
1620
+ // Premium Apple-style fluid glass with enhanced organic flow
1621
+ appleFluid: (uv, mousePosition) => {
1622
+ if (!validateVec2(uv)) return {
1623
+ x: .5,
1624
+ y: .5
1625
+ };
1626
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothStep(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
1627
+ return createTexture(clampValue(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clampValue(totalY + .5, 0, 1));
1628
+ },
1629
+ // High-end glass with advanced refraction and depth
1630
+ premiumGlass: (uv, mousePosition) => {
1631
+ if (!validateVec2(uv)) return {
1632
+ x: .5,
1633
+ y: .5
1634
+ };
1635
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), centerDistance = calculateLength(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
1636
+ // Multi-layer depth effect
1637
+ let depthX = 0, depthY = 0;
1638
+ for (let layer = 0; layer < 3; layer++) {
1639
+ const layerScale = 5 * (layer + 1), layerTime = time * (1 + .3 * layer), layerStrength = .01 / (layer + 1);
1640
+ depthX += Math.sin(ix * layerScale + layerTime) * layerStrength, depthY += Math.cos(iy * layerScale - layerTime) * layerStrength;
1641
+ }
1642
+ // Glass refraction with mouse influence
1643
+ const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothStep(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
1644
+ return createTexture(clampValue(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clampValue(finalY + .5, 0, 1));
1645
+ },
1646
+ // Metallic liquid effect with shimmer
1647
+ liquidMetal: (uv, mousePosition) => {
1648
+ if (!validateVec2(uv)) return {
1649
+ x: .5,
1650
+ y: .5
1651
+ };
1652
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = calculateLength(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothStep(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
1653
+ return createTexture(clampValue(totalX + .5, 0, 1), clampValue(totalY + .5, 0, 1));
1654
+ },
1655
+ // basiBasi - Expert Premium Glass Shader
1656
+ // The most advanced shader with caustics, spectral dispersion, parallax depth, and volumetric effects
1657
+ basiBasi: (uv, mousePosition) => {
1658
+ if (!validateVec2(uv)) return {
1659
+ x: .5,
1660
+ y: .5
1661
+ };
1662
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
1663
+ // Add input validation
1664
+ "number" != typeof x || "number" != typeof y || "number" != typeof time || "number" != typeof intensity || isNaN(x) || isNaN(y) || isNaN(time) || isNaN(intensity) ? .5 : .5 * (Math.sin(8 * x + 2 * time) * Math.cos(8 * y - 2 * time) * .5 + Math.sin(8 * (x + .5) * 1.3 - 2 * time * .8) * Math.cos(8 * (y - .3) * 1.3 + 2 * time * .8) * .3 + Math.sin(8 * (x - .3) * .7 + 2 * time * 1.2) * Math.cos(8 * (y + .4) * .7 - 2 * time * 1.2) * .2 + 1) * intensity)(ix, iy, time, .8), causticDistortion = .02 * (causticIntensity - .5), refractionAngle = Math.atan2(iy, ix), spectralDispersion = ((x, y, angle) => {
1665
+ // Add input validation
1666
+ if ("number" != typeof x || "number" != typeof y || "number" != typeof angle || isNaN(x) || isNaN(y) || isNaN(angle) || isNaN(.025)) return {
1667
+ r: {
1668
+ x: 0,
1669
+ y: 0
1670
+ },
1671
+ g: {
1672
+ x: 0,
1673
+ y: 0
1674
+ },
1675
+ b: {
1676
+ x: 0,
1677
+ y: 0
1678
+ }
1679
+ };
1680
+ const distance = calculateLength(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
1681
+ return {
1682
+ r: {
1683
+ x: Math.cos(angle) * redOffset,
1684
+ y: Math.sin(angle) * redOffset
1685
+ },
1686
+ g: {
1687
+ x: Math.cos(angle) * greenOffset,
1688
+ y: Math.sin(angle) * greenOffset
1689
+ },
1690
+ b: {
1691
+ x: Math.cos(angle) * blueOffset,
1692
+ y: Math.sin(angle) * blueOffset
1693
+ }
1694
+ };
1695
+ })(ix, iy, refractionAngle), spectralX = (spectralDispersion.r.x + spectralDispersion.g.x + spectralDispersion.b.x) / 3, spectralY = (spectralDispersion.r.y + spectralDispersion.g.y + spectralDispersion.b.y) / 3;
1696
+ // === MULTI-LAYER PARALLAX DEPTH ===
1697
+ // Create depth perception with 7 layers
1698
+ let parallaxX = 0, parallaxY = 0;
1699
+ for (let layer = 0; layer < 7; layer++) {
1700
+ const parallaxOffset = calculateParallaxOffset(ix, iy, (layer + 1) / 7, mouseX, mouseY), layerNoise = fbm((ix + parallaxOffset.x) * (8 + 2 * layer) + time * (.5 + .1 * layer), (iy + parallaxOffset.y) * (8 + 2 * layer) - time * (.5 + .1 * layer), 3) - .5, layerWeight = 1 / (layer + 1);
1701
+ parallaxX += (parallaxOffset.x + .01 * layerNoise) * layerWeight, parallaxY += (parallaxOffset.y + .01 * layerNoise) * layerWeight;
1702
+ }
1703
+ // Normalize parallax effect
1704
+ parallaxX /= 7, parallaxY /= 7;
1705
+ // === VOLUMETRIC SCATTERING ===
1706
+ // Simulate light scattering through glass volume
1707
+ const volumetricDensity = ((x, y, depth, time) =>
1708
+ // Add input validation
1709
+ "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(.5) || isNaN(time) ? .5 : fbm(5 * x + .5 * time, 5 * y - .5 * time, 3) * Math.exp(2 * -Math.max(0, .5)) * .5 + .5)(ix, iy, 0, time), scatteringX = Math.cos(refractionAngle) * volumetricDensity * .015, scatteringY = Math.sin(refractionAngle) * volumetricDensity * .015, turbulence = ((x, y, time, octaves = 5) => {
1710
+ // Add input validation
1711
+ if ("number" != typeof x || "number" != typeof y || "number" != typeof time || "number" != typeof octaves || isNaN(x) || isNaN(y) || isNaN(time) || isNaN(octaves)) return 0;
1712
+ // Clamp octaves to prevent performance issues
1713
+ const clampedOctaves = Math.max(1, Math.min(8, Math.floor(octaves)));
1714
+ let turbulence = 0, amplitude = 1, frequency = 1;
1715
+ for (let i = 0; i < clampedOctaves; i++) turbulence += Math.abs(noise2D(x * frequency + time, y * frequency - time)) * amplitude,
1716
+ frequency *= 2, amplitude *= .5;
1717
+ return turbulence;
1718
+ })(6 * ix, 6 * iy, time, 6), turbulenceX = .012 * Math.cos(turbulence * Math.PI * 2), turbulenceY = .012 * Math.sin(turbulence * Math.PI * 2), microSurface = ((x, y, time) =>
1719
+ // Add input validation
1720
+ "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = calculateLength(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = calculateLength(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothStep(.92, -.12, distanceToEdge), edgeSoftness = smoothStep(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
1721
+ return createTexture(clampValue(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clampValue(finalY + .5, 0, 1));
1722
+ }
1723
+ }, shaderUtils = Object.freeze( Object.defineProperty({
1724
+ __proto__: null,
1725
+ ShaderDisplacementGenerator: class {
1726
+ constructor(options) {
1727
+ if (this.options = options, this.canvasDPI = 1, !this.validateOptions(options)) throw new Error("Invalid shader options provided");
1728
+ this.canvas = document.createElement("canvas"),
1729
+ // Enhanced validation for canvas dimensions
1730
+ this.canvas.width = Math.max(1, Math.min(4096, Math.round(options.width * this.canvasDPI || 256))),
1731
+ this.canvas.height = Math.max(1, Math.min(4096, Math.round(options.height * this.canvasDPI || 256))),
1732
+ this.canvas.style.display = "none";
1733
+ const context = this.canvas.getContext("2d");
1734
+ if (!context) throw new Error("AtomixGlass: Could not get 2D canvas context");
1735
+ this.context = context;
1736
+ }
1737
+ validateOptions(options) {
1738
+ try {
1739
+ return options && "number" == typeof options.width && options.width > 0 && options.width <= 4096 && "number" == typeof options.height && options.height > 0 && options.height <= 4096 && "function" == typeof options.fragment;
1740
+ } catch (e) {
1741
+ // Graceful error handling
1742
+ return !1;
1743
+ }
1744
+ }
1745
+ updateShader(mousePosition) {
1746
+ try {
1747
+ const w = this.options.width * this.canvasDPI, h = this.options.height * this.canvasDPI;
1748
+ let maxScale = 0;
1749
+ const rawValues = [];
1750
+ // Calculate displacement values with enhanced smoothing
1751
+ for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
1752
+ const uv = {
1753
+ x: x / w,
1754
+ y: y / h
1755
+ }, pos = this.options.fragment(uv, mousePosition);
1756
+ let dx = pos.x * w - x, dy = pos.y * h - y;
1757
+ // Apply edge smoothing for Apple-like effect
1758
+ const edgeX = 2 * Math.min(x / w, (w - x) / w), edgeY = 2 * Math.min(y / h, (h - y) / h), edgeFactor = Math.min(edgeX, edgeY);
1759
+ dx *= smoothStep(0, .2, edgeFactor), dy *= smoothStep(0, .2, edgeFactor), maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)),
1760
+ rawValues.push(dx, dy);
1761
+ }
1762
+ // Improved normalization to prevent artifacts while maintaining intensity
1763
+ maxScale = Math.max(maxScale, 1);
1764
+ // Create ImageData and fill it
1765
+ const imageData = this.context.createImageData(w, h), data = imageData.data;
1766
+ // Convert to image data with smoother normalization
1767
+ let rawIndex = 0;
1768
+ for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
1769
+ const dx = rawValues[rawIndex++] || 0, dy = rawValues[rawIndex++] || 0, edgeDistance = Math.min(x, y, w - x - 1, h - y - 1), edgeFactor = Math.min(1, edgeDistance / 2), r = dx * edgeFactor / maxScale + .5, g = dy * edgeFactor / maxScale + .5, pixelIndex = 4 * (y * w + x);
1770
+ data[pixelIndex] = clampValue(255 * r, 0, 255), // Red channel (X displacement)
1771
+ data[pixelIndex + 1] = clampValue(255 * g, 0, 255), // Green channel (Y displacement)
1772
+ data[pixelIndex + 2] = clampValue(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
1773
+ data[pixelIndex + 3] = 255;
1774
+ }
1775
+ return this.context.putImageData(imageData, 0, 0), this.canvas.toDataURL();
1776
+ } catch (error) {
1777
+ // Graceful fallback on error
1778
+ return console.warn("ShaderDisplacementGenerator: Error generating shader map, using fallback", error),
1779
+ "";
1780
+ // Return empty string as fallback
1781
+ }
1782
+ }
1783
+ destroy() {
1784
+ try {
1785
+ // Clear canvas data to free memory
1786
+ this.context && this.context.clearRect(0, 0, this.canvas.width, this.canvas.height),
1787
+ // Reduce memory footprint by setting dimensions to 0
1788
+ this.canvas.width = 0, this.canvas.height = 0,
1789
+ // Remove from DOM
1790
+ this.canvas.remove();
1791
+ } catch (e) {
1792
+ // Silently handle cleanup errors
1793
+ console.warn("ShaderDisplacementGenerator: Error during cleanup", e);
1794
+ }
1795
+ }
1796
+ getScale() {
1797
+ return this.canvasDPI;
1798
+ }
1799
+ },
1800
+ fragmentShaders: fragmentShaders
1801
+ }, Symbol.toStringTag, {
1802
+ value: "Module"
1803
+ }));
1804
+
1805
+ var commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : {};
1806
+
1807
+ function getDefaultExportFromCjs(x) {
1808
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x.default : x;
1809
+ }
1810
+
1811
+ var fails$8 = function(exec) {
1812
+ try {
1813
+ return !!exec();
1814
+ } catch (error) {
1815
+ return !0;
1816
+ }
1817
+ }, functionBindNative = !fails$8((function() {
1818
+ // eslint-disable-next-line es/no-function-prototype-bind -- safe
1819
+ var test = function() {/* empty */}.bind();
1820
+ // eslint-disable-next-line no-prototype-builtins -- safe
1821
+ return "function" != typeof test || test.hasOwnProperty("prototype");
1822
+ })), NATIVE_BIND$3 = functionBindNative, FunctionPrototype$1 = Function.prototype, call$5 = FunctionPrototype$1.call, uncurryThisWithBind = NATIVE_BIND$3 && FunctionPrototype$1.bind.bind(call$5, call$5), functionUncurryThis = NATIVE_BIND$3 ? uncurryThisWithBind : function(fn) {
1823
+ return function() {
1824
+ return call$5.apply(fn, arguments);
1825
+ };
1826
+ }, objectIsPrototypeOf = functionUncurryThis({}.isPrototypeOf), check = function(it) {
1827
+ return it && it.Math === Math && it;
1828
+ }, globalThis_1 =
1829
+ // eslint-disable-next-line es/no-global-this -- safe
1830
+ check("object" == typeof globalThis && globalThis) || check("object" == typeof window && window) ||
1831
+ // eslint-disable-next-line no-restricted-globals -- safe
1832
+ check("object" == typeof self && self) || check("object" == typeof commonjsGlobal && commonjsGlobal) || check("object" == typeof commonjsGlobal && commonjsGlobal) ||
1833
+ // eslint-disable-next-line no-new-func -- fallback
1834
+ function() {
1835
+ return this;
1836
+ }() || Function("return this")(), NATIVE_BIND$2 = functionBindNative, FunctionPrototype = Function.prototype, apply$1 = FunctionPrototype.apply, call$4 = FunctionPrototype.call, functionApply = "object" == typeof Reflect && Reflect.apply || (NATIVE_BIND$2 ? call$4.bind(apply$1) : function() {
1837
+ return call$4.apply(apply$1, arguments);
1838
+ }), uncurryThis$7 = functionUncurryThis, toString$3 = uncurryThis$7({}.toString), stringSlice = uncurryThis$7("".slice), classofRaw$2 = function(it) {
1839
+ return stringSlice(toString$3(it), 8, -1);
1840
+ }, classofRaw$1 = classofRaw$2, uncurryThis$6 = functionUncurryThis, functionUncurryThisClause = function(fn) {
1841
+ // Nashorn bug:
1842
+ // https://github.com/zloirock/core-js/issues/1128
1843
+ // https://github.com/zloirock/core-js/issues/1130
1844
+ if ("Function" === classofRaw$1(fn)) return uncurryThis$6(fn);
1845
+ }, documentAll = "object" == typeof document && document.all, isCallable$8 = void 0 === documentAll && void 0 !== documentAll ? function(argument) {
1846
+ return "function" == typeof argument || argument === documentAll;
1847
+ } : function(argument) {
1848
+ return "function" == typeof argument;
1849
+ }, objectGetOwnPropertyDescriptor = {}, descriptors = !fails$8((function() {
1850
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
1851
+ return 7 !== Object.defineProperty({}, 1, {
1852
+ get: function() {
1853
+ return 7;
1854
+ }
1855
+ })[1];
1856
+ })), NATIVE_BIND$1 = functionBindNative, call$3 = Function.prototype.call, functionCall = NATIVE_BIND$1 ? call$3.bind(call$3) : function() {
1857
+ return call$3.apply(call$3, arguments);
1858
+ }, objectPropertyIsEnumerable = {}, $propertyIsEnumerable = {}.propertyIsEnumerable, getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor, NASHORN_BUG = getOwnPropertyDescriptor$1 && !$propertyIsEnumerable.call({
1859
+ 1: 2
1860
+ }, 1);
1861
+
1862
+ // `Object.prototype.propertyIsEnumerable` method implementation
1863
+ // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
1864
+ objectPropertyIsEnumerable.f = NASHORN_BUG ? function(V) {
1865
+ var descriptor = getOwnPropertyDescriptor$1(this, V);
1866
+ return !!descriptor && descriptor.enumerable;
1867
+ } : $propertyIsEnumerable;
1868
+
1869
+ var match, version, createPropertyDescriptor$2 = function(bitmap, value) {
1870
+ return {
1871
+ enumerable: !(1 & bitmap),
1872
+ configurable: !(2 & bitmap),
1873
+ writable: !(4 & bitmap),
1874
+ value: value
1875
+ };
1876
+ }, fails$5 = fails$8, classof$3 = classofRaw$2, $Object$3 = Object, split = functionUncurryThis("".split), indexedObject = fails$5((function() {
1877
+ // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
1878
+ // eslint-disable-next-line no-prototype-builtins -- safe
1879
+ return !$Object$3("z").propertyIsEnumerable(0);
1880
+ })) ? function(it) {
1881
+ return "String" === classof$3(it) ? split(it, "") : $Object$3(it);
1882
+ } : $Object$3, isNullOrUndefined$2 = function(it) {
1883
+ return null == it;
1884
+ }, isNullOrUndefined$1 = isNullOrUndefined$2, $TypeError$6 = TypeError, requireObjectCoercible$3 = function(it) {
1885
+ if (isNullOrUndefined$1(it)) throw new $TypeError$6("Can't call method on " + it);
1886
+ return it;
1887
+ }, IndexedObject = indexedObject, requireObjectCoercible$2 = requireObjectCoercible$3, toIndexedObject$2 = function(it) {
1888
+ return IndexedObject(requireObjectCoercible$2(it));
1889
+ }, isCallable$7 = isCallable$8, isObject$5 = function(it) {
1890
+ return "object" == typeof it ? null !== it : isCallable$7(it);
1891
+ }, path$3 = {}, path$2 = path$3, globalThis$a = globalThis_1, isCallable$6 = isCallable$8, aFunction = function(variable) {
1892
+ return isCallable$6(variable) ? variable : void 0;
1893
+ }, navigator$1 = globalThis_1.navigator, userAgent$1 = navigator$1 && navigator$1.userAgent, globalThis$8 = globalThis_1, userAgent = userAgent$1 ? String(userAgent$1) : "", process$1 = globalThis$8.process, Deno = globalThis$8.Deno, versions = process$1 && process$1.versions || Deno && Deno.version, v8 = versions && versions.v8;
1894
+
1895
+ v8 && (
1896
+ // in old Chrome, versions of V8 isn't V8 = Chrome / 10
1897
+ // but their correct versions are not interesting for us
1898
+ version = (match = v8.split("."))[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1])),
1899
+ // BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
1900
+ // so check `userAgent` even if `.v8` exists, but 0
1901
+ !version && userAgent && (!(match = userAgent.match(/Edge\/(\d+)/)) || match[1] >= 74) && (match = userAgent.match(/Chrome\/(\d+)/)) && (version = +match[1]);
1902
+
1903
+ var V8_VERSION = version, fails$4 = fails$8, $String$3 = globalThis_1.String, symbolConstructorDetection = !!Object.getOwnPropertySymbols && !fails$4((function() {
1904
+ var symbol = Symbol("symbol detection");
1905
+ // Chrome 38 Symbol has incorrect toString conversion
1906
+ // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
1907
+ // nb: Do not call `String` directly to avoid this being optimized out to `symbol+''` which will,
1908
+ // of course, fail.
1909
+ return !$String$3(symbol) || !(Object(symbol) instanceof Symbol) ||
1910
+ // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
1911
+ !Symbol.sham && V8_VERSION && V8_VERSION < 41;
1912
+ })), useSymbolAsUid = symbolConstructorDetection && !Symbol.sham && "symbol" == typeof Symbol.iterator, isCallable$5 = isCallable$8, isPrototypeOf$1 = objectIsPrototypeOf, $Object$2 = Object, isSymbol$2 = useSymbolAsUid ? function(it) {
1913
+ return "symbol" == typeof it;
1914
+ } : function(it) {
1915
+ var $Symbol = function(namespace, method) {
1916
+ return arguments.length < 2 ? aFunction(path$2[namespace]) || aFunction(globalThis$a[namespace]) : path$2[namespace] && path$2[namespace][method] || globalThis$a[namespace] && globalThis$a[namespace][method];
1917
+ }("Symbol");
1918
+ return isCallable$5($Symbol) && isPrototypeOf$1($Symbol.prototype, $Object$2(it));
1919
+ }, $String$2 = String, isCallable$4 = isCallable$8, $TypeError$5 = TypeError, aCallable$2 = function(argument) {
1920
+ if (isCallable$4(argument)) return argument;
1921
+ throw new $TypeError$5(function(argument) {
1922
+ try {
1923
+ return $String$2(argument);
1924
+ } catch (error) {
1925
+ return "Object";
1926
+ }
1927
+ }(argument) + " is not a function");
1928
+ }, aCallable$1 = aCallable$2, isNullOrUndefined = isNullOrUndefined$2, call$2 = functionCall, isCallable$3 = isCallable$8, isObject$4 = isObject$5, $TypeError$4 = TypeError, sharedStore = {
1929
+ exports: {}
1930
+ }, globalThis$6 = globalThis_1, defineProperty = Object.defineProperty, globalThis$5 = globalThis_1, store$1 = sharedStore.exports = globalThis$5["__core-js_shared__"] || function(key, value) {
1931
+ try {
1932
+ defineProperty(globalThis$6, key, {
1933
+ value: value,
1934
+ configurable: !0,
1935
+ writable: !0
1936
+ });
1937
+ } catch (error) {
1938
+ globalThis$6[key] = value;
1939
+ }
1940
+ return value;
1941
+ }("__core-js_shared__", {});
1942
+
1943
+ /* eslint-disable es/no-symbol -- required for testing */ (store$1.versions || (store$1.versions = [])).push({
1944
+ version: "3.43.0",
1945
+ mode: "pure",
1946
+ copyright: "© 2014-2025 Denis Pushkarev (zloirock.ru)",
1947
+ license: "https://github.com/zloirock/core-js/blob/v3.43.0/LICENSE",
1948
+ source: "https://github.com/zloirock/core-js"
1949
+ });
1950
+
1951
+ var key, value, store = sharedStore.exports, requireObjectCoercible$1 = requireObjectCoercible$3, $Object$1 = Object, hasOwnProperty = functionUncurryThis({}.hasOwnProperty), hasOwnProperty_1 = Object.hasOwn || function(it, key) {
1952
+ return hasOwnProperty($Object$1(requireObjectCoercible$1(it)), key);
1953
+ }, uncurryThis$3 = functionUncurryThis, id = 0, postfix = Math.random(), toString$2 = uncurryThis$3(1.1.toString), hasOwn$2 = hasOwnProperty_1, NATIVE_SYMBOL = symbolConstructorDetection, USE_SYMBOL_AS_UID = useSymbolAsUid, Symbol$1 = globalThis_1.Symbol, WellKnownSymbolsStore = store[key = "wks"] || (store[key] = value || {}), createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$1.for || Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || function(key) {
1954
+ return "Symbol(" + (void 0 === key ? "" : key) + ")_" + toString$2(++id + postfix, 36);
1955
+ }, wellKnownSymbol$5 = function(name) {
1956
+ return hasOwn$2(WellKnownSymbolsStore, name) || (WellKnownSymbolsStore[name] = NATIVE_SYMBOL && hasOwn$2(Symbol$1, name) ? Symbol$1[name] : createWellKnownSymbol("Symbol." + name)),
1957
+ WellKnownSymbolsStore[name];
1958
+ }, call$1 = functionCall, isObject$3 = isObject$5, isSymbol$1 = isSymbol$2, $TypeError$3 = TypeError, TO_PRIMITIVE = wellKnownSymbol$5("toPrimitive"), toPrimitive = function(input, pref) {
1959
+ if (!isObject$3(input) || isSymbol$1(input)) return input;
1960
+ var result, func, exoticToPrim = (func = input[TO_PRIMITIVE], isNullOrUndefined(func) ? void 0 : aCallable$1(func));
1961
+ if (exoticToPrim) {
1962
+ if (void 0 === pref && (pref = "default"), result = call$1(exoticToPrim, input, pref),
1963
+ !isObject$3(result) || isSymbol$1(result)) return result;
1964
+ throw new $TypeError$3("Can't convert object to primitive value");
1965
+ }
1966
+ return void 0 === pref && (pref = "number"), function(input, pref) {
1967
+ var fn, val;
1968
+ if ("string" === pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
1969
+ if (isCallable$3(fn = input.valueOf) && !isObject$4(val = call$2(fn, input))) return val;
1970
+ if ("string" !== pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
1971
+ throw new $TypeError$4("Can't convert object to primitive value");
1972
+ }(input, pref);
1973
+ }, isSymbol = isSymbol$2, toPropertyKey$2 = function(argument) {
1974
+ var key = toPrimitive(argument, "string");
1975
+ return isSymbol(key) ? key : key + "";
1976
+ }, isObject$2 = isObject$5, document$1 = globalThis_1.document, EXISTS = isObject$2(document$1) && isObject$2(document$1.createElement), ie8DomDefine = !descriptors && !fails$8((function() {
1977
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
1978
+ return 7 !== Object.defineProperty((it = "div", EXISTS ? document$1.createElement(it) : {}), "a", {
1979
+ get: function() {
1980
+ return 7;
1981
+ }
1982
+ }).a;
1983
+ var it;
1984
+ })), DESCRIPTORS$3 = descriptors, call = functionCall, propertyIsEnumerableModule = objectPropertyIsEnumerable, createPropertyDescriptor$1 = createPropertyDescriptor$2, toIndexedObject$1 = toIndexedObject$2, toPropertyKey$1 = toPropertyKey$2, hasOwn$1 = hasOwnProperty_1, IE8_DOM_DEFINE$1 = ie8DomDefine, $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
1985
+
1986
+ // `Object.getOwnPropertyDescriptor` method
1987
+ // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
1988
+ objectGetOwnPropertyDescriptor.f = DESCRIPTORS$3 ? $getOwnPropertyDescriptor$1 : function(O, P) {
1989
+ if (O = toIndexedObject$1(O), P = toPropertyKey$1(P), IE8_DOM_DEFINE$1) try {
1990
+ return $getOwnPropertyDescriptor$1(O, P);
1991
+ } catch (error) {/* empty */}
1992
+ if (hasOwn$1(O, P)) return createPropertyDescriptor$1(!call(propertyIsEnumerableModule.f, O, P), O[P]);
1993
+ };
1994
+
1995
+ var fails$2 = fails$8, isCallable$2 = isCallable$8, replacement = /#|\.prototype\./, isForced$1 = function(feature, detection) {
1996
+ var value = data[normalize(feature)];
1997
+ return value === POLYFILL || value !== NATIVE && (isCallable$2(detection) ? fails$2(detection) : !!detection);
1998
+ }, normalize = isForced$1.normalize = function(string) {
1999
+ return String(string).replace(replacement, ".").toLowerCase();
2000
+ }, data = isForced$1.data = {}, NATIVE = isForced$1.NATIVE = "N", POLYFILL = isForced$1.POLYFILL = "P", isForced_1 = isForced$1, aCallable = aCallable$2, NATIVE_BIND = functionBindNative, bind$1 = functionUncurryThisClause(functionUncurryThisClause.bind), objectDefineProperty = {}, v8PrototypeDefineBug = descriptors && fails$8((function() {
2001
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
2002
+ return 42 !== Object.defineProperty((function() {/* empty */}), "prototype", {
2003
+ value: 42,
2004
+ writable: !1
2005
+ }).prototype;
2006
+ })), isObject$1 = isObject$5, $String$1 = String, $TypeError$2 = TypeError, DESCRIPTORS$1 = descriptors, IE8_DOM_DEFINE = ie8DomDefine, V8_PROTOTYPE_DEFINE_BUG = v8PrototypeDefineBug, anObject = function(argument) {
2007
+ if (isObject$1(argument)) return argument;
2008
+ throw new $TypeError$2($String$1(argument) + " is not an object");
2009
+ }, toPropertyKey = toPropertyKey$2, $TypeError$1 = TypeError, $defineProperty = Object.defineProperty, $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
2010
+
2011
+ // `Object.defineProperty` method
2012
+ // https://tc39.es/ecma262/#sec-object.defineproperty
2013
+ objectDefineProperty.f = DESCRIPTORS$1 ? V8_PROTOTYPE_DEFINE_BUG ? function(O, P, Attributes) {
2014
+ if (anObject(O), P = toPropertyKey(P), anObject(Attributes), "function" == typeof O && "prototype" === P && "value" in Attributes && "writable" in Attributes && !Attributes.writable) {
2015
+ var current = $getOwnPropertyDescriptor(O, P);
2016
+ current && current.writable && (O[P] = Attributes.value, Attributes = {
2017
+ configurable: "configurable" in Attributes ? Attributes.configurable : current.configurable,
2018
+ enumerable: "enumerable" in Attributes ? Attributes.enumerable : current.enumerable,
2019
+ writable: !1
2020
+ });
2021
+ }
2022
+ return $defineProperty(O, P, Attributes);
2023
+ } : $defineProperty : function(O, P, Attributes) {
2024
+ if (anObject(O), P = toPropertyKey(P), anObject(Attributes), IE8_DOM_DEFINE) try {
2025
+ return $defineProperty(O, P, Attributes);
2026
+ } catch (error) {/* empty */}
2027
+ if ("get" in Attributes || "set" in Attributes) throw new $TypeError$1("Accessors not supported");
2028
+ return "value" in Attributes && (O[P] = Attributes.value), O;
2029
+ };
2030
+
2031
+ var definePropertyModule = objectDefineProperty, createPropertyDescriptor = createPropertyDescriptor$2, createNonEnumerableProperty$1 = descriptors ? function(object, key, value) {
2032
+ return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));
2033
+ } : function(object, key, value) {
2034
+ return object[key] = value, object;
2035
+ }, globalThis$2 = globalThis_1, apply = functionApply, uncurryThis$1 = functionUncurryThisClause, isCallable$1 = isCallable$8, getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f, isForced = isForced_1, path$1 = path$3, bind = function(fn, that) {
2036
+ return aCallable(fn), void 0 === that ? fn : NATIVE_BIND ? bind$1(fn, that) : function() {
2037
+ return fn.apply(that, arguments);
2038
+ };
2039
+ }, createNonEnumerableProperty = createNonEnumerableProperty$1, hasOwn = hasOwnProperty_1, wrapConstructor = function(NativeConstructor) {
2040
+ var Wrapper = function(a, b, c) {
2041
+ if (this instanceof Wrapper) {
2042
+ switch (arguments.length) {
2043
+ case 0:
2044
+ return new NativeConstructor;
2045
+
2046
+ case 1:
2047
+ return new NativeConstructor(a);
2048
+
2049
+ case 2:
2050
+ return new NativeConstructor(a, b);
2051
+ }
2052
+ return new NativeConstructor(a, b, c);
2053
+ }
2054
+ return apply(NativeConstructor, this, arguments);
2055
+ };
2056
+ return Wrapper.prototype = NativeConstructor.prototype, Wrapper;
2057
+ }, _export = function(options, source) {
2058
+ var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE, key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor, TARGET = options.target, GLOBAL = options.global, STATIC = options.stat, PROTO = options.proto, nativeSource = GLOBAL ? globalThis$2 : STATIC ? globalThis$2[TARGET] : globalThis$2[TARGET] && globalThis$2[TARGET].prototype, target = GLOBAL ? path$1 : path$1[TARGET] || createNonEnumerableProperty(path$1, TARGET, {})[TARGET], targetPrototype = target.prototype;
2059
+ for (key in source)
2060
+ // contains in native
2061
+ USE_NATIVE = !(FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? "." : "#") + key, options.forced)) && nativeSource && hasOwn(nativeSource, key),
2062
+ targetProperty = target[key], USE_NATIVE && (nativeProperty = options.dontCallGetSet ? (descriptor = getOwnPropertyDescriptor(nativeSource, key)) && descriptor.value : nativeSource[key]),
2063
+ // export native or implementation
2064
+ sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key], (FORCED || PROTO || typeof targetProperty != typeof sourceProperty) && (
2065
+ // bind methods to global for calling from export context
2066
+ resultProperty = options.bind && USE_NATIVE ? bind(sourceProperty, globalThis$2) : options.wrap && USE_NATIVE ? wrapConstructor(sourceProperty) : PROTO && isCallable$1(sourceProperty) ? uncurryThis$1(sourceProperty) : sourceProperty,
2067
+ // add a flag to not completely full polyfills
2068
+ (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) && createNonEnumerableProperty(resultProperty, "sham", !0),
2069
+ createNonEnumerableProperty(target, key, resultProperty), PROTO && (hasOwn(path$1, VIRTUAL_PROTOTYPE = TARGET + "Prototype") || createNonEnumerableProperty(path$1, VIRTUAL_PROTOTYPE, {}),
2070
+ // export virtual prototype methods
2071
+ createNonEnumerableProperty(path$1[VIRTUAL_PROTOTYPE], key, sourceProperty),
2072
+ // export real prototype methods
2073
+ options.real && targetPrototype && (FORCED || !targetPrototype[key]) && createNonEnumerableProperty(targetPrototype, key, sourceProperty)));
2074
+ }, ceil = Math.ceil, floor = Math.floor, trunc = Math.trunc || function(x) {
2075
+ var n = +x;
2076
+ return (n > 0 ? floor : ceil)(n);
2077
+ }, toIntegerOrInfinity$2 = function(argument) {
2078
+ var number = +argument;
2079
+ // eslint-disable-next-line no-self-compare -- NaN check
2080
+ return number != number || 0 === number ? 0 : trunc(number);
2081
+ }, toIntegerOrInfinity$1 = toIntegerOrInfinity$2, max = Math.max, min$1 = Math.min, toIntegerOrInfinity = toIntegerOrInfinity$2, min = Math.min, toIndexedObject = toIndexedObject$2, lengthOfArrayLike = function(obj) {
2082
+ return argument = obj.length, (len = toIntegerOrInfinity(argument)) > 0 ? min(len, 9007199254740991) : 0;
2083
+ var argument, len;
2084
+ }, createMethod = function(IS_INCLUDES) {
2085
+ return function($this, el, fromIndex) {
2086
+ var O = toIndexedObject($this), length = lengthOfArrayLike(O);
2087
+ if (0 === length) return !IS_INCLUDES && -1;
2088
+ var value, index = function(index, length) {
2089
+ var integer = toIntegerOrInfinity$1(index);
2090
+ return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
2091
+ }(fromIndex, length);
2092
+ // Array#includes uses SameValueZero equality algorithm
2093
+ // eslint-disable-next-line no-self-compare -- NaN check
2094
+ if (IS_INCLUDES && el != el) {
2095
+ for (;length > index; )
2096
+ // eslint-disable-next-line no-self-compare -- NaN check
2097
+ if ((value = O[index++]) != value) return !0;
2098
+ // Array#indexOf ignores holes, Array#includes - not
2099
+ } else for (;length > index; index++) if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
2100
+ return !IS_INCLUDES && -1;
2101
+ };
2102
+ }, $includes = [ createMethod(!0), createMethod(!1) ][0];
2103
+
2104
+ // `Array.prototype.includes` method
2105
+ // https://tc39.es/ecma262/#sec-array.prototype.includes
2106
+ _export({
2107
+ target: "Array",
2108
+ proto: !0,
2109
+ forced: fails$8((function() {
2110
+ // eslint-disable-next-line es/no-array-prototype-includes -- detection
2111
+ return !Array(1).includes();
2112
+ }))
2113
+ }, {
2114
+ includes: function(el /* , fromIndex = 0 */) {
2115
+ return $includes(this, el, arguments.length > 1 ? arguments[1] : void 0);
2116
+ }
2117
+ });
2118
+
2119
+ var globalThis$1 = globalThis_1, path = path$3, getBuiltInPrototypeMethod$2 = function(CONSTRUCTOR, METHOD) {
2120
+ var Namespace = path[CONSTRUCTOR + "Prototype"], pureMethod = Namespace && Namespace[METHOD];
2121
+ if (pureMethod) return pureMethod;
2122
+ var NativeConstructor = globalThis$1[CONSTRUCTOR], NativePrototype = NativeConstructor && NativeConstructor.prototype;
2123
+ return NativePrototype && NativePrototype[METHOD];
2124
+ }, includes$4 = getBuiltInPrototypeMethod$2("Array", "includes"), isObject = isObject$5, classof$2 = classofRaw$2, MATCH$1 = wellKnownSymbol$5("match"), $TypeError = TypeError, test = {};
2125
+
2126
+ test[wellKnownSymbol$5("toStringTag")] = "z";
2127
+
2128
+ var TO_STRING_TAG_SUPPORT = "[object z]" === String(test), isCallable = isCallable$8, classofRaw = classofRaw$2, TO_STRING_TAG = wellKnownSymbol$5("toStringTag"), $Object = Object, CORRECT_ARGUMENTS = "Arguments" === classofRaw(function() {
2129
+ return arguments;
2130
+ }()), classof = TO_STRING_TAG_SUPPORT ? classofRaw : function(it) {
2131
+ var O, tag, result;
2132
+ return void 0 === it ? "Undefined" : null === it ? "Null" : "string" == typeof (tag = function(it, key) {
2133
+ try {
2134
+ return it[key];
2135
+ } catch (error) {/* empty */}
2136
+ }(O = $Object(it), TO_STRING_TAG)) ? tag : CORRECT_ARGUMENTS ? classofRaw(O) : "Object" === (result = classofRaw(O)) && isCallable(O.callee) ? "Arguments" : result;
2137
+ }, $String = String, MATCH = wellKnownSymbol$5("match"), $ = _export, notARegExp = function(it) {
2138
+ if (function(it) {
2139
+ var isRegExp;
2140
+ return isObject(it) && (void 0 !== (isRegExp = it[MATCH$1]) ? !!isRegExp : "RegExp" === classof$2(it));
2141
+ }(it)) throw new $TypeError("The method doesn't accept regular expressions");
2142
+ return it;
2143
+ }, requireObjectCoercible = requireObjectCoercible$3, toString = function(argument) {
2144
+ if ("Symbol" === classof(argument)) throw new TypeError("Cannot convert a Symbol value to a string");
2145
+ return $String(argument);
2146
+ }, stringIndexOf = functionUncurryThis("".indexOf);
2147
+
2148
+ // `String.prototype.includes` method
2149
+ // https://tc39.es/ecma262/#sec-string.prototype.includes
2150
+ $({
2151
+ target: "String",
2152
+ proto: !0,
2153
+ forced: !function(METHOD_NAME) {
2154
+ var regexp = /./;
2155
+ try {
2156
+ "/./"[METHOD_NAME](regexp);
2157
+ } catch (error1) {
2158
+ try {
2159
+ return regexp[MATCH] = !1, "/./"[METHOD_NAME](regexp);
2160
+ } catch (error2) {/* empty */}
2161
+ }
2162
+ return !1;
2163
+ }("includes")
2164
+ }, {
2165
+ includes: function(searchString /* , position = 0 */) {
2166
+ return !!~stringIndexOf(toString(requireObjectCoercible(this)), toString(notARegExp(searchString)), arguments.length > 1 ? arguments[1] : void 0);
2167
+ }
2168
+ });
2169
+
2170
+ var includes$3 = getBuiltInPrototypeMethod$2("String", "includes"), isPrototypeOf = objectIsPrototypeOf, arrayMethod = includes$4, stringMethod = includes$3, ArrayPrototype = Array.prototype, StringPrototype = String.prototype;
2171
+
2172
+ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
2173
+ var own = it.includes;
2174
+ return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.includes ? arrayMethod : "string" == typeof it || it === StringPrototype || isPrototypeOf(StringPrototype, it) && own === StringPrototype.includes ? stringMethod : own;
2175
+ }));
2176
+
2177
+ /**
2178
+ * Component Utilities
2179
+ *
2180
+ * Helper functions for component development with the new customization system
2181
+ */
2182
+ /**
2183
+ * Check if a URL is a YouTube URL
2184
+ */
2185
+ function isYouTubeUrl(url) {
2186
+ return /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/.test(url);
2187
+ }
2188
+
2189
+ /**
2190
+ * Extract YouTube video ID from URL
2191
+ */
2192
+ /**
2193
+ * Advanced Video Player Component
2194
+ */
2195
+ const VideoPlayer = forwardRef((({src: src, type: type = "video", youtubeId: youtubeId, poster: poster, autoplay: autoplay = !1, loop: loop = !1, muted: muted = !1, controls: controls = !0, preload: preload = "metadata", width: width, height: height, aspectRatio: aspectRatio = "16:9", className: className = "", onPlay: onPlay, onPause: onPause, onEnded: onEnded, onTimeUpdate: onTimeUpdate, onVolumeChange: onVolumeChange, onFullscreenChange: onFullscreenChange, onError: onError, showDownload: showDownload = !1, showShare: showShare = !1, showSettings: showSettings = !0, playbackRates: playbackRates = [ .5, .75, 1, 1.25, 1.5, 2 ], subtitles: subtitles, quality: quality, ambientMode: ambientMode = !1, glass: glass = !1, glassOpacity: glassOpacity = 1, glassContent: glassContent, style: style, ...props}, ref) => {
2196
+ const videoRef = useRef(null), containerRef = useRef(null), canvasRef = useRef(null), iframeRef = useRef(null), [containerBorderRadius, setContainerBorderRadius] = useState(8), isYouTube = "youtube" === type || youtubeId || src && isYouTubeUrl(src), videoId = youtubeId || (isYouTube && src ? function(url) {
2197
+ if (!isYouTubeUrl(url)) return null;
2198
+ const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/.*[?&]v=([^&\n?#]+)/ ];
2199
+ for (const pattern of patterns) {
2200
+ const match = url.match(pattern);
2201
+ if (match && match[1]) return match[1];
2202
+ }
2203
+ return null;
2204
+ }(src) : null), {isPlaying: isPlaying, currentTime: currentTime, duration: duration, volume: volume, isMuted: isMuted, isFullscreen: isFullscreen, isLoading: isLoading, playbackRate: playbackRate, currentQuality: currentQuality, showControls: showControls, play: play, pause: pause, togglePlay: togglePlay, seek: seek, setVolume: setVolume, toggleMute: toggleMute, toggleFullscreen: toggleFullscreen, togglePictureInPicture: togglePictureInPicture, setPlaybackRate: setPlaybackRate, setQuality: setQuality, formatTime: formatTime, getProgressPercentage: getProgressPercentage, getBufferedPercentage: getBufferedPercentage} = function({videoRef: videoRef, containerRef: containerRef, onPlay: onPlay, onPause: onPause, onEnded: onEnded, onTimeUpdate: onTimeUpdate, onVolumeChange: onVolumeChange, onFullscreenChange: onFullscreenChange, onError: onError, playbackRates: playbackRates = [ .5, .75, 1, 1.25, 1.5, 2 ], quality: quality}) {
2205
+ const [isPlaying, setIsPlaying] = useState(!1), [currentTime, setCurrentTime] = useState(0), [duration, setDuration] = useState(0), [volume, setVolumeState] = useState(1), [isMuted, setIsMuted] = useState(!1), [isFullscreen, setIsFullscreen] = useState(!1), [isPictureInPicture, setIsPictureInPicture] = useState(!1), [isLoading, setIsLoading] = useState(!1), [buffered, setBuffered] = useState(0), [playbackRate, setPlaybackRateState] = useState(1), [currentQuality, setCurrentQuality] = useState(quality?.[0] || null), [showControls, setShowControls] = useState(!0), controlsTimeoutRef = useRef(null), resetControlsTimeout = useCallback((() => {
2206
+ controlsTimeoutRef.current && clearTimeout(controlsTimeoutRef.current), setShowControls(!0);
2207
+ const timeout = setTimeout((() => {
2208
+ isPlaying && setShowControls(!1);
2209
+ }), 3e3);
2210
+ controlsTimeoutRef.current = timeout;
2211
+ }), [ isPlaying ]), play = useCallback((async () => {
2212
+ if (videoRef.current) try {
2213
+ await videoRef.current.play(), setIsPlaying(!0), onPlay?.();
2214
+ } catch (error) {
2215
+ console.error("Error playing video:", error), onError?.(error), setIsPlaying(!1);
2216
+ }
2217
+ }), [ videoRef, onPlay, onError ]), pause = useCallback((() => {
2218
+ videoRef.current && (videoRef.current.pause(), setIsPlaying(!1), onPause?.());
2219
+ }), [ videoRef, onPause ]), togglePlay = useCallback((() => {
2220
+ isPlaying ? pause() : play();
2221
+ }), [ isPlaying, play, pause ]), seek = useCallback((time => {
2222
+ videoRef.current && (videoRef.current.currentTime = Math.max(0, Math.min(time, duration)));
2223
+ }), [ videoRef, duration ]), setVolume = useCallback((newVolume => {
2224
+ const clampedVolume = Math.max(0, Math.min(1, newVolume));
2225
+ videoRef.current && (videoRef.current.volume = clampedVolume, setVolumeState(clampedVolume),
2226
+ setIsMuted(0 === clampedVolume), onVolumeChange?.(clampedVolume));
2227
+ }), [ videoRef, onVolumeChange ]), toggleMute = useCallback((() => {
2228
+ if (videoRef.current) {
2229
+ const newMuted = !isMuted;
2230
+ videoRef.current.muted = newMuted, setIsMuted(newMuted);
2231
+ }
2232
+ }), [ videoRef, isMuted ]), toggleFullscreen = useCallback((async () => {
2233
+ if (containerRef.current) try {
2234
+ isFullscreen ? document.exitFullscreen && await document.exitFullscreen() : containerRef.current.requestFullscreen && await containerRef.current.requestFullscreen();
2235
+ } catch (error) {
2236
+ console.error("Fullscreen error:", error);
2237
+ }
2238
+ }), [ containerRef, isFullscreen ]), togglePictureInPicture = useCallback((async () => {
2239
+ if (videoRef.current) try {
2240
+ isPictureInPicture ? document.exitPictureInPicture && await document.exitPictureInPicture() : videoRef.current.requestPictureInPicture && await videoRef.current.requestPictureInPicture();
2241
+ } catch (error) {
2242
+ console.error("Picture-in-picture error:", error);
2243
+ }
2244
+ }), [ videoRef, isPictureInPicture ]), setPlaybackRate = useCallback((rate => {
2245
+ videoRef.current && _includesInstanceProperty(playbackRates).call(playbackRates, rate) && (videoRef.current.playbackRate = rate,
2246
+ setPlaybackRateState(rate));
2247
+ }), [ videoRef, playbackRates ]), setQuality = useCallback((newQuality => {
2248
+ if (videoRef.current && quality) {
2249
+ const currentTime = videoRef.current.currentTime, wasPlaying = !videoRef.current.paused, sanitizedSrc = String(newQuality.src).replace(/[<>"']/g, "");
2250
+ sanitizedSrc && (sanitizedSrc.startsWith("http://") || sanitizedSrc.startsWith("https://") || sanitizedSrc.startsWith("blob:") || sanitizedSrc.startsWith("data:")) && (videoRef.current.src = sanitizedSrc,
2251
+ videoRef.current.currentTime = currentTime, wasPlaying && videoRef.current.play(),
2252
+ setCurrentQuality(newQuality));
2253
+ }
2254
+ }), [ videoRef, quality ]), formatTime = useCallback((time => {
2255
+ const hours = Math.floor(time / 3600), minutes = Math.floor(time % 3600 / 60), seconds = Math.floor(time % 60);
2256
+ return hours > 0 ? `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}` : `${minutes}:${seconds.toString().padStart(2, "0")}`;
2257
+ }), []), getProgressPercentage = useCallback((() => duration > 0 ? currentTime / duration * 100 : 0), [ currentTime, duration ]), getBufferedPercentage = useCallback((() => duration > 0 ? buffered / duration * 100 : 0), [ buffered, duration ]);
2258
+ // Event listeners
2259
+ useEffect((() => {
2260
+ const video = videoRef.current;
2261
+ if (!video) return;
2262
+ const handleLoadStart = () => setIsLoading(!0), handleCanPlay = () => setIsLoading(!1), handleLoadedMetadata = () => {
2263
+ setDuration(video.duration), setVolumeState(video.volume), setIsMuted(video.muted);
2264
+ }, handleTimeUpdate = () => {
2265
+ setCurrentTime(video.currentTime), onTimeUpdate?.(video.currentTime);
2266
+ }, handleProgress = () => {
2267
+ video.buffered.length > 0 && setBuffered(video.buffered.end(video.buffered.length - 1));
2268
+ }, handlePlay = () => {
2269
+ setIsPlaying(!0), onPlay?.();
2270
+ }, handlePause = () => {
2271
+ setIsPlaying(!1), onPause?.();
2272
+ }, handleEnded = () => {
2273
+ setIsPlaying(!1), onEnded?.();
2274
+ }, handleVolumeChange = () => {
2275
+ setVolumeState(video.volume), setIsMuted(video.muted), onVolumeChange?.(video.volume);
2276
+ }, handleError = e => {
2277
+ setIsLoading(!1), onError?.(e);
2278
+ }, handleEnterpictureinpicture = () => setIsPictureInPicture(!0), handleLeavepictureinpicture = () => setIsPictureInPicture(!1);
2279
+ return video.addEventListener("loadstart", handleLoadStart), video.addEventListener("canplay", handleCanPlay),
2280
+ video.addEventListener("loadedmetadata", handleLoadedMetadata), video.addEventListener("timeupdate", handleTimeUpdate),
2281
+ video.addEventListener("progress", handleProgress), video.addEventListener("play", handlePlay),
2282
+ video.addEventListener("pause", handlePause), video.addEventListener("ended", handleEnded),
2283
+ video.addEventListener("volumechange", handleVolumeChange), video.addEventListener("error", handleError),
2284
+ video.addEventListener("enterpictureinpicture", handleEnterpictureinpicture), video.addEventListener("leavepictureinpicture", handleLeavepictureinpicture),
2285
+ () => {
2286
+ video.removeEventListener("loadstart", handleLoadStart), video.removeEventListener("canplay", handleCanPlay),
2287
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata), video.removeEventListener("timeupdate", handleTimeUpdate),
2288
+ video.removeEventListener("progress", handleProgress), video.removeEventListener("play", handlePlay),
2289
+ video.removeEventListener("pause", handlePause), video.removeEventListener("ended", handleEnded),
2290
+ video.removeEventListener("volumechange", handleVolumeChange), video.removeEventListener("error", handleError),
2291
+ video.removeEventListener("enterpictureinpicture", handleEnterpictureinpicture),
2292
+ video.removeEventListener("leavepictureinpicture", handleLeavepictureinpicture);
2293
+ };
2294
+ }), [ videoRef, onPlay, onPause, onEnded, onTimeUpdate, onVolumeChange, onError ]),
2295
+ // Fullscreen event listeners
2296
+ useEffect((() => {
2297
+ const handleFullscreenChange = () => {
2298
+ const isCurrentlyFullscreen = !!document.fullscreenElement;
2299
+ setIsFullscreen(isCurrentlyFullscreen), onFullscreenChange?.(isCurrentlyFullscreen);
2300
+ };
2301
+ return document.addEventListener("fullscreenchange", handleFullscreenChange), () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
2302
+ }), [ onFullscreenChange ]);
2303
+ // Keyboard shortcuts
2304
+ const handleKeyDown = useCallback((e => {
2305
+ if (containerRef.current?.contains(document.activeElement)) switch (e.code) {
2306
+ case "Space":
2307
+ e.preventDefault(), togglePlay();
2308
+ break;
2309
+
2310
+ case "ArrowLeft":
2311
+ e.preventDefault(), seek(currentTime - 10);
2312
+ break;
2313
+
2314
+ case "ArrowRight":
2315
+ e.preventDefault(), seek(currentTime + 10);
2316
+ break;
2317
+
2318
+ case "ArrowUp":
2319
+ e.preventDefault(), setVolume(Math.min(1, volume + .1));
2320
+ break;
2321
+
2322
+ case "ArrowDown":
2323
+ e.preventDefault(), setVolume(Math.max(0, volume - .1));
2324
+ break;
2325
+
2326
+ case "KeyM":
2327
+ e.preventDefault(), toggleMute();
2328
+ break;
2329
+
2330
+ case "KeyF":
2331
+ e.preventDefault(), toggleFullscreen();
2332
+ }
2333
+ }), [ togglePlay, seek, currentTime, setVolume, volume, toggleMute, toggleFullscreen, containerRef ]);
2334
+ useEffect((() => (document.addEventListener("keydown", handleKeyDown), () => document.removeEventListener("keydown", handleKeyDown))), [ handleKeyDown ]);
2335
+ // Mouse movement for controls
2336
+ const handleMouseMove = useCallback((() => resetControlsTimeout()), [ resetControlsTimeout ]), handleMouseLeave = useCallback((() => {
2337
+ controlsTimeoutRef.current && clearTimeout(controlsTimeoutRef.current), isPlaying && setShowControls(!1);
2338
+ }), [ isPlaying ]);
2339
+ return useEffect((() => {
2340
+ const container = containerRef.current;
2341
+ if (container) return container.addEventListener("mousemove", handleMouseMove),
2342
+ container.addEventListener("mouseleave", handleMouseLeave), () => {
2343
+ container.removeEventListener("mousemove", handleMouseMove), container.removeEventListener("mouseleave", handleMouseLeave),
2344
+ controlsTimeoutRef.current && clearTimeout(controlsTimeoutRef.current);
2345
+ };
2346
+ }), [ containerRef, handleMouseMove, handleMouseLeave ]), {
2347
+ isPlaying: isPlaying,
2348
+ currentTime: currentTime,
2349
+ duration: duration,
2350
+ volume: volume,
2351
+ isMuted: isMuted,
2352
+ isFullscreen: isFullscreen,
2353
+ isPictureInPicture: isPictureInPicture,
2354
+ isLoading: isLoading,
2355
+ buffered: buffered,
2356
+ playbackRate: playbackRate,
2357
+ currentQuality: currentQuality,
2358
+ showControls: showControls,
2359
+ play: play,
2360
+ pause: pause,
2361
+ togglePlay: togglePlay,
2362
+ seek: seek,
2363
+ setVolume: setVolume,
2364
+ toggleMute: toggleMute,
2365
+ toggleFullscreen: toggleFullscreen,
2366
+ togglePictureInPicture: togglePictureInPicture,
2367
+ setPlaybackRate: setPlaybackRate,
2368
+ setQuality: setQuality,
2369
+ formatTime: formatTime,
2370
+ getProgressPercentage: getProgressPercentage,
2371
+ getBufferedPercentage: getBufferedPercentage
2372
+ };
2373
+ }({
2374
+ videoRef: videoRef,
2375
+ containerRef: containerRef,
2376
+ onPlay: onPlay,
2377
+ onPause: onPause,
2378
+ onEnded: onEnded,
2379
+ onTimeUpdate: onTimeUpdate,
2380
+ onVolumeChange: onVolumeChange,
2381
+ onFullscreenChange: onFullscreenChange,
2382
+ onError: onError,
2383
+ playbackRates: playbackRates,
2384
+ quality: quality
2385
+ });
2386
+ !function({videoRef: videoRef, canvasRef: canvasRef, enabled: enabled, blur: blur = 60, opacity: opacity = .6, scale: scale = 1.2}) {
2387
+ const animationFrameRef = useRef(60);
2388
+ useEffect((() => {
2389
+ if (!enabled || !videoRef.current || !canvasRef.current) return;
2390
+ const video = videoRef.current, canvas = canvasRef.current, ctx = canvas.getContext("2d");
2391
+ if (!ctx) return;
2392
+ const updateAmbientEffect = () => {
2393
+ if (!video || !canvas || !ctx) return;
2394
+ // Set canvas size to match container
2395
+ const rect = video.getBoundingClientRect();
2396
+ canvas.width = rect.width * scale, canvas.height = rect.height * scale,
2397
+ // Draw video frame to canvas
2398
+ ctx.filter = `blur(${blur}px)`, ctx.globalAlpha = opacity;
2399
+ try {
2400
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
2401
+ } catch (e) {
2402
+ // Handle CORS or other drawing errors silently
2403
+ }
2404
+ enabled && (animationFrameRef.current = requestAnimationFrame(updateAmbientEffect));
2405
+ }, handlePlay = () => {
2406
+ enabled && updateAmbientEffect();
2407
+ }, handlePause = () => {
2408
+ animationFrameRef.current && cancelAnimationFrame(animationFrameRef.current);
2409
+ };
2410
+ // Start ambient effect when video plays
2411
+ return video.addEventListener("play", handlePlay), video.addEventListener("pause", handlePause),
2412
+ video.addEventListener("ended", handlePause),
2413
+ // Initial setup if video is already playing
2414
+ video.paused || handlePlay(), () => {
2415
+ video.removeEventListener("play", handlePlay), video.removeEventListener("pause", handlePause),
2416
+ video.removeEventListener("ended", handlePause), animationFrameRef.current && cancelAnimationFrame(animationFrameRef.current);
2417
+ };
2418
+ }), [ enabled, blur, opacity, scale, videoRef, canvasRef ]);
2419
+ }({
2420
+ videoRef: videoRef,
2421
+ canvasRef: canvasRef,
2422
+ enabled: ambientMode
2423
+ });
2424
+ const [showSettingsMenu, setShowSettingsMenu] = useState(!1), [activeSettingsTab, setActiveSettingsTab] = useState("quality"), [activeSubtitle, setActiveSubtitle] = useState(subtitles?.find((sub => sub.default))?.srcLang || null), [videoDimensions, setVideoDimensions] = useState({
2425
+ width: 0,
2426
+ height: 0
2427
+ }), handleProgressClick = useCallback((e => {
2428
+ const rect = e.currentTarget.getBoundingClientRect(), percent = (e.clientX - rect.left) / rect.width;
2429
+ seek(percent * duration);
2430
+ }), [ duration, seek ]), handleVolumeClick = useCallback((e => {
2431
+ const rect = e.currentTarget.getBoundingClientRect(), percent = (e.clientX - rect.left) / rect.width;
2432
+ setVolume(percent);
2433
+ }), [ setVolume ]), handleDownload = useCallback((() => {
2434
+ if (src) {
2435
+ const a = document.createElement("a");
2436
+ a.href = src, a.download = "video", a.click();
2437
+ }
2438
+ }), [ src ]), handleShare = useCallback((async () => {
2439
+ if (navigator.share) try {
2440
+ await navigator.share({
2441
+ title: "Video",
2442
+ url: window.location.href
2443
+ });
2444
+ } catch (err) {}
2445
+ }), []), setSubtitle = useCallback((subtitleLang => {
2446
+ const video = videoRef.current;
2447
+ if (video) {
2448
+ const tracks = video.textTracks;
2449
+ // Hide all tracks first
2450
+ for (let i = 0; i < tracks.length; i++) {
2451
+ const track = tracks[i];
2452
+ track && (track.mode = "hidden");
2453
+ }
2454
+ // Show selected track
2455
+ if (subtitleLang) for (let i = 0; i < tracks.length; i++) {
2456
+ const track = tracks[i];
2457
+ if (track && track.language === subtitleLang) {
2458
+ track.mode = "showing";
2459
+ break;
2460
+ }
2461
+ }
2462
+ setActiveSubtitle(subtitleLang);
2463
+ }
2464
+ }), [ videoRef ]);
2465
+ // Initialize subtitle tracks when video loads
2466
+ useEffect((() => {
2467
+ const video = videoRef.current;
2468
+ if (video && subtitles) {
2469
+ const handleLoadedData = () => {
2470
+ // Wait for tracks to be loaded
2471
+ setTimeout((() => {
2472
+ const defaultSubtitle = subtitles.find((sub => sub.default));
2473
+ defaultSubtitle && setSubtitle(defaultSubtitle.srcLang);
2474
+ }), 100);
2475
+ }, handleCanPlay = () => {
2476
+ // Ensure tracks are ready
2477
+ if (video.textTracks.length > 0) {
2478
+ const defaultSubtitle = subtitles.find((sub => sub.default));
2479
+ defaultSubtitle && setSubtitle(defaultSubtitle.srcLang);
2480
+ }
2481
+ };
2482
+ return video.addEventListener("loadeddata", handleLoadedData), video.addEventListener("canplay", handleCanPlay),
2483
+ () => {
2484
+ video.removeEventListener("loadeddata", handleLoadedData), video.removeEventListener("canplay", handleCanPlay);
2485
+ };
2486
+ }
2487
+ }), [ subtitles, setSubtitle, videoRef ]),
2488
+ // Track video/iframe dimensions for AtomixGlass
2489
+ useEffect((() => {
2490
+ const updateDimensions = () => {
2491
+ if (isYouTube && iframeRef.current) {
2492
+ const rect = iframeRef.current.getBoundingClientRect();
2493
+ setVideoDimensions({
2494
+ width: rect.width,
2495
+ height: rect.height
2496
+ });
2497
+ } else if (videoRef.current) {
2498
+ const rect = videoRef.current.getBoundingClientRect();
2499
+ setVideoDimensions({
2500
+ width: rect.width,
2501
+ height: rect.height
2502
+ });
2503
+ }
2504
+ }, initialTimer = setTimeout(updateDimensions, 100), resizeObserver = new ResizeObserver(updateDimensions);
2505
+ // Initial measurement with slight delay to ensure element is rendered
2506
+ if (isYouTube && iframeRef.current) {
2507
+ const iframe = iframeRef.current;
2508
+ resizeObserver.observe(iframe);
2509
+ // Listen for iframe load event
2510
+ const handleIframeLoad = () => updateDimensions();
2511
+ return iframe.addEventListener("load", handleIframeLoad), () => {
2512
+ clearTimeout(initialTimer), resizeObserver.disconnect(), iframe.removeEventListener("load", handleIframeLoad);
2513
+ };
2514
+ }
2515
+ // Also listen for window resize
2516
+ if (videoRef.current) {
2517
+ const video = videoRef.current;
2518
+ resizeObserver.observe(video);
2519
+ // Listen for video metadata loaded event
2520
+ const handleLoadedMetadata = () => updateDimensions();
2521
+ return video.addEventListener("loadedmetadata", handleLoadedMetadata), () => {
2522
+ clearTimeout(initialTimer), resizeObserver.disconnect(), video.removeEventListener("loadedmetadata", handleLoadedMetadata);
2523
+ };
2524
+ }
2525
+ return window.addEventListener("resize", updateDimensions), () => {
2526
+ clearTimeout(initialTimer), resizeObserver.disconnect(), window.removeEventListener("resize", updateDimensions);
2527
+ };
2528
+ }), [ isYouTube, videoRef, iframeRef ]);
2529
+ const handleContainerClick = useCallback((() => {
2530
+ containerRef.current && containerRef.current.focus();
2531
+ }), []);
2532
+ // Detect container border radius
2533
+ useEffect((() => {
2534
+ const detectBorderRadius = () => {
2535
+ if (!containerRef.current) return;
2536
+ const computedStyle = window.getComputedStyle(containerRef.current), borderRadius = computedStyle.borderRadius || computedStyle.borderTopLeftRadius, radiusValue = parseFloat(borderRadius);
2537
+ isNaN(radiusValue) || setContainerBorderRadius(radiusValue);
2538
+ };
2539
+ // Detect border radius immediately
2540
+ detectBorderRadius();
2541
+ // Create ResizeObserver to watch for style changes
2542
+ let resizeObserver = null;
2543
+ return "undefined" != typeof ResizeObserver && containerRef.current && (resizeObserver = new ResizeObserver(detectBorderRadius),
2544
+ resizeObserver.observe(containerRef.current)),
2545
+ // Also listen for window resize (in case styles change)
2546
+ window.addEventListener("resize", detectBorderRadius), () => {
2547
+ window.removeEventListener("resize", detectBorderRadius), resizeObserver && containerRef.current && (resizeObserver.unobserve(containerRef.current),
2548
+ resizeObserver.disconnect());
2549
+ };
2550
+ }), []);
2551
+ const handleKeyDown = useCallback((e => {
2552
+ switch (e.key) {
2553
+ case " ":
2554
+ case "k":
2555
+ e.preventDefault(), togglePlay();
2556
+ break;
2557
+
2558
+ case "ArrowLeft":
2559
+ e.preventDefault(), seek(currentTime - 10);
2560
+ break;
2561
+
2562
+ case "ArrowRight":
2563
+ e.preventDefault(), seek(currentTime + 10);
2564
+ break;
2565
+
2566
+ case "ArrowUp":
2567
+ e.preventDefault(), setVolume(Math.min(1, volume + .1));
2568
+ break;
2569
+
2570
+ case "ArrowDown":
2571
+ e.preventDefault(), setVolume(Math.max(0, volume - .1));
2572
+ break;
2573
+
2574
+ case "m":
2575
+ e.preventDefault(), toggleMute();
2576
+ break;
2577
+
2578
+ case "f":
2579
+ e.preventDefault(), toggleFullscreen();
2580
+ }
2581
+ }), [ togglePlay, currentTime, seek, volume, setVolume, toggleMute, toggleFullscreen ]);
2582
+ return jsxs("div", {
2583
+ ref: containerRef,
2584
+ className: `${VIDEO_PLAYER_CLASSES_BASE} ${isYouTube ? VIDEO_PLAYER_CLASSES_YOUTUBE : ""} ${ambientMode ? VIDEO_PLAYER_CLASSES_AMBIENT : ""} ${glass ? VIDEO_PLAYER_CLASSES_GLASS : ""} ${className}`,
2585
+ style: {
2586
+ width: width,
2587
+ height: height,
2588
+ aspectRatio: aspectRatio ? aspectRatio.replace(":", "/") : void 0,
2589
+ ...style
2590
+ },
2591
+ tabIndex: 0,
2592
+ onClick: handleContainerClick,
2593
+ onKeyDown: handleKeyDown,
2594
+ role: "application",
2595
+ "aria-label": "Video player",
2596
+ ...props,
2597
+ children: [ ambientMode && jsx("canvas", {
2598
+ ref: canvasRef,
2599
+ className: VIDEO_PLAYER_CLASSES_AMBIENT_CANVAS,
2600
+ "aria-hidden": "true"
2601
+ }), isYouTube && videoId ? jsx("iframe", {
2602
+ ref: iframeRef,
2603
+ className: VIDEO_PLAYER_CLASSES_VIDEO,
2604
+ src: `https://www.youtube.com/embed/${videoId}?${new URLSearchParams({
2605
+ autoplay: autoplay ? "1" : "0",
2606
+ loop: loop ? "1" : "0",
2607
+ mute: muted ? "1" : "0",
2608
+ controls: controls ? "1" : "0",
2609
+ modestbranding: "1",
2610
+ rel: "0",
2611
+ ...loop && {
2612
+ playlist: videoId
2613
+ }
2614
+ }).toString()}`,
2615
+ title: "YouTube video player",
2616
+ frameBorder: "0",
2617
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
2618
+ allowFullScreen: !0
2619
+ }) : jsx("video", {
2620
+ ref: element => {
2621
+ videoRef && videoRef.current !== element && (videoRef.current = element), "function" == typeof ref ? ref(element) : ref && ref.current !== element && (ref.current = element);
2622
+ },
2623
+ className: VIDEO_PLAYER_CLASSES_VIDEO,
2624
+ src: src,
2625
+ poster: poster,
2626
+ autoPlay: autoplay,
2627
+ loop: loop,
2628
+ muted: muted,
2629
+ preload: preload,
2630
+ controls: !1,
2631
+ crossOrigin: "anonymous",
2632
+ children: subtitles && subtitles.map((subtitle => jsx("track", {
2633
+ kind: "subtitles",
2634
+ src: subtitle.src,
2635
+ srcLang: subtitle.srcLang,
2636
+ label: subtitle.label,
2637
+ default: subtitle.default
2638
+ }, subtitle.srcLang)))
2639
+ }), isLoading && jsx("div", {
2640
+ className: VIDEO_PLAYER_CLASSES_LOADING,
2641
+ children: jsx("div", {
2642
+ className: VIDEO_PLAYER_CLASSES_SPINNER
2643
+ })
2644
+ }), glass && jsx("div", {
2645
+ className: VIDEO_PLAYER_CLASSES_GLASS_OVERLAY,
2646
+ children: jsx(AtomixGlass, {
2647
+ ..."boolean" == typeof glass ? {} : glass,
2648
+ mouseContainer: containerRef,
2649
+ displacementScale: 100,
2650
+ blurAmount: 0,
2651
+ saturation: 100,
2652
+ elasticity: 0,
2653
+ children: !glassContent && jsx("div", {
2654
+ style: {
2655
+ width: videoDimensions.width > 0 ? `${videoDimensions.width}px` : "100%",
2656
+ height: videoDimensions.height > 0 ? `${videoDimensions.height}px` : "100%",
2657
+ display: "flex",
2658
+ alignItems: "center",
2659
+ justifyContent: "center",
2660
+ background: "transparent"
2661
+ }
2662
+ })
2663
+ })
2664
+ }), glass && glassContent && jsx("div", {
2665
+ className: VIDEO_PLAYER_CLASSES_GLASS_CONTENT,
2666
+ style: {
2667
+ display: "flex",
2668
+ alignItems: "center",
2669
+ justifyContent: "center"
2670
+ },
2671
+ children: glassContent
2672
+ }), controls && !isYouTube && jsxs("div", {
2673
+ className: `${VIDEO_PLAYER_CLASSES_CONTROLS} ${showControls ? VIDEO_PLAYER_CLASSES_CONTROLS_VISIBLE : ""}`,
2674
+ style: {
2675
+ zIndex: glass ? 3 : "auto"
2676
+ },
2677
+ children: [ jsx("div", {
2678
+ className: VIDEO_PLAYER_CLASSES_PROGRESS_CONTAINER,
2679
+ children: jsxs("div", {
2680
+ className: VIDEO_PLAYER_CLASSES_PROGRESS_BAR,
2681
+ onClick: handleProgressClick,
2682
+ children: [ jsx("div", {
2683
+ className: VIDEO_PLAYER_CLASSES_PROGRESS_BUFFERED,
2684
+ style: {
2685
+ width: `${getBufferedPercentage()}%`
2686
+ }
2687
+ }), jsx("div", {
2688
+ className: VIDEO_PLAYER_CLASSES_PROGRESS_PLAYED,
2689
+ style: {
2690
+ width: `${getProgressPercentage()}%`
2691
+ }
2692
+ }), jsx("div", {
2693
+ className: VIDEO_PLAYER_CLASSES_PROGRESS_THUMB,
2694
+ style: {
2695
+ left: `${getProgressPercentage()}%`
2696
+ }
2697
+ }) ]
2698
+ })
2699
+ }), jsxs("div", {
2700
+ className: VIDEO_PLAYER_CLASSES_CONTROLS_ROW,
2701
+ children: [ jsxs("div", {
2702
+ className: VIDEO_PLAYER_CLASSES_CONTROLS_LEFT,
2703
+ children: [ jsx("button", {
2704
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2705
+ onClick: togglePlay,
2706
+ "aria-label": isPlaying ? "Pause" : "Play",
2707
+ children: jsx(isPlaying ? Pause : Play, {
2708
+ size: 20
2709
+ })
2710
+ }), jsx("button", {
2711
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2712
+ onClick: () => seek(currentTime - 10),
2713
+ "aria-label": "Skip back 10 seconds",
2714
+ children: jsx(SkipBack, {
2715
+ size: 20
2716
+ })
2717
+ }), jsx("button", {
2718
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2719
+ onClick: () => seek(currentTime + 10),
2720
+ "aria-label": "Skip forward 10 seconds",
2721
+ children: jsx(SkipForward, {
2722
+ size: 20
2723
+ })
2724
+ }), jsxs("div", {
2725
+ className: VIDEO_PLAYER_CLASSES_VOLUME_CONTAINER,
2726
+ children: [ jsx("button", {
2727
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2728
+ onClick: toggleMute,
2729
+ "aria-label": isMuted ? "Unmute" : "Mute",
2730
+ children: jsx(isMuted || 0 === volume ? SpeakerX : SpeakerHigh, {
2731
+ size: 20
2732
+ })
2733
+ }), jsx("div", {
2734
+ className: VIDEO_PLAYER_CLASSES_VOLUME_SLIDER,
2735
+ children: jsx("div", {
2736
+ className: VIDEO_PLAYER_CLASSES_VOLUME_BAR,
2737
+ onClick: handleVolumeClick,
2738
+ children: jsx("div", {
2739
+ className: VIDEO_PLAYER_CLASSES_VOLUME_FILL,
2740
+ style: {
2741
+ width: 100 * volume + "%"
2742
+ }
2743
+ })
2744
+ })
2745
+ }) ]
2746
+ }), jsxs("div", {
2747
+ className: VIDEO_PLAYER_CLASSES_TIME_DISPLAY,
2748
+ children: [ jsx("span", {
2749
+ children: formatTime(currentTime)
2750
+ }), jsx("span", {
2751
+ children: "/"
2752
+ }), jsx("span", {
2753
+ children: formatTime(duration)
2754
+ }) ]
2755
+ }) ]
2756
+ }), jsxs("div", {
2757
+ className: VIDEO_PLAYER_CLASSES_CONTROLS_RIGHT,
2758
+ children: [ showSettings && jsxs("div", {
2759
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_CONTAINER,
2760
+ children: [ jsx("button", {
2761
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2762
+ onClick: () => setShowSettingsMenu(!showSettingsMenu),
2763
+ "aria-label": "Settings",
2764
+ children: jsx(Gear, {
2765
+ size: 20
2766
+ })
2767
+ }), showSettingsMenu && jsxs("div", {
2768
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_MENU,
2769
+ children: [ jsxs("div", {
2770
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_TABS,
2771
+ children: [ quality && quality.length > 1 && jsx("button", {
2772
+ className: `${VIDEO_PLAYER_CLASSES_SETTINGS_TAB} ${"quality" === activeSettingsTab ? VIDEO_PLAYER_CLASSES_SETTINGS_TAB_ACTIVE : ""}`,
2773
+ onClick: () => setActiveSettingsTab("quality"),
2774
+ children: "Quality"
2775
+ }), jsx("button", {
2776
+ className: `${VIDEO_PLAYER_CLASSES_SETTINGS_TAB} ${"speed" === activeSettingsTab ? VIDEO_PLAYER_CLASSES_SETTINGS_TAB_ACTIVE : ""}`,
2777
+ onClick: () => setActiveSettingsTab("speed"),
2778
+ children: "Speed"
2779
+ }), jsx("button", {
2780
+ className: `${VIDEO_PLAYER_CLASSES_SETTINGS_TAB} ${"subtitles" === activeSettingsTab ? VIDEO_PLAYER_CLASSES_SETTINGS_TAB_ACTIVE : ""}`,
2781
+ onClick: () => setActiveSettingsTab("subtitles"),
2782
+ children: "Subtitles"
2783
+ }) ]
2784
+ }), jsxs("div", {
2785
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_CONTENT,
2786
+ children: [ "quality" === activeSettingsTab && quality && jsx("div", {
2787
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_OPTIONS,
2788
+ children: quality.map((q => jsx("button", {
2789
+ className: `${VIDEO_PLAYER_CLASSES_SETTINGS_OPTION} ${currentQuality?.label === q.label ? VIDEO_PLAYER_CLASSES_SETTINGS_OPTION_ACTIVE : ""}`,
2790
+ onClick: () => setQuality(q),
2791
+ children: q.label
2792
+ }, q.label)))
2793
+ }), "speed" === activeSettingsTab && jsx("div", {
2794
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_OPTIONS,
2795
+ children: playbackRates.map((rate => jsxs("button", {
2796
+ className: `${VIDEO_PLAYER_CLASSES_SETTINGS_OPTION} ${playbackRate === rate ? VIDEO_PLAYER_CLASSES_SETTINGS_OPTION_ACTIVE : ""}`,
2797
+ onClick: () => setPlaybackRate(rate),
2798
+ children: [ rate, "x" ]
2799
+ }, rate)))
2800
+ }), "subtitles" === activeSettingsTab && jsx("div", {
2801
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_OPTIONS,
2802
+ children: subtitles && subtitles.length > 0 ? jsxs(Fragment, {
2803
+ children: [ jsx("button", {
2804
+ className: `${VIDEO_PLAYER_CLASSES_SETTINGS_OPTION} ${null === activeSubtitle ? VIDEO_PLAYER_CLASSES_SETTINGS_OPTION_ACTIVE : ""}`,
2805
+ onClick: () => setSubtitle(null),
2806
+ children: "Off"
2807
+ }), subtitles.map((subtitle => jsx("button", {
2808
+ className: `${VIDEO_PLAYER_CLASSES_SETTINGS_OPTION} ${activeSubtitle === subtitle.srcLang ? VIDEO_PLAYER_CLASSES_SETTINGS_OPTION_ACTIVE : ""}`,
2809
+ onClick: () => setSubtitle(subtitle.srcLang),
2810
+ children: subtitle.label
2811
+ }, subtitle.srcLang))) ]
2812
+ }) : jsx("div", {
2813
+ className: VIDEO_PLAYER_CLASSES_SETTINGS_OPTION,
2814
+ style: {
2815
+ opacity: .6,
2816
+ cursor: "default"
2817
+ },
2818
+ children: "No subtitles available"
2819
+ })
2820
+ }) ]
2821
+ }) ]
2822
+ }) ]
2823
+ }), showDownload && jsx("button", {
2824
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2825
+ onClick: handleDownload,
2826
+ "aria-label": "Download video",
2827
+ children: jsx(Download, {
2828
+ size: 20
2829
+ })
2830
+ }), showShare && jsx("button", {
2831
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2832
+ onClick: handleShare,
2833
+ "aria-label": "Share video",
2834
+ children: jsx(Share, {
2835
+ size: 20
2836
+ })
2837
+ }), jsx("button", {
2838
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2839
+ onClick: togglePictureInPicture,
2840
+ "aria-label": "Picture in Picture",
2841
+ children: jsx("svg", {
2842
+ width: "20",
2843
+ height: "20",
2844
+ viewBox: "0 0 24 24",
2845
+ fill: "currentColor",
2846
+ children: jsx("path", {
2847
+ d: "M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h18v14z"
2848
+ })
2849
+ })
2850
+ }), jsx("button", {
2851
+ className: VIDEO_PLAYER_CLASSES_CONTROL_BUTTON,
2852
+ onClick: toggleFullscreen,
2853
+ "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
2854
+ children: jsx(isFullscreen ? ArrowsIn : ArrowsOut, {
2855
+ size: 20
2856
+ })
2857
+ }) ]
2858
+ }) ]
2859
+ }) ]
2860
+ }) ]
2861
+ });
2862
+ }));
2863
+
2864
+ VideoPlayer.displayName = "VideoPlayer";
2865
+
2866
+ /**
2867
+ * MasonryGrid component for creating a responsive masonry layout.
2868
+ * Uses JavaScript to position items optimally based on available vertical space,
2869
+ * similar to how a mason fits stones in a wall.
2870
+ *
2871
+ * @example
2872
+ * ```tsx
2873
+ * <MasonryGrid xs={1} sm={2} md={3} lg={4}>
2874
+ * <MasonryGridItem>Item 1</MasonryGridItem>
2875
+ * <MasonryGridItem>Item 2</MasonryGridItem>
2876
+ * <MasonryGridItem>Item 3</MasonryGridItem>
2877
+ * </MasonryGrid>
2878
+ * ```
2879
+ */
2880
+ const MasonryGrid = forwardRef((({children: children, className: className = "", xs: xs = 1, sm: sm, md: md, lg: lg, xl: xl, xxl: xxl, gap: gap = 16, animate: animate = !0, imagesLoaded: imagesLoaded = !0, onLayoutComplete: onLayoutComplete, onImageLoad: onImageLoad, ...props}, ref) => {
2881
+ // === REFS & STATE ===
2882
+ const [columns, setColumns] = useState(xs), [positions, setPositions] = useState([]), [layoutComplete, setLayoutComplete] = useState(!1), [loadingImages, setLoadingImages] = useState(!1), containerRef = useRef(null), columnHeights = useRef([]), imagesLoadedCount = useRef(0), totalImagesCount = useRef(0), imageElements = useRef(new Map);
2883
+ useEffect((() => {
2884
+ setLoadingImages(!!imagesLoaded);
2885
+ }), [ columns, imagesLoaded ]),
2886
+ // Forward ref for parent components
2887
+ useImperativeHandle(ref, (() => containerRef.current));
2888
+ // === HANDLE RESPONSIVE COLUMNS ===
2889
+ const getResponsiveColumns = useCallback((() => {
2890
+ const width = window.innerWidth;
2891
+ return width >= 1400 && void 0 !== xxl ? xxl : width >= 1200 && void 0 !== xl ? xl : width >= 992 && void 0 !== lg ? lg : width >= 768 && void 0 !== md ? md : width >= 576 && void 0 !== sm ? sm : xs;
2892
+ }), [ xs, sm, md, lg, xl, xxl ]);
2893
+ useEffect((() => {
2894
+ const handleResize = () => setColumns(getResponsiveColumns());
2895
+ return handleResize(), // Set on mount
2896
+ window.addEventListener("resize", handleResize), () => window.removeEventListener("resize", handleResize);
2897
+ }), [ getResponsiveColumns ]);
2898
+ // === PREPARE ITEMS WITH REFS ===
2899
+ const [items, setItems] = useState([]);
2900
+ useEffect((() => {
2901
+ const newItems = [];
2902
+ Children.forEach(children, ((child, index) => {
2903
+ isValidElement(child) && newItems.push({
2904
+ id: child.key?.toString() || `masonry-item-${index}`,
2905
+ element: child,
2906
+ position: null,
2907
+ ref: React.createRef()
2908
+ });
2909
+ })), setItems(newItems);
2910
+ }), [ children ]);
2911
+ // === TRACK & MANAGE IMAGES ===
2912
+ const handleImageLoad = useCallback((img => {
2913
+ if (!imageElements.current.get(img)) {
2914
+ // Add loaded class for animation
2915
+ if (imageElements.current.set(img, !0), imagesLoadedCount.current += 1, containerRef.current && imagesLoaded) {
2916
+ const itemElement = img.closest(".o-masonry-grid > div");
2917
+ itemElement && (itemElement.offsetHeight, itemElement.classList.add("o-masonry-grid__item-loaded"),
2918
+ itemElement.classList.remove("o-masonry-grid__item-loading"));
2919
+ }
2920
+ // Ensure layout is recalculated after DOM paints the item image (prevents overlap on slow/late image loads)
2921
+ requestAnimationFrame((() => {
2922
+ requestAnimationFrame((() => {
2923
+ calculateLayout();
2924
+ }));
2925
+ })), onImageLoad?.(imagesLoadedCount.current, totalImagesCount.current),
2926
+ // If all images have loaded, update loading state and complete layout
2927
+ imagesLoadedCount.current >= totalImagesCount.current && totalImagesCount.current > 0 && (setLayoutComplete(!0),
2928
+ setLoadingImages(!1), // This ensures the loading class is removed *immediately* after images load
2929
+ // Force a double requestAnimationFrame for final layout calculation after all images are loaded (guarantees DOM paint)
2930
+ requestAnimationFrame((() => {
2931
+ requestAnimationFrame((() => {
2932
+ calculateLayout(),
2933
+ // As a failsafe, if still present for some render lag, force another setLoadingImages(false)
2934
+ setLoadingImages(!1);
2935
+ }));
2936
+ })), onLayoutComplete?.());
2937
+ }
2938
+ }), [ onImageLoad, onLayoutComplete, imagesLoaded ]), trackImages = useCallback((() => {
2939
+ if (!imagesLoaded || !containerRef.current) return;
2940
+ imageElements.current.clear(), imagesLoadedCount.current = 0;
2941
+ const images = containerRef.current.querySelectorAll("img");
2942
+ return totalImagesCount.current = images.length, 0 === images.length ? (setLayoutComplete(!0),
2943
+ setLoadingImages(!1), void onLayoutComplete?.()) : (setLoadingImages(!0), images.forEach((img => {
2944
+ const masonryImg = img, itemElement = img.closest(".o-masonry-grid > div");
2945
+ if (itemElement && itemElement.classList.add("o-masonry-grid__item-loading"), img.complete) handleImageLoad(img); else {
2946
+ const loadHandler = () => handleImageLoad(img);
2947
+ img.addEventListener("load", loadHandler), img.addEventListener("error", loadHandler),
2948
+ masonryImg._masonryLoadHandler = loadHandler;
2949
+ }
2950
+ })), () => {
2951
+ images.forEach((img => {
2952
+ const masonryImg = img;
2953
+ masonryImg._masonryLoadHandler && (img.removeEventListener("load", masonryImg._masonryLoadHandler),
2954
+ img.removeEventListener("error", masonryImg._masonryLoadHandler), delete masonryImg._masonryLoadHandler);
2955
+ }));
2956
+ });
2957
+ }), [ imagesLoaded, handleImageLoad, onLayoutComplete ]), calculateLayout = useCallback((() => {
2958
+ if (!containerRef.current || 0 === items.length) return;
2959
+ const colWidth = (containerRef.current.offsetWidth - gap * (columns - 1)) / columns;
2960
+ columnHeights.current = Array(columns).fill(0);
2961
+ const newPositions = [];
2962
+ items.forEach(((item, index) => {
2963
+ if (item.ref.current) {
2964
+ // Find the shortest column
2965
+ const shortestCol = columnHeights.current.indexOf(Math.min(...columnHeights.current)), left = shortestCol * (colWidth + gap), top = columnHeights.current[shortestCol] ?? 0, height = item.ref.current.offsetHeight;
2966
+ columnHeights.current[shortestCol] = top + height + gap, newPositions[index] = {
2967
+ left: left,
2968
+ top: top,
2969
+ width: colWidth,
2970
+ height: height
2971
+ };
2972
+ }
2973
+ })), setPositions(newPositions);
2974
+ }), [ items, columns, gap ]);
2975
+ // === OBSERVE CONTAINER RESIZE ===
2976
+ useEffect((() => {
2977
+ if (!containerRef.current) return;
2978
+ let animationFrame = null;
2979
+ const observer = new ResizeObserver((() => {
2980
+ animationFrame && cancelAnimationFrame(animationFrame), animationFrame = requestAnimationFrame((() => calculateLayout()));
2981
+ }));
2982
+ return observer.observe(containerRef.current), () => {
2983
+ observer.disconnect(), animationFrame && cancelAnimationFrame(animationFrame);
2984
+ };
2985
+ }), [ calculateLayout ]),
2986
+ // === LAYOUT EFFECT (REPLACES setTimeout) ===
2987
+ React.useLayoutEffect((() => imagesLoaded ? trackImages() : (calculateLayout(),
2988
+ setLayoutComplete(!0), void setLoadingImages(!1))
2989
+ // Only reset layoutComplete when items or columns change
2990
+ ), [ items, columns, calculateLayout, imagesLoaded, trackImages ]),
2991
+ // === NEW: Add ResizeObservers to all grid items for bulletproof image+content measurement ===
2992
+ React.useEffect((() => {
2993
+ // Clean up old observers if items ever change
2994
+ const observers = [];
2995
+ return items.forEach((item => {
2996
+ if (item.ref.current) {
2997
+ const obs = new ResizeObserver((() => {
2998
+ // Double rAF: ensures layout only runs after DOM/paint/async renders
2999
+ requestAnimationFrame((() => {
3000
+ requestAnimationFrame((() => {
3001
+ calculateLayout();
3002
+ }));
3003
+ }));
3004
+ }));
3005
+ obs.observe(item.ref.current), observers.push(obs);
3006
+ }
3007
+ })), () => {
3008
+ observers.forEach((obs => obs.disconnect()));
3009
+ };
3010
+ }), [ items, calculateLayout ]);
3011
+ // Ensure loadingImages state resets when items/columns/imagesLoaded change
3012
+ // === DETERMINE CONTAINER HEIGHT ===
3013
+ const containerHeight = columnHeights.current.length > 0 ? Math.max(...columnHeights.current) : 0, classes = [ "o-masonry-grid", className, animate ? "o-masonry-grid--animate" : "", loadingImages ? "o-masonry-grid--loading-images" : "" ].filter(Boolean).join(" ");
3014
+ // === DETERMINE CLASSES ===
3015
+ // === RENDER ===
3016
+ return jsx("div", {
3017
+ ref: containerRef,
3018
+ className: classes,
3019
+ style: {
3020
+ position: "relative",
3021
+ width: "100%",
3022
+ height: `${containerHeight}px`,
3023
+ ...props.style
3024
+ },
3025
+ ...props,
3026
+ children: items.map(((item, index) => {
3027
+ const position = positions[index];
3028
+ return jsx("div", position ? {
3029
+ ref: item.ref,
3030
+ className: "o-masonry-grid__item",
3031
+ style: {
3032
+ position: "absolute",
3033
+ left: `${position.left}px`,
3034
+ top: `${position.top}px`,
3035
+ width: `${position.width}px`,
3036
+ opacity: 1
3037
+ },
3038
+ children: item.element
3039
+ } : {
3040
+ ref: item.ref,
3041
+ style: {
3042
+ opacity: 0,
3043
+ position: "absolute"
3044
+ },
3045
+ children: item.element
3046
+ }, item.id);
3047
+ }))
3048
+ });
3049
+ }));
3050
+
3051
+ MasonryGrid.displayName = "MasonryGrid", forwardRef((({children: children, className: className = "", ...props}, ref) => {
3052
+ const classes = [ "o-masonry-grid__item-inner" ];
3053
+ return className && classes.push(className), jsx("div", {
3054
+ ref: ref,
3055
+ className: classes.join(" "),
3056
+ ...props,
3057
+ children: children
3058
+ });
3059
+ })).displayName = "MasonryGridItem";
3060
+
3061
+ const Badge = memo((({label: label, variant: variant = "primary", size: size = "md", disabled: disabled = !1, icon: icon, className: className = "", glass: glass, style: style}) => {
3062
+ const {generateBadgeClass: generateBadgeClass} =
3063
+ /**
3064
+ * Badge state and functionality
3065
+ * @param initialProps - Initial badge properties
3066
+ * @returns Badge state and methods
3067
+ */
3068
+ function(initialProps) {
3069
+ // Default badge properties
3070
+ const defaultProps = {
3071
+ variant: "primary",
3072
+ size: "md",
3073
+ disabled: !1,
3074
+ ...initialProps
3075
+ };
3076
+ /**
3077
+ * Generate badge class based on properties
3078
+ * @param props - Badge properties
3079
+ * @returns Class string
3080
+ */ return {
3081
+ defaultProps: defaultProps,
3082
+ generateBadgeClass: props => {
3083
+ const {variant: variant = defaultProps.variant, size: size = defaultProps.size, disabled: disabled = defaultProps.disabled, className: className = ""} = props;
3084
+ return `c-badge ${variant ? `c-badge--${variant}` : ""} ${"md" === size ? "" : `c-badge--${size}`} ${disabled ? "c-badge--disabled" : ""} ${className}`.trim();
3085
+ }
3086
+ };
3087
+ }({
3088
+ variant: variant,
3089
+ size: size,
3090
+ disabled: disabled
3091
+ }), ref = useRef(null), badgeClass = generateBadgeClass({
3092
+ variant: variant,
3093
+ size: size,
3094
+ disabled: disabled,
3095
+ className: `${className} ${glass ? "c-badge--glass" : ""}`.trim()
3096
+ }), badgeElement = jsxs("span", {
3097
+ className: badgeClass,
3098
+ "aria-disabled": disabled,
3099
+ ref: ref,
3100
+ style: style,
3101
+ children: [ icon && jsx("span", {
3102
+ className: "c-badge__icon",
3103
+ children: icon
3104
+ }), jsx("span", {
3105
+ children: label
3106
+ }) ]
3107
+ });
3108
+ if (glass) {
3109
+ // Default glass settings for badges
3110
+ const defaultGlassProps = {
3111
+ displacementScale: 20,
3112
+ cornerRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : 16,
3113
+ className: "c-badge--glass",
3114
+ elasticity: 0
3115
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3116
+ ...defaultGlassProps,
3117
+ ...glass
3118
+ };
3119
+ return jsx(AtomixGlass, {
3120
+ ...glassProps,
3121
+ children: badgeElement
3122
+ });
3123
+ }
3124
+ return badgeElement;
3125
+ }));
3126
+
3127
+ Badge.displayName = "Badge";
3128
+
3129
+ const Spinner = memo((({size: size = "md", variant: variant = "primary", fullscreen: fullscreen = !1, className: className = "", style: style, glass: glass}) => {
3130
+ const {generateSpinnerClass: generateSpinnerClass} =
3131
+ /**
3132
+ * Spinner state and functionality
3133
+ * @param initialProps - Initial spinner properties
3134
+ * @returns Spinner state and methods
3135
+ */
3136
+ function(initialProps) {
3137
+ // Default spinner properties
3138
+ const defaultProps = {
3139
+ variant: "primary",
3140
+ size: "md",
3141
+ fullscreen: !1,
3142
+ ...initialProps
3143
+ };
3144
+ /**
3145
+ * Generate spinner class based on properties
3146
+ * @param props - Spinner properties
3147
+ * @returns Class string
3148
+ */ return {
3149
+ defaultProps: defaultProps,
3150
+ generateSpinnerClass: props => {
3151
+ const {variant: variant = defaultProps.variant, size: size = defaultProps.size, fullscreen: fullscreen = defaultProps.fullscreen, className: className = ""} = props;
3152
+ return `c-spinner ${variant ? `c-spinner--${variant}` : ""} ${"md" !== size ? `c-spinner--${size}` : ""} ${fullscreen ? "c-spinner--fullscreen" : ""} ${className}`.trim();
3153
+ }
3154
+ };
3155
+ }({
3156
+ size: size,
3157
+ variant: variant,
3158
+ fullscreen: fullscreen
3159
+ }), spinnerClass = generateSpinnerClass({
3160
+ size: size,
3161
+ variant: variant,
3162
+ fullscreen: fullscreen,
3163
+ className: `${className} ${glass ? "c-spinner--glass" : ""}`.trim()
3164
+ }), spinnerContent = jsx("div", {
3165
+ className: spinnerClass,
3166
+ style: style,
3167
+ role: "status",
3168
+ children: jsx("span", {
3169
+ className: "u-visually-hidden",
3170
+ children: "Loading..."
3171
+ })
3172
+ });
3173
+ if (glass) {
3174
+ const defaultGlassProps = {
3175
+ displacementScale: 20,
3176
+ blurAmount: 1,
3177
+ cornerRadius: 999,
3178
+ mode: "shader"
3179
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3180
+ ...defaultGlassProps,
3181
+ ...glass
3182
+ };
3183
+ return jsx(AtomixGlass, {
3184
+ ...glassProps,
3185
+ children: spinnerContent
3186
+ });
3187
+ }
3188
+ return spinnerContent;
3189
+ }));
3190
+
3191
+ Spinner.displayName = "Spinner";
3192
+
3193
+ // Map string sizes to pixel values
3194
+ const sizeMap = {
3195
+ xs: 16,
3196
+ sm: 20,
3197
+ md: 24,
3198
+ lg: 32,
3199
+ xl: 40
3200
+ }, Icon = ({name: name, size: size = "md", weight: weight = "regular", color: color, className: className = "", style: style, alt: alt}) => {
3201
+ // Get the icon component from Phosphor
3202
+ const IconComponent = PhosphorIcons[name];
3203
+ return IconComponent ? jsx("span", {
3204
+ className: `c-icon c-icon--${size} ${className}`,
3205
+ style: style,
3206
+ "aria-hidden": !alt,
3207
+ title: alt,
3208
+ children: jsx(IconComponent, {
3209
+ size: "string" == typeof size ? sizeMap[size] || 24 : size,
3210
+ weight: weight,
3211
+ color: color,
3212
+ "aria-label": alt
3213
+ })
3214
+ }) : (console.warn(`Icon "${name}" not found in Phosphor Icons`), null);
3215
+ // Convert string size to pixel value if needed
3216
+ };
3217
+
3218
+ /**
3219
+ * Icon component that displays a Phosphor icon
3220
+ */ Icon.displayName = "Icon";
3221
+
3222
+ const Button = React.memo( forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, ariaExpanded: ariaExpanded, ariaControls: ariaControls, tabIndex: tabIndex, style: style, LinkComponent: LinkComponent, ...props}, ref) => {
3223
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = useMemo((() => loading ? null : iconName ? jsx(Icon, {
3224
+ name: iconName,
3225
+ size: iconSize
3226
+ }) : icon), [ icon, iconName, iconSize, loading ]), {generateButtonClass: generateButtonClass, handleClick: handleClick} =
3227
+ /**
3228
+ * Button state and functionality
3229
+ * @param initialProps - Initial button properties
3230
+ * @returns Button state and methods
3231
+ */
3232
+ function(initialProps) {
3233
+ // Default button properties
3234
+ const defaultProps = {
3235
+ variant: "primary",
3236
+ size: "md",
3237
+ disabled: !1,
3238
+ rounded: !1,
3239
+ loading: !1,
3240
+ fullWidth: !1,
3241
+ block: !1,
3242
+ active: !1,
3243
+ selected: !1,
3244
+ ...initialProps
3245
+ };
3246
+ /**
3247
+ * Generate button class based on properties
3248
+ * @param props - Button properties
3249
+ * @returns Class string
3250
+ */ return {
3251
+ defaultProps: defaultProps,
3252
+ generateButtonClass: props => {
3253
+ const {variant: variant = defaultProps.variant, size: size = defaultProps.size, disabled: disabled = defaultProps.disabled, rounded: rounded = defaultProps.rounded, iconOnly: iconOnly = !1, glass: glass = defaultProps.glass, loading: loading = defaultProps.loading, fullWidth: fullWidth = defaultProps.fullWidth, block: block = defaultProps.block, active: active = defaultProps.active, selected: selected = defaultProps.selected, className: className = ""} = props, sizeClass = "md" === size ? "" : `c-btn--${size}`, iconOnlyClass = iconOnly ? "c-btn--icon" : "", roundedClass = rounded ? "c-btn--rounded" : "", disabledClass = disabled ? "c-btn--disabled" : "", glassClass = glass ? "c-btn--glass" : "", loadingClass = loading ? BUTTON.CLASSES.LOADING : "", fullWidthClass = fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", blockClass = block ? BUTTON.CLASSES.BLOCK : "", activeClass = active ? BUTTON.CLASSES.ACTIVE : "", selectedClass = selected ? BUTTON.CLASSES.SELECTED : "";
3254
+ return [ BUTTON.BASE_CLASS, `c-btn--${variant}`, sizeClass, iconOnlyClass, roundedClass, disabledClass, glassClass, loadingClass, fullWidthClass, blockClass, activeClass, selectedClass, className ].filter(Boolean).join(" ");
3255
+ },
3256
+ handleClick: handler => event => {
3257
+ defaultProps.disabled || defaultProps.loading || !handler || handler(event);
3258
+ }
3259
+ };
3260
+ }({
3261
+ variant: variant,
3262
+ size: size,
3263
+ disabled: isDisabled,
3264
+ rounded: rounded,
3265
+ glass: glass,
3266
+ loading: loading,
3267
+ fullWidth: fullWidth,
3268
+ block: block,
3269
+ active: active,
3270
+ selected: selected
3271
+ }), buttonClass = useMemo((() => generateButtonClass({
3272
+ variant: variant,
3273
+ size: size,
3274
+ disabled: isDisabled,
3275
+ rounded: rounded,
3276
+ iconOnly: iconOnly,
3277
+ glass: glass,
3278
+ loading: loading,
3279
+ fullWidth: fullWidth,
3280
+ block: block,
3281
+ active: active,
3282
+ selected: selected,
3283
+ className: className
3284
+ })), [ variant, size, isDisabled, rounded, iconOnly, glass, loading, fullWidth, block, active, selected, className, generateButtonClass ]), handleClickEvent = useCallback((event => {
3285
+ isDisabled ? event.preventDefault() : onClick?.(event);
3286
+ }), [ isDisabled, onClick ]), handleMouseEnter = useCallback((event => {
3287
+ isDisabled || onHover?.(event);
3288
+ }), [ isDisabled, onHover ]), handleFocusEvent = useCallback((event => {
3289
+ isDisabled || onFocus?.(event);
3290
+ }), [ isDisabled, onFocus ]), handleBlurEvent = useCallback((event => {
3291
+ isDisabled || onBlur?.(event);
3292
+ }), [ isDisabled, onBlur ]), buttonText = useMemo((() => loading && loadingText ? loadingText : label || children), [ loading, loadingText, label, children ]), spinnerSize = useMemo((() => "sm" === size ? "sm" : "lg" === size ? "md" : "sm"), [ size ]), buttonContent = useMemo((() => {
3293
+ const iconSpan = iconElement && jsx("span", {
3294
+ className: BUTTON.ICON_CLASS,
3295
+ "aria-hidden": "true",
3296
+ children: iconElement
3297
+ }), spinnerElement = loading && jsx("span", {
3298
+ className: BUTTON.SPINNER_CLASS,
3299
+ "aria-hidden": "true",
3300
+ children: jsx(Spinner, {
3301
+ size: spinnerSize,
3302
+ variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
3303
+ })
3304
+ }), labelElement = !iconOnly && buttonText && jsx("span", {
3305
+ className: BUTTON.LABEL_CLASS,
3306
+ children: buttonText
3307
+ });
3308
+ return jsxs(Fragment, "end" === iconPosition ? {
3309
+ children: [ labelElement, spinnerElement, iconSpan ]
3310
+ } : {
3311
+ children: [ spinnerElement, iconSpan, labelElement ]
3312
+ });
3313
+ }), [ iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant ]), buttonProps = useMemo((() => ({
3314
+ ref: ref,
3315
+ className: buttonClass,
3316
+ type: "button" !== Component || shouldRenderAsLink ? void 0 : type,
3317
+ onClick: handleClickEvent,
3318
+ onMouseEnter: onHover ? handleMouseEnter : void 0,
3319
+ onFocus: onFocus ? handleFocusEvent : void 0,
3320
+ onBlur: onBlur ? handleBlurEvent : void 0,
3321
+ disabled: isDisabled && "button" === Component && !shouldRenderAsLink,
3322
+ "aria-disabled": isDisabled,
3323
+ "aria-busy": loading,
3324
+ "aria-label": ariaLabel || (iconOnly ? label || children : void 0),
3325
+ "aria-describedby": ariaDescribedBy,
3326
+ "aria-expanded": ariaExpanded,
3327
+ "aria-controls": ariaControls,
3328
+ tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
3329
+ style: style,
3330
+ ...props
3331
+ })), [ ref, buttonClass, Component, type, handleClickEvent, handleMouseEnter, handleFocusEvent, handleBlurEvent, isDisabled, loading, ariaLabel, iconOnly, label, children, ariaDescribedBy, ariaExpanded, ariaControls, tabIndex, style, props ]);
3332
+ // Determine if we should render as a link
3333
+ // Render as anchor if href is provided
3334
+ if (shouldRenderAsLink) {
3335
+ const {ref: _, ...buttonPropsWithoutRef} = buttonProps, anchorButtonProps = {
3336
+ ...buttonPropsWithoutRef,
3337
+ type: void 0,
3338
+ disabled: void 0
3339
+ };
3340
+ // Use custom LinkComponent if provided (e.g., Next.js Link)
3341
+ if (LinkComponent) {
3342
+ const LinkComp = LinkComponent, linkProps = {
3343
+ ...anchorButtonProps,
3344
+ ref: ref,
3345
+ href: href,
3346
+ target: target,
3347
+ rel: "_blank" === target ? "noopener noreferrer" : void 0
3348
+ }, linkElement = jsx(LinkComp, {
3349
+ ...linkProps,
3350
+ children: buttonContent
3351
+ });
3352
+ if (glass) {
3353
+ const defaultGlassProps = {
3354
+ displacementScale: 20,
3355
+ blurAmount: 0,
3356
+ saturation: 200,
3357
+ elasticity: 0
3358
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3359
+ ...defaultGlassProps,
3360
+ ...glass
3361
+ };
3362
+ return jsx(AtomixGlass, {
3363
+ ...glassProps,
3364
+ children: linkElement
3365
+ });
3366
+ }
3367
+ return linkElement;
3368
+ }
3369
+ // Fallback to regular anchor tag
3370
+ const anchorElement = jsx("a", {
3371
+ ...anchorButtonProps,
3372
+ ref: ref,
3373
+ href: href,
3374
+ target: target,
3375
+ rel: "_blank" === target ? "noopener noreferrer" : void 0,
3376
+ children: buttonContent
3377
+ });
3378
+ if (glass) {
3379
+ const defaultGlassProps = {
3380
+ displacementScale: 20,
3381
+ blurAmount: 0,
3382
+ saturation: 200,
3383
+ elasticity: 0
3384
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3385
+ ...defaultGlassProps,
3386
+ ...glass
3387
+ };
3388
+ return jsx(AtomixGlass, {
3389
+ ...glassProps,
3390
+ children: anchorElement
3391
+ });
3392
+ }
3393
+ return anchorElement;
3394
+ }
3395
+ // Default button rendering
3396
+ if (glass) {
3397
+ const defaultGlassProps = {
3398
+ displacementScale: 20,
3399
+ blurAmount: 0,
3400
+ saturation: 200,
3401
+ elasticity: 0
3402
+ }, glassProps = !0 === glass ? defaultGlassProps : {
3403
+ ...defaultGlassProps,
3404
+ ...glass
3405
+ };
3406
+ return jsx(AtomixGlass, {
3407
+ ...glassProps,
3408
+ children: jsx(Component, {
3409
+ ...buttonProps,
3410
+ children: buttonContent
3411
+ })
3412
+ });
3413
+ }
3414
+ return jsx(Component, {
3415
+ ...buttonProps,
3416
+ children: buttonContent
3417
+ });
3418
+ })));
3419
+
3420
+ Button.displayName = "Button";
3421
+
3422
+ /**
3423
+ * PhotoViewerHeader component - displays controls and counter for the photo viewer
3424
+ *
3425
+ * @param props - PhotoViewerHeaderProps
3426
+ * @returns JSX.Element
3427
+ */
3428
+ const PhotoViewerHeader = ({currentIndex: currentIndex, imagesLength: imagesLength, onZoomOut: onZoomOut, onResetZoom: onResetZoom, onZoomIn: onZoomIn, onToggleFullscreen: onToggleFullscreen, onClose: onClose, isFullscreen: isFullscreen, zoomLevel: zoomLevel, onRotate: onRotate, onDownload: onDownload, onShare: onShare, showInfo: showInfo, onToggleInfo: onToggleInfo, currentImage: currentImage}) => jsxs("div", {
3429
+ className: "c-photo-viewer__header",
3430
+ children: [ jsxs("div", {
3431
+ className: "c-photo-viewer__header-left",
3432
+ children: [ jsx(Badge, {
3433
+ label: `${currentIndex + 1} / ${imagesLength}`,
3434
+ variant: "primary",
3435
+ size: "sm"
3436
+ }), currentImage?.title && jsx("h3", {
3437
+ className: "c-photo-viewer__image-title",
3438
+ children: currentImage.title
3439
+ }) ]
3440
+ }), jsxs("div", {
3441
+ className: "c-photo-viewer__actions",
3442
+ children: [ jsx(Button, {
3443
+ iconOnly: !0,
3444
+ size: "sm",
3445
+ variant: "ghost",
3446
+ rounded: !0,
3447
+ onClick: onZoomOut,
3448
+ disabled: zoomLevel <= .1,
3449
+ "aria-label": "Zoom out",
3450
+ className: "c-photo-viewer__action-button",
3451
+ icon: jsx(Icon, {
3452
+ name: "Minus",
3453
+ size: "sm"
3454
+ })
3455
+ }), jsx(Button, {
3456
+ iconOnly: !0,
3457
+ size: "sm",
3458
+ variant: "ghost",
3459
+ rounded: !0,
3460
+ onClick: onResetZoom,
3461
+ disabled: 1 === zoomLevel,
3462
+ "aria-label": "Reset zoom",
3463
+ className: "c-photo-viewer__action-button",
3464
+ icon: jsx(Icon, {
3465
+ name: "MagnifyingGlass",
3466
+ size: "sm"
3467
+ })
3468
+ }), jsx(Button, {
3469
+ iconOnly: !0,
3470
+ size: "sm",
3471
+ variant: "ghost",
3472
+ rounded: !0,
3473
+ onClick: onZoomIn,
3474
+ disabled: zoomLevel >= 5,
3475
+ "aria-label": "Zoom in",
3476
+ className: "c-photo-viewer__action-button",
3477
+ icon: jsx(Icon, {
3478
+ name: "Plus",
3479
+ size: "sm"
3480
+ })
3481
+ }), jsx("div", {
3482
+ className: "c-photo-viewer__divider"
3483
+ }), jsx(Button, {
3484
+ iconOnly: !0,
3485
+ size: "sm",
3486
+ variant: "ghost",
3487
+ rounded: !0,
3488
+ onClick: onRotate,
3489
+ "aria-label": "Rotate image",
3490
+ className: "c-photo-viewer__action-button",
3491
+ icon: jsx(Icon, {
3492
+ name: "ArrowsClockwise",
3493
+ size: "sm"
3494
+ })
3495
+ }), jsx(Button, {
3496
+ iconOnly: !0,
3497
+ size: "sm",
3498
+ variant: "ghost",
3499
+ rounded: !0,
3500
+ onClick: onDownload,
3501
+ "aria-label": "Download image",
3502
+ className: "c-photo-viewer__action-button",
3503
+ icon: jsx(Icon, {
3504
+ name: "Download",
3505
+ size: "sm"
3506
+ })
3507
+ }), "share" in navigator && "function" == typeof navigator.share && jsx(Button, {
3508
+ iconOnly: !0,
3509
+ size: "sm",
3510
+ variant: "ghost",
3511
+ rounded: !0,
3512
+ onClick: onShare,
3513
+ "aria-label": "Share image",
3514
+ className: "c-photo-viewer__action-button",
3515
+ icon: jsx(Icon, {
3516
+ name: "Share",
3517
+ size: "sm"
3518
+ })
3519
+ }), jsx(Button, {
3520
+ iconOnly: !0,
3521
+ size: "sm",
3522
+ variant: "ghost",
3523
+ rounded: !0,
3524
+ onClick: onToggleInfo,
3525
+ "aria-label": "Toggle info panel",
3526
+ className: "c-photo-viewer__action-button " + (showInfo ? "is-active" : ""),
3527
+ icon: jsx(Icon, {
3528
+ name: "Info",
3529
+ size: "sm"
3530
+ })
3531
+ }), jsx("div", {
3532
+ className: "c-photo-viewer__divider"
3533
+ }), jsx(Button, {
3534
+ iconOnly: !0,
3535
+ size: "sm",
3536
+ variant: "ghost",
3537
+ rounded: !0,
3538
+ onClick: onToggleFullscreen,
3539
+ "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
3540
+ className: "c-photo-viewer__action-button",
3541
+ icon: jsx(Icon, {
3542
+ name: isFullscreen ? "ArrowsIn" : "ArrowsOut",
3543
+ size: "sm"
3544
+ })
3545
+ }), jsx(Button, {
3546
+ iconOnly: !0,
3547
+ size: "sm",
3548
+ variant: "ghost",
3549
+ rounded: !0,
3550
+ onClick: onClose,
3551
+ "aria-label": "Close viewer",
3552
+ className: "c-photo-viewer__action-button c-photo-viewer__close-button",
3553
+ icon: jsx(Icon, {
3554
+ name: "X",
3555
+ size: "sm"
3556
+ })
3557
+ }) ]
3558
+ }) ]
3559
+ })
3560
+ /**
3561
+ * PhotoViewerNavigation component - handles navigation between images
3562
+ *
3563
+ * @param props - PhotoViewerNavigationProps
3564
+ * @returns JSX.Element
3565
+ */ , PhotoViewerNavigation = ({show: show, onPrev: onPrev, onNext: onNext, currentIndex: currentIndex, imagesLength: imagesLength, enableKeyboardNav: enableKeyboardNav, onClose: onClose}) => (
3566
+ // Add keyboard navigation
3567
+ useEffect((() => {
3568
+ if (!enableKeyboardNav) return;
3569
+ const handleKeyDown = e => {
3570
+ "ArrowLeft" === e.key && onPrev(), "ArrowRight" === e.key && onNext(), "Escape" === e.key && onClose();
3571
+ };
3572
+ return window.addEventListener("keydown", handleKeyDown), () => window.removeEventListener("keydown", handleKeyDown);
3573
+ }), [ enableKeyboardNav, onPrev, onNext, onClose ]), show ? jsxs(Fragment, {
3574
+ children: [ jsx(Button, {
3575
+ iconOnly: !0,
3576
+ size: "md",
3577
+ variant: "ghost",
3578
+ rounded: !0,
3579
+ onClick: onPrev,
3580
+ disabled: 0 === currentIndex,
3581
+ "aria-label": "Previous image",
3582
+ className: "c-photo-viewer__nav-button c-photo-viewer__nav-button--prev",
3583
+ icon: jsx(Icon, {
3584
+ name: "CaretLeft",
3585
+ size: "md"
3586
+ })
3587
+ }), jsx(Button, {
3588
+ iconOnly: !0,
3589
+ size: "md",
3590
+ variant: "ghost",
3591
+ rounded: !0,
3592
+ onClick: onNext,
3593
+ disabled: currentIndex === imagesLength - 1,
3594
+ "aria-label": "Next image",
3595
+ className: "c-photo-viewer__nav-button c-photo-viewer__nav-button--next",
3596
+ icon: jsx(Icon, {
3597
+ name: "CaretRight",
3598
+ size: "md"
3599
+ })
3600
+ }) ]
3601
+ }) : null), PhotoViewerImage = ({imageRef: imageRef, containerRef: containerRef, src: src, alt: alt, zoomLevel: zoomLevel, dragPosition: dragPosition, isDragging: isDragging, rotationAngle: rotationAngle, isTransitioning: isTransitioning = !1, onMouseDown: onMouseDown, onMouseMove: onMouseMove, onMouseUp: onMouseUp, onWheel: onWheel, onTouchStart: onTouchStart, onTouchMove: onTouchMove, onTouchEnd: onTouchEnd, onDoubleClick: onDoubleClick}) => {
3602
+ const internalContainerRef = useRef(null), effectiveContainerRef = containerRef || internalContainerRef, [isMounted, setIsMounted] = useState(!1);
3603
+ // Track mounting state
3604
+ return useEffect((() => (setIsMounted(!0), () => setIsMounted(!1))), []),
3605
+ // Add non-passive event listeners to prevent page scrolling/zooming
3606
+ useEffect((() => {
3607
+ const container = effectiveContainerRef.current;
3608
+ if (!container) return;
3609
+ const handleWheelEvent = e => {
3610
+ // Only call if mounted and handler exists
3611
+ isMounted && container && onWheel && onWheel(e);
3612
+ }, handleTouchStartEvent = e => {
3613
+ // Only call if mounted and handler exists
3614
+ isMounted && container && onTouchStart && onTouchStart(e);
3615
+ }, handleTouchMoveEvent = e => {
3616
+ // Only call if mounted and handler exists
3617
+ isMounted && container && onTouchMove && onTouchMove(e);
3618
+ }, handleTouchEndEvent = e => {
3619
+ // Only call if mounted and handler exists
3620
+ isMounted && container && onTouchEnd && onTouchEnd(e);
3621
+ };
3622
+ // Clean up
3623
+ // Only add event listeners if mounted
3624
+ return isMounted && (container.addEventListener("wheel", handleWheelEvent, {
3625
+ passive: !1
3626
+ }), container.addEventListener("touchstart", handleTouchStartEvent, {
3627
+ passive: !1
3628
+ }), container.addEventListener("touchmove", handleTouchMoveEvent, {
3629
+ passive: !1
3630
+ }), container.addEventListener("touchend", handleTouchEndEvent, {
3631
+ passive: !1
3632
+ })), () => {
3633
+ container.removeEventListener("wheel", handleWheelEvent), container.removeEventListener("touchstart", handleTouchStartEvent),
3634
+ container.removeEventListener("touchmove", handleTouchMoveEvent), container.removeEventListener("touchend", handleTouchEndEvent);
3635
+ };
3636
+ }), [ isMounted, onWheel, onTouchStart, onTouchMove, onTouchEnd, effectiveContainerRef ]),
3637
+ jsx("div", {
3638
+ ref: effectiveContainerRef,
3639
+ className: "c-photo-viewer__image-container " + (isTransitioning ? "is-transitioning" : ""),
3640
+ style: {
3641
+ cursor: isDragging ? "grabbing" : zoomLevel > 1 ? "grab" : "default",
3642
+ opacity: isTransitioning ? .7 : 1,
3643
+ touchAction: "none"
3644
+ },
3645
+ onMouseDown: onMouseDown,
3646
+ onMouseMove: onMouseMove,
3647
+ onMouseUp: onMouseUp,
3648
+ onMouseLeave: onMouseUp,
3649
+ onDoubleClick: e => {
3650
+ isMounted && onDoubleClick && onDoubleClick(e);
3651
+ },
3652
+ children: jsx("img", {
3653
+ ref: imageRef,
3654
+ src: src,
3655
+ alt: alt,
3656
+ className: "c-photo-viewer__image",
3657
+ style: {
3658
+ transform: `scale(${zoomLevel}) translate(${dragPosition.x}px, ${dragPosition.y}px) rotate(${rotationAngle}deg)`,
3659
+ transition: isDragging ? "none" : isTransitioning ? "opacity 0.15s ease-out" : "transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)",
3660
+ transformOrigin: "center center",
3661
+ willChange: isDragging ? "transform" : "auto",
3662
+ touchAction: "none"
3663
+ },
3664
+ draggable: !1,
3665
+ onContextMenu: e => e.preventDefault()
3666
+ })
3667
+ });
3668
+ }, PhotoViewerThumbnails = ({images: images, currentIndex: currentIndex, goToImage: goToImage}) => images.length <= 1 ? null : jsx("div", {
3669
+ className: "c-photo-viewer__thumbnails",
3670
+ children: jsx("div", {
3671
+ className: "c-photo-viewer__thumbnails-container",
3672
+ children: images.map(((image, index) => {
3673
+ const thumbnailSrc = image.thumbnail || image.src, isActive = index === currentIndex;
3674
+ return jsx(Button, {
3675
+ variant: "ghost",
3676
+ className: "c-photo-viewer__thumbnail " + (isActive ? "is-active" : ""),
3677
+ onClick: () => goToImage(index),
3678
+ "aria-label": `View image ${index + 1}${image.title ? `: ${image.title}` : ""}`,
3679
+ "aria-current": isActive,
3680
+ children: jsxs("div", {
3681
+ className: "c-photo-viewer__thumbnail-wrapper",
3682
+ children: [ jsx("img", {
3683
+ loading: "lazy",
3684
+ src: thumbnailSrc,
3685
+ alt: image.alt || `Thumbnail ${index + 1}`,
3686
+ className: "c-photo-viewer__thumbnail-img"
3687
+ }), isActive && jsx("div", {
3688
+ className: "c-photo-viewer__thumbnail-indicator"
3689
+ }) ]
3690
+ })
3691
+ }, index);
3692
+ }))
3693
+ })
3694
+ }), PhotoViewerInfo = ({show: show, image: image, onClose: onClose}) => show && image ? jsxs("div", {
3695
+ className: "c-photo-viewer__info-panel",
3696
+ children: [ jsxs("div", {
3697
+ className: "c-photo-viewer__info-header",
3698
+ children: [ jsx("h4", {
3699
+ className: "c-photo-viewer__info-panel-title",
3700
+ children: "Image Details"
3701
+ }), jsx(Button, {
3702
+ iconOnly: !0,
3703
+ size: "sm",
3704
+ variant: "ghost",
3705
+ rounded: !0,
3706
+ onClick: onClose,
3707
+ "aria-label": "Close info panel",
3708
+ className: "c-photo-viewer__info-close",
3709
+ icon: jsx(Icon, {
3710
+ name: "X",
3711
+ size: "sm"
3712
+ })
3713
+ }) ]
3714
+ }), jsxs("div", {
3715
+ className: "c-photo-viewer__info-content",
3716
+ children: [ image.title && jsx("div", {
3717
+ className: "c-photo-viewer__info-section",
3718
+ children: jsx("h5", {
3719
+ className: "c-photo-viewer__info-title",
3720
+ children: image.title
3721
+ })
3722
+ }), image.description && jsx("div", {
3723
+ className: "c-photo-viewer__info-section",
3724
+ children: jsx("p", {
3725
+ className: "c-photo-viewer__info-description",
3726
+ children: image.description
3727
+ })
3728
+ }), (image.date || image.author) && jsx("div", {
3729
+ className: "c-photo-viewer__info-section",
3730
+ children: jsxs("div", {
3731
+ className: "c-photo-viewer__info-meta",
3732
+ children: [ image.date && jsxs("div", {
3733
+ className: "c-photo-viewer__info-meta-item",
3734
+ children: [ jsx(Icon, {
3735
+ name: "Calendar",
3736
+ size: 14
3737
+ }), jsx("span", {
3738
+ children: image.date
3739
+ }) ]
3740
+ }), image.author && jsxs("div", {
3741
+ className: "c-photo-viewer__info-meta-item",
3742
+ children: [ jsx(Icon, {
3743
+ name: "User",
3744
+ size: 14
3745
+ }), jsx("span", {
3746
+ children: image.author
3747
+ }) ]
3748
+ }) ]
3749
+ })
3750
+ }), image.tags && image.tags.length > 0 && jsxs("div", {
3751
+ className: "c-photo-viewer__info-section",
3752
+ children: [ jsx("h6", {
3753
+ className: "c-photo-viewer__info-section-title",
3754
+ children: "Tags"
3755
+ }), jsx("div", {
3756
+ className: "c-photo-viewer__info-tags",
3757
+ children: image.tags.map(((tag, index) => jsx(Badge, {
3758
+ label: tag,
3759
+ variant: "secondary",
3760
+ size: "sm"
3761
+ }, index)))
3762
+ }) ]
3763
+ }) ]
3764
+ }) ]
3765
+ }) : null, PhotoViewer = ({images: images, startIndex: startIndex = 0, className: className = "", disabled: disabled = !1, enableKeyboardNavigation: enableKeyboardNavigation = !0, enableGestures: enableGestures = !0, enableFullscreen: enableFullscreen = !0, thumbnailPosition: thumbnailPosition = "bottom", onImageChange: onImageChange, onClose: onClose}) => {
3766
+ // Use the external composable hook with enhanced features
3767
+ const {currentIndex: currentIndex, zoomLevel: zoomLevel, imagePosition: dragPosition, isDragging: isDragging, isFullscreen: isFullscreen, rotationAngle: rotationAngle, showInfo: showInfo, imageRef: imageRef, containerRef: containerRef, isTransitioning: isTransitioning, setZoomLevel: setZoomLevel, setImagePosition: setDragPosition, setIsDragging: setIsDragging, setIsFullscreen: setIsFullscreen, setRotationAngle: setRotationAngle, setShowInfo: setShowInfo, closeModal: closeModal, goToPrevious: goToPrevious, goToNext: goToNext, setCurrentIndex: goToImage, handleMouseDown: handleMouseDown, handleMouseMove: handleMouseMove, handleMouseUp: handleMouseUp, handleWheel: handleWheel, handleTouchStart: handleTouchStart, handleTouchMove: handleTouchMove, handleTouchEnd: handleTouchEnd, handleDoubleClick: handleDoubleClick, resetImageState: resetImageState} = (({images: images, startIndex: startIndex = 0, enableGestures: enableGestures = !0, onImageChange: onImageChange, onClose: onClose}) => {
3768
+ const [currentIndex, setCurrentIndex] = useState(startIndex), [isModalOpen, setIsModalOpen] = useState(!1), [isDragging, setIsDragging] = useState(!1), [startDragPosition, setStartDragPosition] = useState({
3769
+ x: 0,
3770
+ y: 0
3771
+ }), [isFullscreen, setIsFullscreen] = useState(!1), [showInfo, setShowInfo] = useState(!1), [imageStates, setImageStates] = useState({}), [isTransitioning, setIsTransitioning] = useState(!1), [isMounted, setIsMounted] = useState(!1), [momentumZoom, setMomentumZoom] = useState({
3772
+ velocity: 0,
3773
+ timestamp: 0
3774
+ }), imageRef = useRef(null), containerRef = useRef(null), touchPointsRef = useRef([]), lastDistanceRef = useRef(null), lastMidpointRef = useRef(null), lastWheelTime = useRef(0), momentumTimeoutRef = useRef(null), calculateBounds = useCallback(((zoomLevel, rotation) => {
3775
+ if (!isMounted || !imageRef.current || !containerRef.current) return {
3776
+ minX: 0,
3777
+ maxX: 0,
3778
+ minY: 0,
3779
+ maxY: 0
3780
+ };
3781
+ const image = imageRef.current, container = containerRef.current;
3782
+ // Additional safety check for DOM readiness
3783
+ if (!image.naturalWidth && !image.width) return {
3784
+ minX: 0,
3785
+ maxX: 0,
3786
+ minY: 0,
3787
+ maxY: 0
3788
+ };
3789
+ // Get natural image dimensions
3790
+ const imageWidth = image.naturalWidth || image.width || 800, imageHeight = image.naturalHeight || image.height || 600;
3791
+ // Get container dimensions with null check
3792
+ try {
3793
+ const containerRect = container.getBoundingClientRect();
3794
+ if (!containerRect || 0 === containerRect.width || 0 === containerRect.height) return {
3795
+ minX: 0,
3796
+ maxX: 0,
3797
+ minY: 0,
3798
+ maxY: 0
3799
+ };
3800
+ const containerWidth = containerRect.width, containerHeight = containerRect.height, rotationRad = rotation * Math.PI / 180, cos = Math.abs(Math.cos(rotationRad)), sin = Math.abs(Math.sin(rotationRad)), aspectRatio = imageWidth / imageHeight;
3801
+ let displayWidth, displayHeight;
3802
+ containerWidth / containerHeight > aspectRatio ? (displayHeight = Math.min(.9 * containerHeight, imageHeight),
3803
+ displayWidth = displayHeight * aspectRatio) : (displayWidth = Math.min(.9 * containerWidth, imageWidth),
3804
+ displayHeight = displayWidth / aspectRatio);
3805
+ // Account for rotation in bounds calculation
3806
+ const scaledWidth = (displayWidth * cos + displayHeight * sin) * zoomLevel, scaledHeight = (displayWidth * sin + displayHeight * cos) * zoomLevel, maxX = Math.max(0, (scaledWidth - containerWidth) / 2), maxY = Math.max(0, (scaledHeight - containerHeight) / 2);
3807
+ return {
3808
+ minX: -maxX,
3809
+ maxX: maxX,
3810
+ minY: -maxY,
3811
+ maxY: maxY
3812
+ };
3813
+ } catch (error) {
3814
+ return console.warn("PhotoViewer: Error calculating bounds", error), {
3815
+ minX: 0,
3816
+ maxX: 0,
3817
+ minY: 0,
3818
+ maxY: 0
3819
+ };
3820
+ }
3821
+ }), [ isMounted ]), constrainPosition = useCallback(((position, bounds) => ({
3822
+ x: Math.max(bounds.minX, Math.min(bounds.maxX, position.x)),
3823
+ y: Math.max(bounds.minY, Math.min(bounds.maxY, position.y))
3824
+ })), []);
3825
+ // Mount tracking and ensure the current index is within bounds
3826
+ useEffect((() => (setIsMounted(!0), startIndex < 0 || startIndex >= images.length ? setCurrentIndex(0) : setCurrentIndex(startIndex),
3827
+ () => setIsMounted(!1))), [ images, startIndex ]),
3828
+ // Handle modal open/close body class
3829
+ useEffect((() => {
3830
+ isModalOpen ? document.body.classList.add("is-open-photoviewer") : document.body.classList.remove("is-open-photoviewer");
3831
+ }), [ isModalOpen ]),
3832
+ // Initialize state for current image when index changes
3833
+ useEffect((() => {
3834
+ isModalOpen && setImageStates((prev => prev[currentIndex] ? prev : {
3835
+ ...prev,
3836
+ [currentIndex]: {
3837
+ zoomLevel: 1,
3838
+ position: {
3839
+ x: 0,
3840
+ y: 0
3841
+ },
3842
+ rotation: 0,
3843
+ bounds: {
3844
+ minX: 0,
3845
+ maxX: 0,
3846
+ minY: 0,
3847
+ maxY: 0
3848
+ }
3849
+ }
3850
+ }));
3851
+ }), [ isModalOpen, currentIndex ]),
3852
+ // Call onImageChange callback when current index changes
3853
+ useEffect((() => {
3854
+ onImageChange && onImageChange(currentIndex);
3855
+ }), [ currentIndex, onImageChange ]),
3856
+ // Update bounds when image loads or dimensions change
3857
+ useEffect((() => {
3858
+ const image = imageRef.current, container = containerRef.current, updateImageBounds = () => {
3859
+ isMounted && image && container && setImageStates((prev => {
3860
+ const currentState = prev[currentIndex] || {
3861
+ zoomLevel: 1,
3862
+ position: {
3863
+ x: 0,
3864
+ y: 0
3865
+ },
3866
+ rotation: 0,
3867
+ bounds: {
3868
+ minX: 0,
3869
+ maxX: 0,
3870
+ minY: 0,
3871
+ maxY: 0
3872
+ }
3873
+ }, newBounds = calculateBounds(currentState.zoomLevel, currentState.rotation), constrainedPosition = constrainPosition(currentState.position, newBounds);
3874
+ return {
3875
+ ...prev,
3876
+ [currentIndex]: {
3877
+ ...currentState,
3878
+ bounds: newBounds,
3879
+ position: constrainedPosition
3880
+ }
3881
+ };
3882
+ }));
3883
+ };
3884
+ if (!(image && container && image.complete && isMounted)) return image && container && isMounted ? (image.addEventListener("load", updateImageBounds),
3885
+ () => image.removeEventListener("load", updateImageBounds)) : void 0;
3886
+ updateImageBounds();
3887
+ }), [ currentIndex, calculateBounds, constrainPosition, isMounted ]),
3888
+ // Handle window resize
3889
+ useEffect((() => {
3890
+ const handleResize = () => {
3891
+ isMounted && imageRef.current && containerRef.current && setImageStates((prev => {
3892
+ const currentState = prev[currentIndex] || {
3893
+ zoomLevel: 1,
3894
+ position: {
3895
+ x: 0,
3896
+ y: 0
3897
+ },
3898
+ rotation: 0,
3899
+ bounds: {
3900
+ minX: 0,
3901
+ maxX: 0,
3902
+ minY: 0,
3903
+ maxY: 0
3904
+ }
3905
+ }, newBounds = calculateBounds(currentState.zoomLevel, currentState.rotation), constrainedPosition = constrainPosition(currentState.position, newBounds);
3906
+ return {
3907
+ ...prev,
3908
+ [currentIndex]: {
3909
+ ...currentState,
3910
+ bounds: newBounds,
3911
+ position: constrainedPosition
3912
+ }
3913
+ };
3914
+ }));
3915
+ };
3916
+ return window.addEventListener("resize", handleResize), () => window.removeEventListener("resize", handleResize);
3917
+ }), [ currentIndex, calculateBounds, constrainPosition, isMounted ]);
3918
+ const openModal = useCallback((() => {
3919
+ setIsModalOpen(!0);
3920
+ }), []), closeModal = useCallback((() => {
3921
+ setIsModalOpen(!1), onClose && onClose();
3922
+ }), [ onClose ]), goToPrevious = useCallback((() => {
3923
+ currentIndex > 0 && (setIsTransitioning(!0), setTimeout((() => {
3924
+ setCurrentIndex((prev => prev - 1)), setIsTransitioning(!1);
3925
+ }), 150));
3926
+ }), [ currentIndex ]), goToNext = useCallback((() => {
3927
+ currentIndex < images.length - 1 && (setIsTransitioning(!0), setTimeout((() => {
3928
+ setCurrentIndex((prev => prev + 1)), setIsTransitioning(!1);
3929
+ }), 150));
3930
+ }), [ currentIndex, images.length ]), setZoomLevel = useCallback((zoom => {
3931
+ setImageStates((prev => {
3932
+ const currentState = prev[currentIndex] || {
3933
+ zoomLevel: 1,
3934
+ position: {
3935
+ x: 0,
3936
+ y: 0
3937
+ },
3938
+ rotation: 0,
3939
+ bounds: {
3940
+ minX: 0,
3941
+ maxX: 0,
3942
+ minY: 0,
3943
+ maxY: 0
3944
+ }
3945
+ }, newZoom = "function" == typeof zoom ? zoom(currentState.zoomLevel) : zoom, clampedZoom = Math.max(.1, Math.min(5, newZoom)), newBounds = calculateBounds(clampedZoom, currentState.rotation), constrainedPosition = constrainPosition(currentState.position, newBounds);
3946
+ return {
3947
+ ...prev,
3948
+ [currentIndex]: {
3949
+ ...currentState,
3950
+ zoomLevel: clampedZoom,
3951
+ bounds: newBounds,
3952
+ position: constrainedPosition
3953
+ }
3954
+ };
3955
+ }));
3956
+ }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), setImagePosition = useCallback((position => {
3957
+ setImageStates((prev => {
3958
+ const currentState = prev[currentIndex] || {
3959
+ zoomLevel: 1,
3960
+ position: {
3961
+ x: 0,
3962
+ y: 0
3963
+ },
3964
+ rotation: 0,
3965
+ bounds: {
3966
+ minX: 0,
3967
+ maxX: 0,
3968
+ minY: 0,
3969
+ maxY: 0
3970
+ }
3971
+ }, newPosition = "function" == typeof position ? position(currentState.position) : position, constrainedPosition = constrainPosition(newPosition, currentState.bounds);
3972
+ return {
3973
+ ...prev,
3974
+ [currentIndex]: {
3975
+ ...currentState,
3976
+ position: constrainedPosition
3977
+ }
3978
+ };
3979
+ }));
3980
+ }), [ currentIndex, constrainPosition ]), setRotationAngle = useCallback((rotation => {
3981
+ setImageStates((prev => {
3982
+ const currentState = prev[currentIndex] || {
3983
+ zoomLevel: 1,
3984
+ position: {
3985
+ x: 0,
3986
+ y: 0
3987
+ },
3988
+ rotation: 0,
3989
+ bounds: {
3990
+ minX: 0,
3991
+ maxX: 0,
3992
+ minY: 0,
3993
+ maxY: 0
3994
+ }
3995
+ }, normalizedRotation = (("function" == typeof rotation ? rotation(currentState.rotation) : rotation) % 360 + 360) % 360, newBounds = calculateBounds(currentState.zoomLevel, normalizedRotation), constrainedPosition = constrainPosition(currentState.position, newBounds);
3996
+ return {
3997
+ ...prev,
3998
+ [currentIndex]: {
3999
+ ...currentState,
4000
+ rotation: normalizedRotation,
4001
+ bounds: newBounds,
4002
+ position: constrainedPosition
4003
+ }
4004
+ };
4005
+ }));
4006
+ }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), handleWheel = useCallback((event => {
4007
+ var _context;
4008
+ if (!isMounted || !event || !event.currentTarget) return;
4009
+ // Additional safety check for the target element
4010
+ const target = event.currentTarget;
4011
+ if (target && "function" == typeof target.getBoundingClientRect) {
4012
+ // Storybook-specific safety check - ensure DOM is ready
4013
+ if ("undefined" != typeof window && (null == (_context = window.location?.href) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("storybook")) try {
4014
+ // Test if getBoundingClientRect works before proceeding
4015
+ const testRect = target.getBoundingClientRect();
4016
+ if (!testRect || 0 === testRect.width || 0 === testRect.height) return;
4017
+ } catch (e) {
4018
+ return;
4019
+ }
4020
+ setImageStates((prev => {
4021
+ const currentState = prev[currentIndex] || {
4022
+ zoomLevel: 1,
4023
+ position: {
4024
+ x: 0,
4025
+ y: 0
4026
+ },
4027
+ rotation: 0,
4028
+ bounds: {
4029
+ minX: 0,
4030
+ maxX: 0,
4031
+ minY: 0,
4032
+ maxY: 0
4033
+ }
4034
+ }, isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform), isTrackpadPinch = event.ctrlKey && isMac, hasHorizontalScroll = Math.abs(event.deltaX) > 0, isTrackpadScroll = !event.ctrlKey && hasHorizontalScroll && isMac, isMagicMouse = !event.ctrlKey && !hasHorizontalScroll && isMac, isRegularMouse = !isMac;
4035
+ // Advanced gesture detection for different input methods
4036
+ // Handle different input methods with appropriate sensitivity
4037
+ let zoomAmount, shouldPreventDefault = !1;
4038
+ if (isTrackpadPinch)
4039
+ // MacBook trackpad pinch zoom - natural, high sensitivity
4040
+ zoomAmount = -.02 * event.deltaY, shouldPreventDefault = !0; else if (isTrackpadScroll) {
4041
+ // MacBook trackpad scroll with two fingers
4042
+ if (!(currentState.zoomLevel > 1)) return prev;
4043
+ // Allow page scroll when not zoomed
4044
+ // Only zoom when already zoomed in, otherwise allow natural scroll
4045
+ zoomAmount = -.003 * event.deltaY, shouldPreventDefault = !0;
4046
+ } else isMagicMouse ? (
4047
+ // Apple Magic Mouse - less sensitive
4048
+ zoomAmount = -.004 * event.deltaY, shouldPreventDefault = !0) : isRegularMouse ? (
4049
+ // Regular mouse wheel - medium sensitivity
4050
+ zoomAmount = -.006 * event.deltaY, shouldPreventDefault = !0) : (
4051
+ // Fallback for other input methods
4052
+ zoomAmount = -.005 * event.deltaY, shouldPreventDefault = !0);
4053
+ shouldPreventDefault && (event.preventDefault(), event.stopPropagation());
4054
+ // Add momentum for trackpad gestures
4055
+ const currentTime = Date.now(), timeDelta = currentTime - lastWheelTime.current;
4056
+ // Calculate velocity for momentum (trackpad specific)
4057
+ if (lastWheelTime.current = currentTime, isTrackpadPinch && timeDelta < 100) {
4058
+ const velocity = Math.abs(zoomAmount) / timeDelta;
4059
+ setMomentumZoom({
4060
+ velocity: velocity,
4061
+ timestamp: currentTime
4062
+ }),
4063
+ // Clear any existing momentum timeout
4064
+ momentumTimeoutRef.current && clearTimeout(momentumTimeoutRef.current),
4065
+ // Apply momentum decay after gesture ends
4066
+ momentumTimeoutRef.current = setTimeout((() => {
4067
+ const applyMomentum = () => {
4068
+ setMomentumZoom((prev => {
4069
+ if (prev.velocity < .001) return prev;
4070
+ const newVelocity = .95 * prev.velocity, momentumZoomAmount = newVelocity * (zoomAmount > 0 ? 1 : -1);
4071
+ // Apply momentum zoom
4072
+ return setImageStates((current => {
4073
+ const state = current[currentIndex] || {
4074
+ zoomLevel: 1,
4075
+ position: {
4076
+ x: 0,
4077
+ y: 0
4078
+ },
4079
+ rotation: 0,
4080
+ bounds: {
4081
+ minX: 0,
4082
+ maxX: 0,
4083
+ minY: 0,
4084
+ maxY: 0
4085
+ }
4086
+ }, newZoom = Math.max(.1, Math.min(5, state.zoomLevel + momentumZoomAmount));
4087
+ if (newZoom === state.zoomLevel) return current;
4088
+ const newBounds = calculateBounds(newZoom, state.rotation), constrainedPosition = constrainPosition(state.position, newBounds);
4089
+ return {
4090
+ ...current,
4091
+ [currentIndex]: {
4092
+ ...state,
4093
+ zoomLevel: newZoom,
4094
+ bounds: newBounds,
4095
+ position: constrainedPosition
4096
+ }
4097
+ };
4098
+ })), newVelocity >= .001 && requestAnimationFrame(applyMomentum), {
4099
+ velocity: newVelocity,
4100
+ timestamp: Date.now()
4101
+ };
4102
+ }));
4103
+ };
4104
+ requestAnimationFrame(applyMomentum);
4105
+ }), 50);
4106
+ }
4107
+ // Safe getBoundingClientRect call with error handling
4108
+ let rect;
4109
+ try {
4110
+ rect = target.getBoundingClientRect();
4111
+ } catch (error) {
4112
+ return console.warn("PhotoViewer: Error getting bounding rect", error), prev;
4113
+ }
4114
+ if (!rect || 0 === rect.width || 0 === rect.height) return prev;
4115
+ const centerX = rect.width / 2, centerY = rect.height / 2, cursorX = event.clientX - rect.left - centerX, cursorY = event.clientY - rect.top - centerY, oldZoom = currentState.zoomLevel, newZoom = Math.max(.1, Math.min(5, oldZoom + zoomAmount));
4116
+ if (newZoom !== oldZoom) {
4117
+ const zoomFactor = newZoom / oldZoom, newBounds = calculateBounds(newZoom, currentState.rotation), newPosition = {
4118
+ x: currentState.position.x + cursorX * (1 - zoomFactor) * .5,
4119
+ y: currentState.position.y + cursorY * (1 - zoomFactor) * .5
4120
+ }, constrainedPosition = constrainPosition(newPosition, newBounds);
4121
+ return {
4122
+ ...prev,
4123
+ [currentIndex]: {
4124
+ ...currentState,
4125
+ zoomLevel: newZoom,
4126
+ bounds: newBounds,
4127
+ position: constrainedPosition
4128
+ }
4129
+ };
4130
+ }
4131
+ return prev;
4132
+ }));
4133
+ }
4134
+ }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), handleDoubleClick = useCallback((event => {
4135
+ if (!isMounted || !event || !event.currentTarget) return;
4136
+ const target = event.currentTarget;
4137
+ target && "function" == typeof target.getBoundingClientRect && setImageStates((prev => {
4138
+ const currentState = prev[currentIndex] || {
4139
+ zoomLevel: 1,
4140
+ position: {
4141
+ x: 0,
4142
+ y: 0
4143
+ },
4144
+ rotation: 0,
4145
+ bounds: {
4146
+ minX: 0,
4147
+ maxX: 0,
4148
+ minY: 0,
4149
+ maxY: 0
4150
+ }
4151
+ };
4152
+ let rect;
4153
+ try {
4154
+ rect = target.getBoundingClientRect();
4155
+ } catch (error) {
4156
+ return console.warn("PhotoViewer: Error getting bounding rect in double click", error),
4157
+ prev;
4158
+ }
4159
+ if (!rect || 0 === rect.width || 0 === rect.height) return prev;
4160
+ const centerX = rect.width / 2, centerY = rect.height / 2, cursorX = event.clientX - rect.left - centerX, cursorY = event.clientY - rect.top - centerY;
4161
+ let newZoom, newPosition = {
4162
+ x: 0,
4163
+ y: 0
4164
+ };
4165
+ currentState.zoomLevel < 1.5 ? (newZoom = 2,
4166
+ // Zoom towards cursor
4167
+ newPosition = {
4168
+ x: .5 * -cursorX,
4169
+ y: .5 * -cursorY
4170
+ }) : currentState.zoomLevel < 3 ? (newZoom = 4, newPosition = {
4171
+ x: .75 * -cursorX,
4172
+ y: .75 * -cursorY
4173
+ }) : (newZoom = 1, newPosition = {
4174
+ x: 0,
4175
+ y: 0
4176
+ });
4177
+ const newBounds = calculateBounds(newZoom, currentState.rotation), constrainedPosition = constrainPosition(newPosition, newBounds);
4178
+ return {
4179
+ ...prev,
4180
+ [currentIndex]: {
4181
+ ...currentState,
4182
+ zoomLevel: newZoom,
4183
+ bounds: newBounds,
4184
+ position: constrainedPosition
4185
+ }
4186
+ };
4187
+ }));
4188
+ }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), handleMouseDown = useCallback((event => {
4189
+ setImageStates((prev => {
4190
+ const currentState = prev[currentIndex] || {
4191
+ zoomLevel: 1,
4192
+ position: {
4193
+ x: 0,
4194
+ y: 0
4195
+ },
4196
+ rotation: 0,
4197
+ bounds: {
4198
+ minX: 0,
4199
+ maxX: 0,
4200
+ minY: 0,
4201
+ maxY: 0
4202
+ }
4203
+ };
4204
+ return currentState.zoomLevel > 1 && (event.preventDefault(), setIsDragging(!0),
4205
+ setStartDragPosition({
4206
+ x: event.clientX - currentState.position.x,
4207
+ y: event.clientY - currentState.position.y
4208
+ })), prev;
4209
+ }));
4210
+ }), [ currentIndex ]), handleMouseMove = useCallback((event => {
4211
+ isDragging && setImageStates((prev => {
4212
+ const currentState = prev[currentIndex] || {
4213
+ zoomLevel: 1,
4214
+ position: {
4215
+ x: 0,
4216
+ y: 0
4217
+ },
4218
+ rotation: 0,
4219
+ bounds: {
4220
+ minX: 0,
4221
+ maxX: 0,
4222
+ minY: 0,
4223
+ maxY: 0
4224
+ }
4225
+ }, dragSensitivity = Math.min(1, 1 / currentState.zoomLevel), deltaX = (event.clientX - startDragPosition.x) * dragSensitivity, deltaY = (event.clientY - startDragPosition.y) * dragSensitivity, constrainedPosition = constrainPosition({
4226
+ x: deltaX,
4227
+ y: deltaY
4228
+ }, currentState.bounds);
4229
+ // Apply scaling factor to reduce drag sensitivity
4230
+ return {
4231
+ ...prev,
4232
+ [currentIndex]: {
4233
+ ...currentState,
4234
+ position: constrainedPosition
4235
+ }
4236
+ };
4237
+ }));
4238
+ }), [ isDragging, startDragPosition, currentIndex, constrainPosition ]), handleMouseUp = useCallback((() => {
4239
+ setIsDragging(!1);
4240
+ }), []), handleTouchStart = useCallback((event => {
4241
+ if (!enableGestures) return;
4242
+ const touches = event.touches;
4243
+ // Always prevent default for multi-touch to stop page zoom
4244
+ touches.length > 1 && (event.preventDefault(), event.stopPropagation()),
4245
+ touchPointsRef.current = Array.from(touches).map((touch => ({
4246
+ x: touch.clientX,
4247
+ y: touch.clientY
4248
+ }))), setImageStates((prev => {
4249
+ const currentState = prev[currentIndex] || {
4250
+ zoomLevel: 1,
4251
+ position: {
4252
+ x: 0,
4253
+ y: 0
4254
+ },
4255
+ rotation: 0,
4256
+ bounds: {
4257
+ minX: 0,
4258
+ maxX: 0,
4259
+ minY: 0,
4260
+ maxY: 0
4261
+ }
4262
+ };
4263
+ if (1 === touches.length && currentState.zoomLevel > 1) {
4264
+ setIsDragging(!0);
4265
+ const touch = touches[0];
4266
+ touch && setStartDragPosition({
4267
+ x: touch.clientX - currentState.position.x,
4268
+ y: touch.clientY - currentState.position.y
4269
+ });
4270
+ } else if (2 === touches.length) {
4271
+ const touch1 = touches[0], touch2 = touches[1];
4272
+ if (touch1 && touch2) {
4273
+ const dx = touch1.clientX - touch2.clientX, dy = touch1.clientY - touch2.clientY;
4274
+ lastDistanceRef.current = Math.sqrt(dx * dx + dy * dy), lastMidpointRef.current = {
4275
+ x: (touch1.clientX + touch2.clientX) / 2,
4276
+ y: (touch1.clientY + touch2.clientY) / 2
4277
+ };
4278
+ }
4279
+ }
4280
+ return prev;
4281
+ }));
4282
+ }), [ enableGestures, currentIndex ]), handleTouchMove = useCallback((event => {
4283
+ if (!enableGestures) return;
4284
+ const touches = event.touches;
4285
+ // Always prevent default for multi-touch gestures to stop page zoom
4286
+ touches.length > 1 && (event.preventDefault(), event.stopPropagation()),
4287
+ setImageStates((prev => {
4288
+ const currentState = prev[currentIndex] || {
4289
+ zoomLevel: 1,
4290
+ position: {
4291
+ x: 0,
4292
+ y: 0
4293
+ },
4294
+ rotation: 0,
4295
+ bounds: {
4296
+ minX: 0,
4297
+ maxX: 0,
4298
+ minY: 0,
4299
+ maxY: 0
4300
+ }
4301
+ };
4302
+ // Prevent default for single touch when zoomed in to avoid conflicts
4303
+ currentState.zoomLevel > 1 && 1 === touches.length && event.preventDefault();
4304
+ let newPosition = null, zoomDelta = 0, currentMidpoint = null;
4305
+ if (1 === touches.length && isDragging && currentState.zoomLevel > 1) {
4306
+ const touch = touches[0];
4307
+ if (touch) {
4308
+ // Apply scaling factor to reduce touch drag sensitivity
4309
+ const dragSensitivity = Math.min(1, 1 / currentState.zoomLevel);
4310
+ newPosition = {
4311
+ x: (touch.clientX - startDragPosition.x) * dragSensitivity,
4312
+ y: (touch.clientY - startDragPosition.y) * dragSensitivity
4313
+ };
4314
+ }
4315
+ if (newPosition) {
4316
+ const constrainedPosition = constrainPosition(newPosition, currentState.bounds);
4317
+ return {
4318
+ ...prev,
4319
+ [currentIndex]: {
4320
+ ...currentState,
4321
+ position: constrainedPosition
4322
+ }
4323
+ };
4324
+ }
4325
+ } else if (2 === touches.length && null !== lastDistanceRef.current) {
4326
+ const touch1 = touches[0], touch2 = touches[1];
4327
+ if (touch1 && touch2) {
4328
+ const dx = touch1.clientX - touch2.clientX, dy = touch1.clientY - touch2.clientY, distance = Math.sqrt(dx * dx + dy * dy);
4329
+ zoomDelta = .005 * (distance - lastDistanceRef.current), lastDistanceRef.current = distance,
4330
+ currentMidpoint = {
4331
+ x: (touch1.clientX + touch2.clientX) / 2,
4332
+ y: (touch1.clientY + touch2.clientY) / 2
4333
+ };
4334
+ const oldZoom = currentState.zoomLevel, newZoom = Math.max(.1, Math.min(5, oldZoom + zoomDelta));
4335
+ if (newZoom !== oldZoom && lastMidpointRef.current && currentMidpoint) {
4336
+ let rect;
4337
+ try {
4338
+ rect = event.currentTarget.getBoundingClientRect();
4339
+ } catch (error) {
4340
+ return console.warn("PhotoViewer: Error getting bounding rect in touch move", error),
4341
+ prev;
4342
+ }
4343
+ if (!rect || 0 === rect.width || 0 === rect.height) return prev;
4344
+ const centerX = rect.width / 2, centerY = rect.height / 2, midpointX = currentMidpoint.x - rect.left - centerX, midpointY = currentMidpoint.y - rect.top - centerY, zoomFactor = newZoom / oldZoom, newBounds = calculateBounds(newZoom, currentState.rotation), newPosition = {
4345
+ x: currentState.position.x + midpointX * (1 - zoomFactor) * .5,
4346
+ y: currentState.position.y + midpointY * (1 - zoomFactor) * .5
4347
+ }, constrainedPosition = constrainPosition(newPosition, newBounds);
4348
+ return lastMidpointRef.current = currentMidpoint, {
4349
+ ...prev,
4350
+ [currentIndex]: {
4351
+ ...currentState,
4352
+ zoomLevel: newZoom,
4353
+ bounds: newBounds,
4354
+ position: constrainedPosition
4355
+ }
4356
+ };
4357
+ }
4358
+ currentMidpoint && (lastMidpointRef.current = currentMidpoint);
4359
+ }
4360
+ }
4361
+ return prev;
4362
+ }));
4363
+ }), [ isMounted, enableGestures, isDragging, startDragPosition, currentIndex, constrainPosition, calculateBounds ]), handleTouchEnd = useCallback((() => {
4364
+ setIsDragging(!1), lastDistanceRef.current = null, lastMidpointRef.current = null;
4365
+ }), []), currentState = imageStates[currentIndex] || {
4366
+ zoomLevel: 1,
4367
+ position: {
4368
+ x: 0,
4369
+ y: 0
4370
+ },
4371
+ rotation: 0,
4372
+ bounds: {
4373
+ minX: 0,
4374
+ maxX: 0,
4375
+ minY: 0,
4376
+ maxY: 0
4377
+ }
4378
+ };
4379
+ return {
4380
+ currentIndex: currentIndex,
4381
+ isModalOpen: isModalOpen,
4382
+ zoomLevel: currentState.zoomLevel,
4383
+ imagePosition: currentState.position,
4384
+ isDragging: isDragging,
4385
+ isFullscreen: isFullscreen,
4386
+ rotationAngle: currentState.rotation,
4387
+ showInfo: showInfo,
4388
+ imageRef: imageRef,
4389
+ containerRef: containerRef,
4390
+ isTransitioning: isTransitioning,
4391
+ setCurrentIndex: setCurrentIndex,
4392
+ setZoomLevel: setZoomLevel,
4393
+ setImagePosition: setImagePosition,
4394
+ setIsDragging: setIsDragging,
4395
+ setIsFullscreen: setIsFullscreen,
4396
+ setRotationAngle: setRotationAngle,
4397
+ setShowInfo: setShowInfo,
4398
+ openModal: openModal,
4399
+ closeModal: closeModal,
4400
+ goToPrevious: goToPrevious,
4401
+ goToNext: goToNext,
4402
+ handleWheel: handleWheel,
4403
+ handleMouseDown: handleMouseDown,
4404
+ handleMouseMove: handleMouseMove,
4405
+ handleMouseUp: handleMouseUp,
4406
+ handleTouchStart: handleTouchStart,
4407
+ handleTouchMove: handleTouchMove,
4408
+ handleTouchEnd: handleTouchEnd,
4409
+ handleDoubleClick: handleDoubleClick,
4410
+ resetImageState: () => {
4411
+ setImageStates((prev => ({
4412
+ ...prev,
4413
+ [currentIndex]: {
4414
+ zoomLevel: 1,
4415
+ position: {
4416
+ x: 0,
4417
+ y: 0
4418
+ },
4419
+ rotation: 0,
4420
+ bounds: {
4421
+ minX: 0,
4422
+ maxX: 0,
4423
+ minY: 0,
4424
+ maxY: 0
4425
+ }
4426
+ }
4427
+ })));
4428
+ }
4429
+ };
4430
+ })({
4431
+ images: images,
4432
+ startIndex: startIndex,
4433
+ enableGestures: enableGestures,
4434
+ onImageChange: onImageChange,
4435
+ onClose: onClose || (() => {})
4436
+ }), processedImages = useMemo((() => images.map((img => "string" == typeof img ? {
4437
+ src: img
4438
+ } : img))), [ images ]), currentImage = processedImages[currentIndex], photoViewerClasses = useMemo((() => [ "c-photo-viewer", `c-photo-viewer--thumbnails-${thumbnailPosition}`, isDragging ? "c-photo-viewer--dragging" : "", isFullscreen ? "c-photo-viewer--fullscreen" : "", showInfo ? "c-photo-viewer--info-open" : "", disabled ? "is-disabled" : "", className ].filter(Boolean).join(" ")), [ isDragging, isFullscreen, showInfo, disabled, thumbnailPosition, className ]);
4439
+ // Process images to handle both string arrays and object arrays, ensuring ImageType structure
4440
+ // Early return for empty images array
4441
+ // Listen for fullscreen changes
4442
+ return useEffect((() => {
4443
+ const handleFullscreenChange = () => {
4444
+ setIsFullscreen(!!document.fullscreenElement);
4445
+ };
4446
+ return document.addEventListener("fullscreenchange", handleFullscreenChange), () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
4447
+ }), [ setIsFullscreen ]),
4448
+ // Add/remove is-open-photoviewer class on body
4449
+ useEffect((() => (document.body.classList.add("is-open-photoviewer"), () => {
4450
+ document.body.classList.remove("is-open-photoviewer");
4451
+ })), []), images.length ? jsxs("div", {
4452
+ className: photoViewerClasses,
4453
+ role: "dialog",
4454
+ "aria-modal": "true",
4455
+ "aria-label": "Photo viewer",
4456
+ children: [ jsx("div", {
4457
+ className: "c-photo-viewer__backdrop",
4458
+ onClick: closeModal
4459
+ }), jsxs("div", {
4460
+ className: "c-photo-viewer__container",
4461
+ children: [ jsx(PhotoViewerHeader, {
4462
+ currentIndex: currentIndex,
4463
+ imagesLength: images.length,
4464
+ onZoomOut: () => setZoomLevel((z => Math.max(z - .25, .1))),
4465
+ onResetZoom: () => {
4466
+ resetImageState();
4467
+ },
4468
+ onZoomIn: () => setZoomLevel((z => Math.min(z + .25, 5))),
4469
+ onToggleFullscreen: () => {
4470
+ if (enableFullscreen) {
4471
+ if (isFullscreen) document.exitFullscreen && document.exitFullscreen(); else {
4472
+ const element = document.documentElement;
4473
+ element.requestFullscreen && element.requestFullscreen();
4474
+ }
4475
+ setIsFullscreen(!isFullscreen);
4476
+ }
4477
+ },
4478
+ onClose: onClose || closeModal,
4479
+ isFullscreen: isFullscreen,
4480
+ zoomLevel: zoomLevel,
4481
+ onRotate: () => {
4482
+ setRotationAngle((angle => (angle + 90) % 360));
4483
+ },
4484
+ onDownload: () => {
4485
+ if (!currentImage?.src) return;
4486
+ const link = document.createElement("a");
4487
+ link.href = currentImage.src;
4488
+ const sanitizedTitle = (currentImage.title || `image-${currentIndex + 1}`).replace(/[^a-zA-Z0-9.-]/g, "_");
4489
+ link.download = sanitizedTitle, document.body.appendChild(link), link.click(), document.body.removeChild(link);
4490
+ },
4491
+ onShare: async () => {
4492
+ if (navigator.share && currentImage?.src) try {
4493
+ await navigator.share({
4494
+ title: currentImage.title || "Shared Image",
4495
+ text: currentImage.description || "Check out this image",
4496
+ url: currentImage.src
4497
+ });
4498
+ } catch (error) {
4499
+ console.error("Error sharing:", error);
4500
+ }
4501
+ },
4502
+ showInfo: showInfo,
4503
+ onToggleInfo: () => setShowInfo(!showInfo),
4504
+ currentImage: currentImage
4505
+ }), jsxs("div", {
4506
+ className: "c-photo-viewer__content",
4507
+ children: [ jsx(PhotoViewerNavigation, {
4508
+ show: images.length > 1,
4509
+ onPrev: goToPrevious,
4510
+ onNext: goToNext,
4511
+ currentIndex: currentIndex,
4512
+ imagesLength: images.length,
4513
+ enableKeyboardNav: enableKeyboardNavigation,
4514
+ onClose: onClose || closeModal
4515
+ }), currentImage?.src && jsx(PhotoViewerImage, {
4516
+ imageRef: imageRef,
4517
+ containerRef: containerRef,
4518
+ src: currentImage.src,
4519
+ alt: currentImage?.alt || `Image ${currentIndex + 1}`,
4520
+ zoomLevel: zoomLevel,
4521
+ dragPosition: dragPosition,
4522
+ isDragging: isDragging,
4523
+ rotationAngle: rotationAngle,
4524
+ isTransitioning: isTransitioning,
4525
+ onMouseDown: handleMouseDown,
4526
+ onMouseMove: handleMouseMove,
4527
+ onMouseUp: handleMouseUp,
4528
+ onWheel: handleWheel,
4529
+ onTouchStart: handleTouchStart,
4530
+ onTouchMove: handleTouchMove,
4531
+ onTouchEnd: handleTouchEnd,
4532
+ onDoubleClick: handleDoubleClick
4533
+ }) ]
4534
+ }), "none" !== thumbnailPosition && jsx(PhotoViewerThumbnails, {
4535
+ images: processedImages,
4536
+ currentIndex: currentIndex,
4537
+ goToImage: goToImage
4538
+ }), jsx(PhotoViewerInfo, {
4539
+ show: showInfo,
4540
+ image: currentImage,
4541
+ onClose: () => setShowInfo(!1)
4542
+ }) ]
4543
+ }) ]
4544
+ }) : null;
4545
+ };
4546
+
4547
+ PhotoViewer.displayName = "PhotoViewer";
4548
+
4549
+ export { AtomixGlass, MasonryGrid, PhotoViewer, VideoPlayer };
4550
+ //# sourceMappingURL=heavy.js.map