@shohojdhara/atomix 0.1.30 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/LICENSE +0 -0
  3. package/README.md +151 -39
  4. package/dist/atomix.css +13529 -0
  5. package/dist/atomix.min.css +15 -0
  6. package/dist/index.d.ts +6112 -1757
  7. package/dist/index.esm.js +16852 -8364
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +16892 -8369
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.min.js +1 -1
  12. package/dist/index.min.js.map +1 -1
  13. package/dist/themes/boomdevs.css +13241 -0
  14. package/dist/themes/boomdevs.min.css +353 -0
  15. package/dist/themes/esrar.css +15374 -0
  16. package/dist/themes/esrar.min.css +189 -0
  17. package/dist/themes/mashroom.css +28079 -0
  18. package/dist/themes/mashroom.min.css +403 -0
  19. package/dist/themes/shaj-default.css +14203 -0
  20. package/dist/themes/shaj-default.min.css +500 -0
  21. package/dist/themes/yabai.css +13711 -0
  22. package/dist/themes/yabai.min.css +189 -0
  23. package/package.json +126 -99
  24. package/src/components/Accordion/Accordion.stories.tsx +271 -0
  25. package/src/components/Accordion/Accordion.tsx +131 -0
  26. package/src/components/Accordion/index.ts +3 -0
  27. package/src/components/AtomixLogo/AtomixLogo.tsx +36 -0
  28. package/src/components/AtomixLogo/index.ts +3 -0
  29. package/src/components/AtomixLogo.tsx +40 -0
  30. package/src/components/Avatar/Avatar.stories.tsx +257 -0
  31. package/src/components/Avatar/Avatar.tsx +68 -0
  32. package/src/components/Avatar/AvatarGroup.tsx +73 -0
  33. package/src/components/Avatar/index.ts +3 -0
  34. package/src/components/Badge/Badge.stories.tsx +371 -0
  35. package/src/components/Badge/Badge.tsx +39 -0
  36. package/src/components/Badge/index.ts +3 -0
  37. package/src/components/Block/Block.stories.tsx +408 -0
  38. package/src/components/Block/Block.tsx +137 -0
  39. package/src/components/Block/index.ts +1 -0
  40. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +106 -0
  41. package/src/components/Breadcrumb/Breadcrumb.tsx +112 -0
  42. package/src/components/Breadcrumb/index.ts +3 -0
  43. package/src/components/Button/Button.stories.tsx +312 -0
  44. package/src/components/Button/Button.tsx +69 -0
  45. package/src/components/Button/index.ts +3 -0
  46. package/src/components/Callout/Callout.stories.tsx +588 -0
  47. package/src/components/Callout/Callout.tsx +78 -0
  48. package/src/components/Callout/index.ts +1 -0
  49. package/src/components/Card/Card.stories.tsx +105 -0
  50. package/src/components/Card/Card.tsx +69 -0
  51. package/src/components/Card/ElevationCard.tsx +47 -0
  52. package/src/components/Card/index.ts +15 -0
  53. package/src/components/Chart/AdvancedChart.tsx +624 -0
  54. package/src/components/Chart/AnimatedChart.tsx +206 -0
  55. package/src/components/Chart/AreaChart.tsx +27 -0
  56. package/src/components/Chart/BarChart.tsx +148 -0
  57. package/src/components/Chart/BubbleChart.tsx +411 -0
  58. package/src/components/Chart/CandlestickChart.tsx +765 -0
  59. package/src/components/Chart/Chart.stories.tsx +527 -0
  60. package/src/components/Chart/Chart.tsx +218 -0
  61. package/src/components/Chart/ChartRenderer.tsx +322 -0
  62. package/src/components/Chart/ChartToolbar.tsx +436 -0
  63. package/src/components/Chart/ChartTooltip.tsx +101 -0
  64. package/src/components/Chart/DonutChart.tsx +370 -0
  65. package/src/components/Chart/FunnelChart.tsx +393 -0
  66. package/src/components/Chart/GaugeChart.tsx +550 -0
  67. package/src/components/Chart/HeatmapChart.tsx +614 -0
  68. package/src/components/Chart/LineChart.tsx +172 -0
  69. package/src/components/Chart/LineChartNew.tsx +167 -0
  70. package/src/components/Chart/MultiAxisChart.tsx +498 -0
  71. package/src/components/Chart/PieChart.tsx +103 -0
  72. package/src/components/Chart/RadarChart.tsx +332 -0
  73. package/src/components/Chart/RealTimeChart.tsx +436 -0
  74. package/src/components/Chart/ScatterChart.tsx +152 -0
  75. package/src/components/Chart/TreemapChart.tsx +574 -0
  76. package/src/components/Chart/WaterfallChart.tsx +450 -0
  77. package/src/components/Chart/index.ts +119 -0
  78. package/src/components/Chart/types.ts +338 -0
  79. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +44 -0
  80. package/src/components/ColorModeToggle/ColorModeToggle.tsx +85 -0
  81. package/src/components/ColorModeToggle/index.ts +2 -0
  82. package/src/components/Countdown/Countdown.stories.tsx +46 -0
  83. package/src/components/Countdown/Countdown.tsx +90 -0
  84. package/src/components/Countdown/index.ts +2 -0
  85. package/src/components/DataTable/DataTable.stories.tsx +248 -0
  86. package/src/components/DataTable/DataTable.tsx +213 -0
  87. package/src/components/DataTable/index.ts +3 -0
  88. package/src/components/DatePicker/DatePicker.stories.tsx +364 -0
  89. package/src/components/DatePicker/DatePicker.tsx +504 -0
  90. package/src/components/DatePicker/index.ts +4 -0
  91. package/src/components/DatePicker/readme.md +106 -0
  92. package/src/components/DatePicker/types.ts +167 -0
  93. package/src/components/DatePicker/utils.ts +185 -0
  94. package/src/components/Dropdown/Dropdown.stories.tsx +358 -0
  95. package/src/components/Dropdown/Dropdown.tsx +352 -0
  96. package/src/components/Dropdown/index.ts +14 -0
  97. package/src/components/Dropdown/readme.md +151 -0
  98. package/src/components/EdgePanel/EdgePanel.stories.tsx +266 -0
  99. package/src/components/EdgePanel/EdgePanel.tsx +73 -0
  100. package/src/components/EdgePanel/index.ts +1 -0
  101. package/src/components/Form/Checkbox.stories.tsx +76 -0
  102. package/src/components/Form/Checkbox.tsx +69 -0
  103. package/src/components/Form/Form.stories.tsx +497 -0
  104. package/src/components/Form/Form.tsx +46 -0
  105. package/src/components/Form/FormGroup.stories.tsx +162 -0
  106. package/src/components/Form/FormGroup.tsx +53 -0
  107. package/src/components/Form/Input.stories.tsx +106 -0
  108. package/src/components/Form/Input.tsx +87 -0
  109. package/src/components/Form/Radio.stories.tsx +94 -0
  110. package/src/components/Form/Radio.tsx +65 -0
  111. package/src/components/Form/Select.stories.tsx +151 -0
  112. package/src/components/Form/Select.tsx +191 -0
  113. package/src/components/Form/Textarea.stories.tsx +123 -0
  114. package/src/components/Form/Textarea.tsx +78 -0
  115. package/src/components/Form/index.ts +7 -0
  116. package/src/components/Hero/Hero.stories.tsx +295 -0
  117. package/src/components/Hero/Hero.tsx +175 -0
  118. package/src/components/Hero/index.ts +6 -0
  119. package/src/components/Icon/Icon.tsx +87 -0
  120. package/src/components/Icon/index.ts +2 -0
  121. package/src/components/List/List.stories.tsx +122 -0
  122. package/src/components/List/List.tsx +35 -0
  123. package/src/components/List/ListGroup.tsx +35 -0
  124. package/src/components/List/index.ts +2 -0
  125. package/src/components/Messages/Messages.stories.tsx +160 -0
  126. package/src/components/Messages/Messages.tsx +172 -0
  127. package/src/components/Messages/index.ts +3 -0
  128. package/src/components/Modal/Modal.stories.tsx +284 -0
  129. package/src/components/Modal/Modal.tsx +198 -0
  130. package/src/components/Modal/README.md +169 -0
  131. package/src/components/Modal/index.ts +1 -0
  132. package/src/components/Navigation/Menu/MegaMenu.tsx +109 -0
  133. package/src/components/Navigation/Menu/Menu.stories.tsx +339 -0
  134. package/src/components/Navigation/Menu/Menu.tsx +111 -0
  135. package/src/components/Navigation/Nav/Nav.stories.tsx +456 -0
  136. package/src/components/Navigation/Nav/Nav.tsx +51 -0
  137. package/src/components/Navigation/Nav/NavDropdown.tsx +105 -0
  138. package/src/components/Navigation/Nav/NavItem.tsx +168 -0
  139. package/src/components/Navigation/Navbar/Navbar.stories.tsx +569 -0
  140. package/src/components/Navigation/Navbar/Navbar.tsx +150 -0
  141. package/src/components/Navigation/README.md +314 -0
  142. package/src/components/Navigation/SideMenu/SideMenu.README.md +494 -0
  143. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +609 -0
  144. package/src/components/Navigation/SideMenu/SideMenu.tsx +101 -0
  145. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +103 -0
  146. package/src/components/Navigation/SideMenu/SideMenuList.tsx +41 -0
  147. package/src/components/Navigation/index.ts +23 -0
  148. package/src/components/Pagination/Pagination.stories.tsx +188 -0
  149. package/src/components/Pagination/Pagination.tsx +162 -0
  150. package/src/components/Pagination/index.ts +1 -0
  151. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +397 -0
  152. package/src/components/PhotoViewer/PhotoViewer.tsx +246 -0
  153. package/src/components/PhotoViewer/PhotoViewerHeader.tsx +184 -0
  154. package/src/components/PhotoViewer/PhotoViewerImage.tsx +173 -0
  155. package/src/components/PhotoViewer/PhotoViewerInfo.tsx +91 -0
  156. package/src/components/PhotoViewer/PhotoViewerNavigation.tsx +85 -0
  157. package/src/components/PhotoViewer/PhotoViewerThumbnails.tsx +63 -0
  158. package/src/components/PhotoViewer/README.md +358 -0
  159. package/src/components/PhotoViewer/examples/ImageGallery.tsx +187 -0
  160. package/src/components/PhotoViewer/examples/SimpleGallery.tsx +73 -0
  161. package/src/components/PhotoViewer/examples/index.ts +2 -0
  162. package/src/components/PhotoViewer/index.ts +14 -0
  163. package/src/components/Popover/Popover.stories.tsx +143 -0
  164. package/src/components/Popover/Popover.tsx +137 -0
  165. package/src/components/Popover/index.ts +5 -0
  166. package/src/components/Popover/readme.md +120 -0
  167. package/src/components/ProductReview/ProductReview.stories.tsx +88 -0
  168. package/src/components/ProductReview/ProductReview.tsx +169 -0
  169. package/src/components/ProductReview/index.ts +3 -0
  170. package/src/components/Progress/Progress.stories.tsx +75 -0
  171. package/src/components/Progress/Progress.tsx +45 -0
  172. package/src/components/Progress/index.ts +1 -0
  173. package/src/components/Rating/Rating.stories.tsx +109 -0
  174. package/src/components/Rating/Rating.tsx +286 -0
  175. package/src/components/Rating/index.ts +6 -0
  176. package/src/components/River/River.stories.tsx +230 -0
  177. package/src/components/River/River.tsx +134 -0
  178. package/src/components/River/index.ts +2 -0
  179. package/src/components/SectionIntro/SectionIntro.stories.tsx +143 -0
  180. package/src/components/SectionIntro/SectionIntro.tsx +184 -0
  181. package/src/components/SectionIntro/index.ts +3 -0
  182. package/src/components/Slider/Slider.stories.tsx +241 -0
  183. package/src/components/Slider/Slider.tsx +225 -0
  184. package/src/components/Slider/index.ts +24 -0
  185. package/src/components/Spinner/Spinner.stories.tsx +65 -0
  186. package/src/components/Spinner/Spinner.tsx +36 -0
  187. package/src/components/Spinner/index.ts +2 -0
  188. package/src/components/Steps/Steps.stories.tsx +158 -0
  189. package/src/components/Steps/Steps.tsx +115 -0
  190. package/src/components/Steps/index.ts +3 -0
  191. package/src/components/Tab/Tab.stories.tsx +129 -0
  192. package/src/components/Tab/Tab.tsx +111 -0
  193. package/src/components/Tab/index.ts +2 -0
  194. package/src/components/Testimonial/Testimonial.stories.tsx +180 -0
  195. package/src/components/Testimonial/Testimonial.tsx +138 -0
  196. package/src/components/Testimonial/index.ts +3 -0
  197. package/src/components/Todo/Todo.stories.tsx +103 -0
  198. package/src/components/Todo/Todo.tsx +158 -0
  199. package/src/components/Todo/index.ts +1 -0
  200. package/src/components/Toggle/Toggle.stories.tsx +49 -0
  201. package/src/components/Toggle/Toggle.tsx +84 -0
  202. package/src/components/Toggle/index.ts +2 -0
  203. package/src/components/Tooltip/Tooltip.stories.tsx +115 -0
  204. package/src/components/Tooltip/Tooltip.tsx +150 -0
  205. package/src/components/Tooltip/index.ts +3 -0
  206. package/src/components/Upload/Upload.stories.tsx +220 -0
  207. package/src/components/Upload/Upload.tsx +354 -0
  208. package/src/components/Upload/index.ts +3 -0
  209. package/src/components/VideoPlayer/VideoPlayer.stories.tsx +484 -0
  210. package/src/components/VideoPlayer/VideoPlayer.tsx +574 -0
  211. package/src/components/VideoPlayer/index.ts +7 -0
  212. package/src/components/index.ts +111 -0
  213. package/src/layouts/Grid/Container.tsx +58 -0
  214. package/src/layouts/Grid/Grid.stories.tsx +861 -0
  215. package/src/layouts/Grid/Grid.tsx +68 -0
  216. package/src/layouts/Grid/GridCol.tsx +161 -0
  217. package/src/layouts/Grid/README.md +108 -0
  218. package/src/layouts/Grid/Row.tsx +70 -0
  219. package/src/layouts/Grid/index.ts +8 -0
  220. package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +387 -0
  221. package/src/layouts/MasonryGrid/MasonryGrid.tsx +408 -0
  222. package/src/layouts/MasonryGrid/MasonryGridItem.tsx +44 -0
  223. package/src/layouts/MasonryGrid/README.md +117 -0
  224. package/src/layouts/MasonryGrid/index.ts +4 -0
  225. package/src/layouts/index.ts +7 -0
  226. package/src/lib/README.md +89 -0
  227. package/src/lib/composables/index.ts +63 -0
  228. package/src/lib/composables/useAccordion.ts +129 -0
  229. package/src/lib/composables/useAmbientMode.ts +90 -0
  230. package/src/lib/composables/useBadge.ts +42 -0
  231. package/src/lib/composables/useBarChart.ts +365 -0
  232. package/src/lib/composables/useBlock.ts +56 -0
  233. package/src/lib/composables/useBreadcrumb.ts +81 -0
  234. package/src/lib/composables/useButton.ts +59 -0
  235. package/src/lib/composables/useCallout.ts +55 -0
  236. package/src/lib/composables/useCard.ts +155 -0
  237. package/src/lib/composables/useChart.ts +1082 -0
  238. package/src/lib/composables/useChartAnalytics.ts +505 -0
  239. package/src/lib/composables/useChartData.ts +38 -0
  240. package/src/lib/composables/useChartExport.ts +392 -0
  241. package/src/lib/composables/useChartInteraction.ts +34 -0
  242. package/src/lib/composables/useChartInteractions.ts +123 -0
  243. package/src/lib/composables/useChartPerformance.ts +323 -0
  244. package/src/lib/composables/useChartScale.ts +48 -0
  245. package/src/lib/composables/useChartToolbar.ts +532 -0
  246. package/src/lib/composables/useCheckbox.ts +70 -0
  247. package/src/lib/composables/useDataTable.ts +208 -0
  248. package/src/lib/composables/useDatePicker.ts +564 -0
  249. package/src/lib/composables/useDropdown.ts +272 -0
  250. package/src/lib/composables/useEdgePanel.ts +261 -0
  251. package/src/lib/composables/useForm.ts +62 -0
  252. package/src/lib/composables/useFormGroup.ts +51 -0
  253. package/src/lib/composables/useHero.ts +250 -0
  254. package/src/lib/composables/useInput.ts +58 -0
  255. package/src/lib/composables/useLineChart.ts +319 -0
  256. package/src/lib/composables/useMessages.ts +77 -0
  257. package/src/lib/composables/useModal.ts +110 -0
  258. package/src/lib/composables/useNavbar.ts +288 -0
  259. package/src/lib/composables/usePagination.ts +101 -0
  260. package/src/lib/composables/usePhotoViewer.ts +937 -0
  261. package/src/lib/composables/usePieChart.ts +362 -0
  262. package/src/lib/composables/usePopover.ts +354 -0
  263. package/src/lib/composables/useProgress.ts +74 -0
  264. package/src/lib/composables/useRadio.ts +47 -0
  265. package/src/lib/composables/useRating.ts +174 -0
  266. package/src/lib/composables/useRiver.ts +205 -0
  267. package/src/lib/composables/useSelect.ts +52 -0
  268. package/src/lib/composables/useSideMenu.ts +197 -0
  269. package/src/lib/composables/useSlider.ts +339 -0
  270. package/src/lib/composables/useSpinner.ts +42 -0
  271. package/src/lib/composables/useTextarea.ts +55 -0
  272. package/src/lib/composables/useTodo.ts +141 -0
  273. package/src/lib/composables/useVideoPlayer.ts +398 -0
  274. package/src/lib/constants/components.ts +1433 -0
  275. package/src/lib/constants/index.ts +4 -0
  276. package/src/lib/index.ts +11 -0
  277. package/src/lib/types/components.ts +4750 -0
  278. package/src/lib/types/index.ts +2 -0
  279. package/src/lib/utils/dom.ts +41 -0
  280. package/src/lib/utils/icons.ts +74 -0
  281. package/src/lib/utils/index.ts +55 -0
  282. package/src/lib/utils/useForkRef.test.tsx +64 -0
  283. package/src/lib/utils/useForkRef.ts +36 -0
  284. package/src/lib/utils.test.ts +14 -0
  285. package/src/styles/01-settings/_index.scss +2 -0
  286. package/src/styles/01-settings/_settings.accordion.scss +7 -5
  287. package/src/styles/01-settings/_settings.animations.scss +0 -0
  288. package/src/styles/01-settings/_settings.avatar-group.scss +6 -3
  289. package/src/styles/01-settings/_settings.avatar.scss +2 -2
  290. package/src/styles/01-settings/_settings.badge.scss +15 -9
  291. package/src/styles/01-settings/_settings.block.scss +11 -0
  292. package/src/styles/01-settings/_settings.border-radius.scss +12 -9
  293. package/src/styles/01-settings/_settings.border.scss +4 -1
  294. package/src/styles/01-settings/_settings.box-shadow.scss +1 -1
  295. package/src/styles/01-settings/_settings.breadcrumb.scss +9 -8
  296. package/src/styles/01-settings/_settings.breakpoints.scss +0 -0
  297. package/src/styles/01-settings/_settings.btn-group.scss +4 -1
  298. package/src/styles/01-settings/_settings.button.scss +19 -21
  299. package/src/styles/01-settings/_settings.callout.scss +42 -24
  300. package/src/styles/01-settings/_settings.card.scss +12 -10
  301. package/src/styles/01-settings/_settings.chart.scss +199 -0
  302. package/src/styles/01-settings/_settings.checkbox-group.scss +0 -0
  303. package/src/styles/01-settings/_settings.checkbox.scss +0 -0
  304. package/src/styles/01-settings/_settings.color-mode.scss +0 -0
  305. package/src/styles/01-settings/_settings.colors.scss +20 -0
  306. package/src/styles/01-settings/_settings.config.scss +1 -1
  307. package/src/styles/01-settings/_settings.countdown.scss +0 -0
  308. package/src/styles/01-settings/_settings.data-table.scss +0 -0
  309. package/src/styles/01-settings/_settings.datepicker.scss +0 -0
  310. package/src/styles/01-settings/_settings.dropdown.scss +0 -0
  311. package/src/styles/01-settings/_settings.edge-panel.scss +0 -0
  312. package/src/styles/01-settings/_settings.fonts.scss +1 -1
  313. package/src/styles/01-settings/_settings.form-group.scss +0 -0
  314. package/src/styles/01-settings/_settings.form.scss +0 -0
  315. package/src/styles/01-settings/_settings.grid.scss +3 -3
  316. package/src/styles/01-settings/_settings.hero.scss +1 -1
  317. package/src/styles/01-settings/_settings.input.scss +1 -1
  318. package/src/styles/01-settings/_settings.link.scss +0 -0
  319. package/src/styles/01-settings/_settings.list-group.scss +0 -0
  320. package/src/styles/01-settings/_settings.list.scss +0 -0
  321. package/src/styles/01-settings/_settings.maps.scss +43 -8
  322. package/src/styles/01-settings/_settings.masonry-grid.scss +0 -0
  323. package/src/styles/01-settings/_settings.menu.scss +0 -0
  324. package/src/styles/01-settings/_settings.messages.scss +0 -0
  325. package/src/styles/01-settings/_settings.modal.scss +1 -1
  326. package/src/styles/01-settings/_settings.nav.scss +0 -0
  327. package/src/styles/01-settings/_settings.navbar.scss +0 -0
  328. package/src/styles/01-settings/_settings.pagination.scss +0 -0
  329. package/src/styles/01-settings/_settings.photoviewer.scss +89 -23
  330. package/src/styles/01-settings/_settings.popover.scss +0 -0
  331. package/src/styles/01-settings/_settings.position.scss +0 -0
  332. package/src/styles/01-settings/_settings.progress.scss +0 -0
  333. package/src/styles/01-settings/_settings.rating.scss +0 -0
  334. package/src/styles/01-settings/_settings.river.scss +0 -0
  335. package/src/styles/01-settings/_settings.sectionintro.scss +0 -0
  336. package/src/styles/01-settings/_settings.select.scss +0 -0
  337. package/src/styles/01-settings/_settings.side-menu.scss +0 -0
  338. package/src/styles/01-settings/_settings.skeleton.scss +0 -0
  339. package/src/styles/01-settings/_settings.slider.scss +59 -0
  340. package/src/styles/01-settings/_settings.spacing.scss +11 -3
  341. package/src/styles/01-settings/_settings.spinner.scss +0 -0
  342. package/src/styles/01-settings/_settings.steps.scss +1 -1
  343. package/src/styles/01-settings/_settings.tabs.scss +4 -4
  344. package/src/styles/01-settings/_settings.testimonials.scss +0 -0
  345. package/src/styles/01-settings/_settings.todo.scss +0 -0
  346. package/src/styles/01-settings/_settings.toggle.scss +1 -1
  347. package/src/styles/01-settings/_settings.tooltip.scss +0 -0
  348. package/src/styles/01-settings/_settings.typography.scss +2 -0
  349. package/src/styles/01-settings/_settings.upload.scss +0 -0
  350. package/src/styles/01-settings/_settings.video-player.scss +64 -0
  351. package/src/styles/01-settings/_settings.z-layers.scss +0 -0
  352. package/src/styles/02-tools/_index.scss +1 -0
  353. package/src/styles/02-tools/_tools.animations.scss +82 -0
  354. package/src/styles/02-tools/_tools.border-radius.scss +0 -0
  355. package/src/styles/02-tools/_tools.breakpoints.scss +0 -0
  356. package/src/styles/02-tools/_tools.button.scss +5 -0
  357. package/src/styles/02-tools/_tools.clearfix.scss +0 -0
  358. package/src/styles/02-tools/_tools.color-functions.scss +0 -0
  359. package/src/styles/02-tools/_tools.color-mode.scss +1 -1
  360. package/src/styles/02-tools/_tools.component.scss +479 -0
  361. package/src/styles/02-tools/_tools.event.scss +0 -0
  362. package/src/styles/02-tools/_tools.grid.scss +0 -0
  363. package/src/styles/02-tools/_tools.hidden-visually.scss +0 -0
  364. package/src/styles/02-tools/_tools.hidden.scss +0 -0
  365. package/src/styles/02-tools/_tools.map-loop.scss +0 -0
  366. package/src/styles/02-tools/_tools.media-queries.scss +0 -0
  367. package/src/styles/02-tools/_tools.object-fit.scss +0 -0
  368. package/src/styles/02-tools/_tools.placeholder.scss +0 -0
  369. package/src/styles/02-tools/_tools.rem.scss +5 -1
  370. package/src/styles/02-tools/_tools.size.scss +0 -0
  371. package/src/styles/02-tools/_tools.spacing.scss +0 -0
  372. package/src/styles/02-tools/_tools.to-rgb.scss +0 -0
  373. package/src/styles/02-tools/_tools.transition.scss +0 -0
  374. package/src/styles/02-tools/_tools.utilities.scss +0 -0
  375. package/src/styles/02-tools/_tools.utility-api.scss +23 -2
  376. package/src/styles/03-generic/_generic.fonts.scss +0 -0
  377. package/src/styles/03-generic/_generic.reset.scss +0 -0
  378. package/src/styles/03-generic/_generic.root.scss +5 -1
  379. package/src/styles/03-generic/_generic.selection.scss +0 -0
  380. package/src/styles/03-generic/_index.scss +0 -0
  381. package/src/styles/04-elements/_elements.all.scss +0 -0
  382. package/src/styles/04-elements/_elements.body.scss +0 -0
  383. package/src/styles/04-elements/_elements.heading.scss +0 -0
  384. package/src/styles/04-elements/_elements.html.scss +0 -0
  385. package/src/styles/04-elements/_elements.links.scss +0 -0
  386. package/src/styles/04-elements/_index.scss +0 -0
  387. package/src/styles/05-objects/_index.scss +1 -0
  388. package/src/styles/05-objects/_objects.block.scss +122 -0
  389. package/src/styles/05-objects/_objects.container.scss +14 -10
  390. package/src/styles/05-objects/_objects.grid.scss +0 -0
  391. package/src/styles/05-objects/_objects.masonry-grid.scss +0 -0
  392. package/src/styles/06-components/_components.accordion.scss +3 -1
  393. package/src/styles/06-components/_components.avatar-group.scss +0 -0
  394. package/src/styles/06-components/_components.avatar.scss +0 -0
  395. package/src/styles/06-components/_components.badge.scss +9 -9
  396. package/src/styles/06-components/_components.breadcrumb.scss +0 -0
  397. package/src/styles/06-components/_components.btn-group.scss +0 -0
  398. package/src/styles/06-components/_components.button.scss +0 -0
  399. package/src/styles/06-components/_components.callout.scss +2 -1
  400. package/src/styles/06-components/_components.card.scss +0 -1
  401. package/src/styles/06-components/_components.chart.scss +2102 -0
  402. package/src/styles/06-components/_components.checkbox-group.scss +0 -0
  403. package/src/styles/06-components/_components.checkbox.scss +0 -0
  404. package/src/styles/06-components/_components.color-mode-toggle.scss +0 -0
  405. package/src/styles/06-components/_components.countdown.scss +0 -0
  406. package/src/styles/06-components/_components.data-table.scss +0 -0
  407. package/src/styles/06-components/_components.datepicker.scss +0 -0
  408. package/src/styles/06-components/_components.dropdown.scss +0 -0
  409. package/src/styles/06-components/_components.edge-panel.scss +0 -0
  410. package/src/styles/06-components/_components.form-group.scss +0 -0
  411. package/src/styles/06-components/_components.form.scss +0 -0
  412. package/src/styles/06-components/_components.hero.scss +1 -0
  413. package/src/styles/06-components/_components.icon.scss +2 -2
  414. package/src/styles/06-components/_components.image-gallery.scss +0 -0
  415. package/src/styles/06-components/_components.input.scss +0 -0
  416. package/src/styles/06-components/_components.list-group.scss +0 -0
  417. package/src/styles/06-components/_components.list.scss +0 -0
  418. package/src/styles/06-components/_components.menu.scss +0 -0
  419. package/src/styles/06-components/_components.messages.scss +0 -0
  420. package/src/styles/06-components/_components.modal.scss +3 -0
  421. package/src/styles/06-components/_components.nav.scss +0 -0
  422. package/src/styles/06-components/_components.navbar.scss +0 -0
  423. package/src/styles/06-components/_components.pagination.scss +0 -0
  424. package/src/styles/06-components/_components.photoviewer.scss +603 -545
  425. package/src/styles/06-components/_components.popover.scss +0 -0
  426. package/src/styles/06-components/_components.product-review.scss +0 -0
  427. package/src/styles/06-components/_components.progress.scss +0 -0
  428. package/src/styles/06-components/_components.rating.scss +0 -0
  429. package/src/styles/06-components/_components.river.scss +0 -0
  430. package/src/styles/06-components/_components.sectionintro.scss +0 -0
  431. package/src/styles/06-components/_components.select.scss +0 -0
  432. package/src/styles/06-components/_components.side-menu.scss +0 -0
  433. package/src/styles/06-components/_components.skeleton.scss +0 -0
  434. package/src/styles/06-components/_components.slider.scss +273 -0
  435. package/src/styles/06-components/_components.spinner.scss +0 -0
  436. package/src/styles/06-components/_components.steps.scss +1 -0
  437. package/src/styles/06-components/_components.tabs.scss +0 -0
  438. package/src/styles/06-components/_components.testimonials.scss +0 -0
  439. package/src/styles/06-components/_components.todo.scss +0 -0
  440. package/src/styles/06-components/_components.toggle.scss +0 -0
  441. package/src/styles/06-components/_components.tooltip.scss +4 -9
  442. package/src/styles/06-components/_components.upload.scss +0 -0
  443. package/src/styles/06-components/_components.video-player.scss +623 -0
  444. package/src/styles/06-components/_index.scss +3 -0
  445. package/src/styles/06-components/old.chart.styles.scss +2819 -0
  446. package/src/styles/99-utilities/_index.scss +0 -0
  447. package/src/styles/99-utilities/_utilities.background.scss +0 -0
  448. package/src/styles/99-utilities/_utilities.border.scss +0 -0
  449. package/src/styles/99-utilities/_utilities.clearfix.scss +0 -0
  450. package/src/styles/99-utilities/_utilities.display.scss +0 -0
  451. package/src/styles/99-utilities/_utilities.flex.scss +0 -0
  452. package/src/styles/99-utilities/_utilities.link.scss +0 -0
  453. package/src/styles/99-utilities/_utilities.object-fit.scss +0 -0
  454. package/src/styles/99-utilities/_utilities.opacity.scss +0 -0
  455. package/src/styles/99-utilities/_utilities.overflow.scss +0 -0
  456. package/src/styles/99-utilities/_utilities.position.scss +0 -0
  457. package/src/styles/99-utilities/_utilities.scss +2 -1
  458. package/src/styles/99-utilities/_utilities.shadow.scss +0 -0
  459. package/src/styles/99-utilities/_utilities.sizes.scss +0 -0
  460. package/src/styles/99-utilities/_utilities.spacing.scss +0 -0
  461. package/src/styles/99-utilities/_utilities.text.scss +5 -0
  462. package/src/styles/99-utilities/_utilities.visibility.scss +0 -0
  463. package/src/styles/99-utilities/_utilities.visually-hidden.scss +0 -0
  464. package/src/styles/99-utilities/_utilities.z-index.scss +0 -0
  465. package/src/styles/css-modules.d.ts +0 -0
  466. package/src/styles/index.scss +0 -0
  467. package/dist/index.css +0 -15
  468. package/dist/index.esm.css +0 -15
  469. package/dist/index.min.css +0 -15
@@ -0,0 +1,937 @@
1
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
2
+
3
+ interface UsePhotoViewerProps {
4
+ images: (string | { src: string; [key: string]: any })[];
5
+ startIndex?: number;
6
+ enableGestures?: boolean;
7
+ onImageChange?: (index: number) => void;
8
+ onClose?: () => void;
9
+ }
10
+
11
+ interface ImageState {
12
+ zoomLevel: number;
13
+ position: { x: number; y: number };
14
+ rotation: number;
15
+ bounds: {
16
+ minX: number;
17
+ maxX: number;
18
+ minY: number;
19
+ maxY: number;
20
+ };
21
+ }
22
+
23
+ export const usePhotoViewer = ({
24
+ images,
25
+ startIndex = 0,
26
+ enableGestures = true,
27
+ onImageChange,
28
+ onClose,
29
+ }: UsePhotoViewerProps) => {
30
+ const [currentIndex, setCurrentIndex] = useState(startIndex);
31
+ const [isModalOpen, setIsModalOpen] = useState(false);
32
+ const [isDragging, setIsDragging] = useState(false);
33
+ const [startDragPosition, setStartDragPosition] = useState({ x: 0, y: 0 });
34
+ const [isFullscreen, setIsFullscreen] = useState(false);
35
+ const [showInfo, setShowInfo] = useState(false);
36
+ const [imageStates, setImageStates] = useState<Record<number, ImageState>>({});
37
+ const [isTransitioning, setIsTransitioning] = useState(false);
38
+ const [isMounted, setIsMounted] = useState(false);
39
+ const [momentumZoom, setMomentumZoom] = useState({ velocity: 0, timestamp: 0 });
40
+
41
+ // Ref for the image element
42
+ const imageRef = useRef<HTMLImageElement>(null);
43
+ const containerRef = useRef<HTMLDivElement>(null);
44
+
45
+ // Track touch points for pinch zoom
46
+ const touchPointsRef = useRef<{ x: number; y: number }[]>([]);
47
+ const lastDistanceRef = useRef<number | null>(null);
48
+ const lastMidpointRef = useRef<{ x: number; y: number } | null>(null);
49
+ const lastWheelTime = useRef<number>(0);
50
+ const momentumTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
51
+
52
+ // Calculate dragging bounds based on zoom level and image dimensions
53
+ const calculateBounds = useCallback(
54
+ (zoomLevel: number, rotation: number) => {
55
+ if (!isMounted || !imageRef.current || !containerRef.current) {
56
+ return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
57
+ }
58
+
59
+ const image = imageRef.current;
60
+ const container = containerRef.current;
61
+
62
+ // Additional safety check for DOM readiness
63
+ if (!image.naturalWidth && !image.width) {
64
+ return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
65
+ }
66
+
67
+ // Get natural image dimensions
68
+ const imageWidth = image.naturalWidth || image.width || 800;
69
+ const imageHeight = image.naturalHeight || image.height || 600;
70
+
71
+ // Get container dimensions with null check
72
+ try {
73
+ const containerRect = container.getBoundingClientRect();
74
+ if (!containerRect || containerRect.width === 0 || containerRect.height === 0) {
75
+ return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
76
+ }
77
+ const containerWidth = containerRect.width;
78
+ const containerHeight = containerRect.height;
79
+
80
+ // Calculate image display dimensions considering rotation
81
+ const rotationRad = (rotation * Math.PI) / 180;
82
+ const cos = Math.abs(Math.cos(rotationRad));
83
+ const sin = Math.abs(Math.sin(rotationRad));
84
+
85
+ // Calculate the actual display size of the image
86
+ const aspectRatio = imageWidth / imageHeight;
87
+ let displayWidth, displayHeight;
88
+
89
+ if (containerWidth / containerHeight > aspectRatio) {
90
+ displayHeight = Math.min(containerHeight * 0.9, imageHeight);
91
+ displayWidth = displayHeight * aspectRatio;
92
+ } else {
93
+ displayWidth = Math.min(containerWidth * 0.9, imageWidth);
94
+ displayHeight = displayWidth / aspectRatio;
95
+ }
96
+
97
+ // Account for rotation in bounds calculation
98
+ const rotatedWidth = displayWidth * cos + displayHeight * sin;
99
+ const rotatedHeight = displayWidth * sin + displayHeight * cos;
100
+
101
+ // Calculate scaled dimensions
102
+ const scaledWidth = rotatedWidth * zoomLevel;
103
+ const scaledHeight = rotatedHeight * zoomLevel;
104
+
105
+ // Calculate bounds - how far we can drag
106
+ const maxX = Math.max(0, (scaledWidth - containerWidth) / 2);
107
+ const maxY = Math.max(0, (scaledHeight - containerHeight) / 2);
108
+
109
+ return {
110
+ minX: -maxX,
111
+ maxX: maxX,
112
+ minY: -maxY,
113
+ maxY: maxY,
114
+ };
115
+ } catch (error) {
116
+ console.warn('PhotoViewer: Error calculating bounds', error);
117
+ return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
118
+ }
119
+ },
120
+ [isMounted]
121
+ );
122
+
123
+ // Constrain position within bounds
124
+ const constrainPosition = useCallback(
125
+ (position: { x: number; y: number }, bounds: ImageState['bounds']) => {
126
+ return {
127
+ x: Math.max(bounds.minX, Math.min(bounds.maxX, position.x)),
128
+ y: Math.max(bounds.minY, Math.min(bounds.maxY, position.y)),
129
+ };
130
+ },
131
+ []
132
+ );
133
+
134
+ // Mount tracking and ensure the current index is within bounds
135
+ useEffect(() => {
136
+ setIsMounted(true);
137
+ if (startIndex < 0 || startIndex >= images.length) {
138
+ setCurrentIndex(0);
139
+ } else {
140
+ setCurrentIndex(startIndex);
141
+ }
142
+ return () => setIsMounted(false);
143
+ }, [images, startIndex]);
144
+
145
+ // Handle modal open/close body class
146
+ useEffect(() => {
147
+ if (isModalOpen) {
148
+ document.body.classList.add('is-open-photoviewer');
149
+ } else {
150
+ document.body.classList.remove('is-open-photoviewer');
151
+ }
152
+ }, [isModalOpen]);
153
+
154
+ // Initialize state for current image when index changes
155
+ useEffect(() => {
156
+ if (isModalOpen) {
157
+ setImageStates(prev => {
158
+ if (!prev[currentIndex]) {
159
+ return {
160
+ ...prev,
161
+ [currentIndex]: {
162
+ zoomLevel: 1,
163
+ position: { x: 0, y: 0 },
164
+ rotation: 0,
165
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
166
+ },
167
+ };
168
+ }
169
+ return prev;
170
+ });
171
+ }
172
+ }, [isModalOpen, currentIndex]);
173
+
174
+ // Call onImageChange callback when current index changes
175
+ useEffect(() => {
176
+ if (onImageChange) {
177
+ onImageChange(currentIndex);
178
+ }
179
+ }, [currentIndex, onImageChange]);
180
+
181
+ // Update bounds when image loads or dimensions change
182
+ useEffect(() => {
183
+ const image = imageRef.current;
184
+ const container = containerRef.current;
185
+
186
+ const updateImageBounds = (): void => {
187
+ if (!isMounted || !image || !container) return undefined;
188
+
189
+ setImageStates(prev => {
190
+ const currentState = prev[currentIndex] || {
191
+ zoomLevel: 1,
192
+ position: { x: 0, y: 0 },
193
+ rotation: 0,
194
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
195
+ };
196
+
197
+ const newBounds = calculateBounds(currentState.zoomLevel, currentState.rotation);
198
+ const constrainedPosition = constrainPosition(currentState.position, newBounds);
199
+
200
+ return {
201
+ ...prev,
202
+ [currentIndex]: {
203
+ ...currentState,
204
+ bounds: newBounds,
205
+ position: constrainedPosition,
206
+ },
207
+ };
208
+ });
209
+ };
210
+
211
+ if (image && container && image.complete && isMounted) {
212
+ updateImageBounds();
213
+ return undefined;
214
+ } else if (image && container && isMounted) {
215
+ image.addEventListener('load', updateImageBounds);
216
+ return () => image.removeEventListener('load', updateImageBounds);
217
+ }
218
+ return undefined;
219
+ }, [currentIndex, calculateBounds, constrainPosition, isMounted]);
220
+
221
+ // Handle window resize
222
+ useEffect(() => {
223
+ const handleResize = (): void => {
224
+ if (!isMounted || !imageRef.current || !containerRef.current) return undefined;
225
+
226
+ setImageStates(prev => {
227
+ const currentState = prev[currentIndex] || {
228
+ zoomLevel: 1,
229
+ position: { x: 0, y: 0 },
230
+ rotation: 0,
231
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
232
+ };
233
+
234
+ const newBounds = calculateBounds(currentState.zoomLevel, currentState.rotation);
235
+ const constrainedPosition = constrainPosition(currentState.position, newBounds);
236
+
237
+ return {
238
+ ...prev,
239
+ [currentIndex]: {
240
+ ...currentState,
241
+ bounds: newBounds,
242
+ position: constrainedPosition,
243
+ },
244
+ };
245
+ });
246
+ };
247
+
248
+ window.addEventListener('resize', handleResize);
249
+ return () => window.removeEventListener('resize', handleResize);
250
+ }, [currentIndex, calculateBounds, constrainPosition, isMounted]);
251
+
252
+ const openModal = useCallback(() => {
253
+ setIsModalOpen(true);
254
+ }, []);
255
+
256
+ const closeModal = useCallback(() => {
257
+ setIsModalOpen(false);
258
+ if (onClose) onClose();
259
+ }, [onClose]);
260
+
261
+ const goToPrevious = useCallback(() => {
262
+ if (currentIndex > 0) {
263
+ setIsTransitioning(true);
264
+ setTimeout(() => {
265
+ setCurrentIndex(prev => prev - 1);
266
+ setIsTransitioning(false);
267
+ }, 150);
268
+ }
269
+ }, [currentIndex]);
270
+
271
+ const goToNext = useCallback(() => {
272
+ if (currentIndex < images.length - 1) {
273
+ setIsTransitioning(true);
274
+ setTimeout(() => {
275
+ setCurrentIndex(prev => prev + 1);
276
+ setIsTransitioning(false);
277
+ }, 150);
278
+ }
279
+ }, [currentIndex, images.length]);
280
+
281
+ const setZoomLevel = useCallback(
282
+ (zoom: number | ((prev: number) => number)) => {
283
+ setImageStates(prev => {
284
+ const currentState = prev[currentIndex] || {
285
+ zoomLevel: 1,
286
+ position: { x: 0, y: 0 },
287
+ rotation: 0,
288
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
289
+ };
290
+
291
+ const newZoom = typeof zoom === 'function' ? zoom(currentState.zoomLevel) : zoom;
292
+ const clampedZoom = Math.max(0.1, Math.min(5, newZoom));
293
+
294
+ const newBounds = calculateBounds(clampedZoom, currentState.rotation);
295
+ const constrainedPosition = constrainPosition(currentState.position, newBounds);
296
+
297
+ return {
298
+ ...prev,
299
+ [currentIndex]: {
300
+ ...currentState,
301
+ zoomLevel: clampedZoom,
302
+ bounds: newBounds,
303
+ position: constrainedPosition,
304
+ },
305
+ };
306
+ });
307
+ },
308
+ [isMounted, currentIndex, calculateBounds, constrainPosition]
309
+ );
310
+
311
+ const setImagePosition = useCallback(
312
+ (
313
+ position:
314
+ | { x: number; y: number }
315
+ | ((prev: { x: number; y: number }) => { x: number; y: number })
316
+ ) => {
317
+ setImageStates(prev => {
318
+ const currentState = prev[currentIndex] || {
319
+ zoomLevel: 1,
320
+ position: { x: 0, y: 0 },
321
+ rotation: 0,
322
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
323
+ };
324
+
325
+ const newPosition =
326
+ typeof position === 'function' ? position(currentState.position) : position;
327
+ const constrainedPosition = constrainPosition(newPosition, currentState.bounds);
328
+
329
+ return {
330
+ ...prev,
331
+ [currentIndex]: {
332
+ ...currentState,
333
+ position: constrainedPosition,
334
+ },
335
+ };
336
+ });
337
+ },
338
+ [currentIndex, constrainPosition]
339
+ );
340
+
341
+ const setRotationAngle = useCallback(
342
+ (rotation: number | ((prev: number) => number)) => {
343
+ setImageStates(prev => {
344
+ const currentState = prev[currentIndex] || {
345
+ zoomLevel: 1,
346
+ position: { x: 0, y: 0 },
347
+ rotation: 0,
348
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
349
+ };
350
+
351
+ const newRotation =
352
+ typeof rotation === 'function' ? rotation(currentState.rotation) : rotation;
353
+ const normalizedRotation = ((newRotation % 360) + 360) % 360;
354
+
355
+ const newBounds = calculateBounds(currentState.zoomLevel, normalizedRotation);
356
+ const constrainedPosition = constrainPosition(currentState.position, newBounds);
357
+
358
+ return {
359
+ ...prev,
360
+ [currentIndex]: {
361
+ ...currentState,
362
+ rotation: normalizedRotation,
363
+ bounds: newBounds,
364
+ position: constrainedPosition,
365
+ },
366
+ };
367
+ });
368
+ },
369
+ [isMounted, currentIndex, calculateBounds, constrainPosition]
370
+ );
371
+
372
+ // Handle mouse wheel for zooming with proper bounds
373
+ const handleWheel = useCallback(
374
+ (event: React.WheelEvent<HTMLDivElement>) => {
375
+ if (!isMounted || !event || !event.currentTarget) return;
376
+
377
+ // Additional safety check for the target element
378
+ const target = event.currentTarget;
379
+ if (!target || typeof target.getBoundingClientRect !== 'function') return;
380
+
381
+ // Storybook-specific safety check - ensure DOM is ready
382
+ if (typeof window !== 'undefined' && window.location?.href?.includes('storybook')) {
383
+ try {
384
+ // Test if getBoundingClientRect works before proceeding
385
+ const testRect = target.getBoundingClientRect();
386
+ if (!testRect || testRect.width === 0 || testRect.height === 0) return;
387
+ } catch (e) {
388
+ return;
389
+ }
390
+ }
391
+
392
+ setImageStates(prev => {
393
+ const currentState = prev[currentIndex] || {
394
+ zoomLevel: 1,
395
+ position: { x: 0, y: 0 },
396
+ rotation: 0,
397
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
398
+ };
399
+
400
+ // Advanced gesture detection for different input methods
401
+ const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
402
+ const isTrackpadPinch = event.ctrlKey && isMac;
403
+ const hasHorizontalScroll = Math.abs(event.deltaX) > 0;
404
+ const isTrackpadScroll = !event.ctrlKey && hasHorizontalScroll && isMac;
405
+ const isMagicMouse = !event.ctrlKey && !hasHorizontalScroll && isMac;
406
+ const isRegularMouse = !isMac;
407
+
408
+ // Handle different input methods with appropriate sensitivity
409
+ let zoomAmount: number;
410
+ let shouldPreventDefault = false;
411
+
412
+ if (isTrackpadPinch) {
413
+ // MacBook trackpad pinch zoom - natural, high sensitivity
414
+ zoomAmount = event.deltaY * -0.02;
415
+ shouldPreventDefault = true;
416
+ } else if (isTrackpadScroll) {
417
+ // MacBook trackpad scroll with two fingers
418
+ if (currentState.zoomLevel > 1) {
419
+ // Only zoom when already zoomed in, otherwise allow natural scroll
420
+ zoomAmount = event.deltaY * -0.003;
421
+ shouldPreventDefault = true;
422
+ } else {
423
+ return prev; // Allow page scroll when not zoomed
424
+ }
425
+ } else if (isMagicMouse) {
426
+ // Apple Magic Mouse - less sensitive
427
+ zoomAmount = event.deltaY * -0.004;
428
+ shouldPreventDefault = true;
429
+ } else if (isRegularMouse) {
430
+ // Regular mouse wheel - medium sensitivity
431
+ zoomAmount = event.deltaY * -0.006;
432
+ shouldPreventDefault = true;
433
+ } else {
434
+ // Fallback for other input methods
435
+ zoomAmount = event.deltaY * -0.005;
436
+ shouldPreventDefault = true;
437
+ }
438
+
439
+ if (shouldPreventDefault) {
440
+ event.preventDefault();
441
+ event.stopPropagation();
442
+ }
443
+
444
+ // Add momentum for trackpad gestures
445
+ const currentTime = Date.now();
446
+ const timeDelta = currentTime - lastWheelTime.current;
447
+ lastWheelTime.current = currentTime;
448
+
449
+ // Calculate velocity for momentum (trackpad specific)
450
+ if (isTrackpadPinch && timeDelta < 100) {
451
+ const velocity = Math.abs(zoomAmount) / timeDelta;
452
+ setMomentumZoom({ velocity, timestamp: currentTime });
453
+
454
+ // Clear any existing momentum timeout
455
+ if (momentumTimeoutRef.current) {
456
+ clearTimeout(momentumTimeoutRef.current);
457
+ }
458
+
459
+ // Apply momentum decay after gesture ends
460
+ momentumTimeoutRef.current = setTimeout(() => {
461
+ const decayFactor = 0.95;
462
+ const minVelocity = 0.001;
463
+
464
+ const applyMomentum = () => {
465
+ setMomentumZoom(prev => {
466
+ if (prev.velocity < minVelocity) return prev;
467
+
468
+ const newVelocity = prev.velocity * decayFactor;
469
+ const momentumZoomAmount = newVelocity * (zoomAmount > 0 ? 1 : -1);
470
+
471
+ // Apply momentum zoom
472
+ setImageStates(current => {
473
+ const state = current[currentIndex] || {
474
+ zoomLevel: 1,
475
+ position: { x: 0, y: 0 },
476
+ rotation: 0,
477
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
478
+ };
479
+
480
+ const newZoom = Math.max(0.1, Math.min(5, state.zoomLevel + momentumZoomAmount));
481
+ if (newZoom === state.zoomLevel) return current;
482
+
483
+ const newBounds = calculateBounds(newZoom, state.rotation);
484
+ const constrainedPosition = constrainPosition(state.position, newBounds);
485
+
486
+ return {
487
+ ...current,
488
+ [currentIndex]: {
489
+ ...state,
490
+ zoomLevel: newZoom,
491
+ bounds: newBounds,
492
+ position: constrainedPosition,
493
+ },
494
+ };
495
+ });
496
+
497
+ if (newVelocity >= minVelocity) {
498
+ requestAnimationFrame(applyMomentum);
499
+ }
500
+
501
+ return { velocity: newVelocity, timestamp: Date.now() };
502
+ });
503
+ };
504
+
505
+ requestAnimationFrame(applyMomentum);
506
+ }, 50);
507
+ }
508
+
509
+ // Safe getBoundingClientRect call with error handling
510
+ let rect;
511
+ try {
512
+ rect = target.getBoundingClientRect();
513
+ } catch (error) {
514
+ console.warn('PhotoViewer: Error getting bounding rect', error);
515
+ return prev;
516
+ }
517
+
518
+ if (!rect || rect.width === 0 || rect.height === 0) return prev;
519
+
520
+ const centerX = rect.width / 2;
521
+ const centerY = rect.height / 2;
522
+ const cursorX = event.clientX - rect.left - centerX;
523
+ const cursorY = event.clientY - rect.top - centerY;
524
+
525
+ const oldZoom = currentState.zoomLevel;
526
+ const newZoom = Math.max(0.1, Math.min(5, oldZoom + zoomAmount));
527
+
528
+ if (newZoom !== oldZoom) {
529
+ const zoomFactor = newZoom / oldZoom;
530
+ const newBounds = calculateBounds(newZoom, currentState.rotation);
531
+
532
+ // Calculate new position to zoom towards cursor
533
+ const newPosition = {
534
+ x: currentState.position.x + cursorX * (1 - zoomFactor) * 0.5,
535
+ y: currentState.position.y + cursorY * (1 - zoomFactor) * 0.5,
536
+ };
537
+
538
+ const constrainedPosition = constrainPosition(newPosition, newBounds);
539
+
540
+ return {
541
+ ...prev,
542
+ [currentIndex]: {
543
+ ...currentState,
544
+ zoomLevel: newZoom,
545
+ bounds: newBounds,
546
+ position: constrainedPosition,
547
+ },
548
+ };
549
+ }
550
+ return prev;
551
+ });
552
+ },
553
+ [isMounted, currentIndex, calculateBounds, constrainPosition]
554
+ );
555
+
556
+ // Handle double click to zoom with smart zoom levels
557
+ const handleDoubleClick = useCallback(
558
+ (event: React.MouseEvent) => {
559
+ if (!isMounted || !event || !event.currentTarget) return;
560
+
561
+ const target = event.currentTarget;
562
+ if (!target || typeof target.getBoundingClientRect !== 'function') return;
563
+
564
+ setImageStates(prev => {
565
+ const currentState = prev[currentIndex] || {
566
+ zoomLevel: 1,
567
+ position: { x: 0, y: 0 },
568
+ rotation: 0,
569
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
570
+ };
571
+
572
+ let rect;
573
+ try {
574
+ rect = target.getBoundingClientRect();
575
+ } catch (error) {
576
+ console.warn('PhotoViewer: Error getting bounding rect in double click', error);
577
+ return prev;
578
+ }
579
+
580
+ if (!rect || rect.width === 0 || rect.height === 0) return prev;
581
+
582
+ const centerX = rect.width / 2;
583
+ const centerY = rect.height / 2;
584
+ const cursorX = event.clientX - rect.left - centerX;
585
+ const cursorY = event.clientY - rect.top - centerY;
586
+
587
+ let newZoom: number;
588
+ let newPosition = { x: 0, y: 0 };
589
+
590
+ if (currentState.zoomLevel < 1.5) {
591
+ newZoom = 2;
592
+ // Zoom towards cursor
593
+ newPosition = {
594
+ x: -cursorX * 0.5,
595
+ y: -cursorY * 0.5,
596
+ };
597
+ } else if (currentState.zoomLevel < 3) {
598
+ newZoom = 4;
599
+ newPosition = {
600
+ x: -cursorX * 0.75,
601
+ y: -cursorY * 0.75,
602
+ };
603
+ } else {
604
+ newZoom = 1;
605
+ newPosition = { x: 0, y: 0 };
606
+ }
607
+
608
+ const newBounds = calculateBounds(newZoom, currentState.rotation);
609
+ const constrainedPosition = constrainPosition(newPosition, newBounds);
610
+
611
+ return {
612
+ ...prev,
613
+ [currentIndex]: {
614
+ ...currentState,
615
+ zoomLevel: newZoom,
616
+ bounds: newBounds,
617
+ position: constrainedPosition,
618
+ },
619
+ };
620
+ });
621
+ },
622
+ [isMounted, currentIndex, calculateBounds, constrainPosition]
623
+ );
624
+
625
+ // Handle mouse down for panning
626
+ const handleMouseDown = useCallback(
627
+ (event: React.MouseEvent<HTMLDivElement | HTMLImageElement, MouseEvent>) => {
628
+ setImageStates(prev => {
629
+ const currentState = prev[currentIndex] || {
630
+ zoomLevel: 1,
631
+ position: { x: 0, y: 0 },
632
+ rotation: 0,
633
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
634
+ };
635
+
636
+ if (currentState.zoomLevel > 1) {
637
+ event.preventDefault();
638
+ setIsDragging(true);
639
+ setStartDragPosition({
640
+ x: event.clientX - currentState.position.x,
641
+ y: event.clientY - currentState.position.y,
642
+ });
643
+ }
644
+ return prev;
645
+ });
646
+ },
647
+ [currentIndex]
648
+ );
649
+
650
+ // Handle mouse move for panning with bounds
651
+ const handleMouseMove = useCallback(
652
+ (event: React.MouseEvent<HTMLDivElement | HTMLImageElement, MouseEvent>) => {
653
+ if (!isDragging) return;
654
+
655
+ setImageStates(prev => {
656
+ const currentState = prev[currentIndex] || {
657
+ zoomLevel: 1,
658
+ position: { x: 0, y: 0 },
659
+ rotation: 0,
660
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
661
+ };
662
+
663
+ // Apply scaling factor to reduce drag sensitivity
664
+ const dragSensitivity = Math.min(1, 1 / currentState.zoomLevel);
665
+ const deltaX = (event.clientX - startDragPosition.x) * dragSensitivity;
666
+ const deltaY = (event.clientY - startDragPosition.y) * dragSensitivity;
667
+
668
+ const newPosition = {
669
+ x: deltaX,
670
+ y: deltaY,
671
+ };
672
+
673
+ const constrainedPosition = constrainPosition(newPosition, currentState.bounds);
674
+
675
+ return {
676
+ ...prev,
677
+ [currentIndex]: {
678
+ ...currentState,
679
+ position: constrainedPosition,
680
+ },
681
+ };
682
+ });
683
+ },
684
+ [isDragging, startDragPosition, currentIndex, constrainPosition]
685
+ );
686
+
687
+ // Handle mouse up for panning
688
+ const handleMouseUp = useCallback(() => {
689
+ setIsDragging(false);
690
+ }, []);
691
+
692
+ // Touch handlers for mobile gestures with bounds
693
+ const handleTouchStart = useCallback(
694
+ (event: React.TouchEvent<HTMLImageElement | HTMLDivElement>) => {
695
+ if (!enableGestures) return;
696
+
697
+ const touches = event.touches;
698
+
699
+ // Always prevent default for multi-touch to stop page zoom
700
+ if (touches.length > 1) {
701
+ event.preventDefault();
702
+ event.stopPropagation();
703
+ }
704
+
705
+ touchPointsRef.current = Array.from(touches).map(touch => ({
706
+ x: touch.clientX,
707
+ y: touch.clientY,
708
+ }));
709
+
710
+ setImageStates(prev => {
711
+ const currentState = prev[currentIndex] || {
712
+ zoomLevel: 1,
713
+ position: { x: 0, y: 0 },
714
+ rotation: 0,
715
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
716
+ };
717
+
718
+ if (touches.length === 1 && currentState.zoomLevel > 1) {
719
+ setIsDragging(true);
720
+ const touch = touches[0];
721
+ if (touch) {
722
+ setStartDragPosition({
723
+ x: touch.clientX - currentState.position.x,
724
+ y: touch.clientY - currentState.position.y,
725
+ });
726
+ }
727
+ } else if (touches.length === 2) {
728
+ const touch1 = touches[0];
729
+ const touch2 = touches[1];
730
+ if (touch1 && touch2) {
731
+ const dx = touch1.clientX - touch2.clientX;
732
+ const dy = touch1.clientY - touch2.clientY;
733
+ lastDistanceRef.current = Math.sqrt(dx * dx + dy * dy);
734
+
735
+ lastMidpointRef.current = {
736
+ x: (touch1.clientX + touch2.clientX) / 2,
737
+ y: (touch1.clientY + touch2.clientY) / 2,
738
+ };
739
+ }
740
+ }
741
+ return prev;
742
+ });
743
+ },
744
+ [enableGestures, currentIndex]
745
+ );
746
+
747
+ // Handle touch move for dragging and pinch zoom with bounds
748
+ const handleTouchMove = useCallback(
749
+ (event: React.TouchEvent<HTMLImageElement | HTMLDivElement>) => {
750
+ if (!enableGestures) return;
751
+
752
+ const touches = event.touches;
753
+
754
+ // Always prevent default for multi-touch gestures to stop page zoom
755
+ if (touches.length > 1) {
756
+ event.preventDefault();
757
+ event.stopPropagation();
758
+ }
759
+
760
+ setImageStates(prev => {
761
+ const currentState = prev[currentIndex] || {
762
+ zoomLevel: 1,
763
+ position: { x: 0, y: 0 },
764
+ rotation: 0,
765
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
766
+ };
767
+
768
+ // Prevent default for single touch when zoomed in to avoid conflicts
769
+ if (currentState.zoomLevel > 1 && touches.length === 1) {
770
+ event.preventDefault();
771
+ }
772
+
773
+ let newPosition: { x: number; y: number } | null = null;
774
+ let zoomDelta = 0;
775
+ let currentMidpoint: { x: number; y: number } | null = null;
776
+
777
+ if (touches.length === 1 && isDragging && currentState.zoomLevel > 1) {
778
+ const touch = touches[0];
779
+ if (touch) {
780
+ // Apply scaling factor to reduce touch drag sensitivity
781
+ const dragSensitivity = Math.min(1, 1 / currentState.zoomLevel);
782
+ const deltaX = (touch.clientX - startDragPosition.x) * dragSensitivity;
783
+ const deltaY = (touch.clientY - startDragPosition.y) * dragSensitivity;
784
+
785
+ newPosition = {
786
+ x: deltaX,
787
+ y: deltaY,
788
+ };
789
+ }
790
+
791
+ if (newPosition) {
792
+ const constrainedPosition = constrainPosition(newPosition, currentState.bounds);
793
+
794
+ return {
795
+ ...prev,
796
+ [currentIndex]: {
797
+ ...currentState,
798
+ position: constrainedPosition,
799
+ },
800
+ };
801
+ }
802
+ } else if (touches.length === 2 && lastDistanceRef.current !== null) {
803
+ const touch1 = touches[0];
804
+ const touch2 = touches[1];
805
+ if (touch1 && touch2) {
806
+ const dx = touch1.clientX - touch2.clientX;
807
+ const dy = touch1.clientY - touch2.clientY;
808
+ const distance = Math.sqrt(dx * dx + dy * dy);
809
+
810
+ zoomDelta = (distance - lastDistanceRef.current) * 0.005;
811
+ lastDistanceRef.current = distance;
812
+
813
+ currentMidpoint = {
814
+ x: (touch1.clientX + touch2.clientX) / 2,
815
+ y: (touch1.clientY + touch2.clientY) / 2,
816
+ };
817
+
818
+ const oldZoom = currentState.zoomLevel;
819
+ const newZoom = Math.max(0.1, Math.min(5, oldZoom + zoomDelta));
820
+
821
+ if (newZoom !== oldZoom && lastMidpointRef.current && currentMidpoint) {
822
+ let rect;
823
+ try {
824
+ rect = event.currentTarget.getBoundingClientRect();
825
+ } catch (error) {
826
+ console.warn('PhotoViewer: Error getting bounding rect in touch move', error);
827
+ return prev;
828
+ }
829
+
830
+ if (!rect || rect.width === 0 || rect.height === 0) return prev;
831
+
832
+ const centerX = rect.width / 2;
833
+ const centerY = rect.height / 2;
834
+ const midpointX = currentMidpoint.x - rect.left - centerX;
835
+ const midpointY = currentMidpoint.y - rect.top - centerY;
836
+
837
+ const zoomFactor = newZoom / oldZoom;
838
+ const newBounds = calculateBounds(newZoom, currentState.rotation);
839
+
840
+ const newPosition = {
841
+ x: currentState.position.x + midpointX * (1 - zoomFactor) * 0.5,
842
+ y: currentState.position.y + midpointY * (1 - zoomFactor) * 0.5,
843
+ };
844
+
845
+ const constrainedPosition = constrainPosition(newPosition, newBounds);
846
+
847
+ lastMidpointRef.current = currentMidpoint;
848
+
849
+ return {
850
+ ...prev,
851
+ [currentIndex]: {
852
+ ...currentState,
853
+ zoomLevel: newZoom,
854
+ bounds: newBounds,
855
+ position: constrainedPosition,
856
+ },
857
+ };
858
+ }
859
+
860
+ if (currentMidpoint) {
861
+ lastMidpointRef.current = currentMidpoint;
862
+ }
863
+ }
864
+ }
865
+ return prev;
866
+ });
867
+ },
868
+ [
869
+ isMounted,
870
+ enableGestures,
871
+ isDragging,
872
+ startDragPosition,
873
+ currentIndex,
874
+ constrainPosition,
875
+ calculateBounds,
876
+ ]
877
+ );
878
+
879
+ // Handle touch end
880
+ const handleTouchEnd = useCallback(() => {
881
+ setIsDragging(false);
882
+ lastDistanceRef.current = null;
883
+ lastMidpointRef.current = null;
884
+ }, []);
885
+
886
+ // Get current state values without causing re-renders
887
+ const currentState = imageStates[currentIndex] || {
888
+ zoomLevel: 1,
889
+ position: { x: 0, y: 0 },
890
+ rotation: 0,
891
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
892
+ };
893
+
894
+ return {
895
+ currentIndex,
896
+ isModalOpen,
897
+ zoomLevel: currentState.zoomLevel,
898
+ imagePosition: currentState.position,
899
+ isDragging,
900
+ isFullscreen,
901
+ rotationAngle: currentState.rotation,
902
+ showInfo,
903
+ imageRef,
904
+ containerRef,
905
+ isTransitioning,
906
+ setCurrentIndex,
907
+ setZoomLevel,
908
+ setImagePosition,
909
+ setIsDragging,
910
+ setIsFullscreen,
911
+ setRotationAngle,
912
+ setShowInfo,
913
+ openModal,
914
+ closeModal,
915
+ goToPrevious,
916
+ goToNext,
917
+ handleWheel,
918
+ handleMouseDown,
919
+ handleMouseMove,
920
+ handleMouseUp,
921
+ handleTouchStart,
922
+ handleTouchMove,
923
+ handleTouchEnd,
924
+ handleDoubleClick,
925
+ resetImageState: () => {
926
+ setImageStates(prev => ({
927
+ ...prev,
928
+ [currentIndex]: {
929
+ zoomLevel: 1,
930
+ position: { x: 0, y: 0 },
931
+ rotation: 0,
932
+ bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
933
+ },
934
+ }));
935
+ },
936
+ };
937
+ };