@shohojdhara/atomix 0.1.16 → 0.1.18
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.
- package/CONTRIBUTING.md +151 -0
- package/NEXTJS_INTEGRATION.md +358 -0
- package/README.md +168 -119
- package/babel.config.js +58 -0
- package/css.d.ts +10 -0
- package/dist/css/atomix.css +1 -2
- package/dist/js/194.js +1 -2
- package/dist/js/244.js +1 -0
- package/dist/js/atomix.react.cjs.js +1 -0
- package/dist/js/atomix.react.esm.js +1 -2
- package/dist/js/atomix.react.umd.js +1 -2
- package/dist/js/chunks/cjs/202.9d3b1ef1eaa0d5c8a309.js +1 -0
- package/dist/js/chunks/cjs/308.6ea9685ea38ead4120d0.js +1 -0
- package/dist/js/chunks/cjs/54.73db6922594e421ba6b1.js +1 -0
- package/dist/js/chunks/cjs/619.51feecaadcab819780d4.js +1 -0
- package/dist/js/chunks/cjs/690.90f6d11164081cbcbc4d.js +1 -0
- package/dist/js/chunks/cjs/894.24877561df336a8dfd14.js +1 -0
- package/dist/js/chunks/cjs/897.6c2a71fae95338890de7.js +1 -0
- package/dist/js/chunks/esm/{202.ff48d27672233280e021.js → 202.82aa7b3244e53c9edb72.js} +1 -2
- package/dist/js/chunks/esm/{308.f873332126eba90e5c62.js → 308.27e1e4005705ae320432.js} +1 -2
- package/dist/js/chunks/esm/{54.4db919e5e4e5cc6d7c72.js → 54.ece1fd6964f98d4d994f.js} +1 -2
- package/dist/js/chunks/esm/{619.afc5a718eff77fa423b5.js → 619.ebeb0298432a066ac05c.js} +1 -2
- package/dist/js/chunks/esm/{690.a9e968c7497d61e56cdc.js → 690.c5f412cc979b55740359.js} +1 -2
- package/dist/js/chunks/esm/{894.f1091a4a8758c26d29e4.js → 894.3604ddc9367d75191198.js} +1 -2
- package/dist/js/chunks/esm/{897.561a50f7d043d42169da.js → 897.a4aab2fad9401693eb12.js} +1 -2
- package/dist/js/chunks/umd/{202.dac7605cc555b6bda542.js → 202.5017dd0403d696bf1644.js} +1 -2
- package/dist/js/chunks/umd/{308.6709979849dcbdb90c9b.js → 308.4bc14b9d7b16b6ee0ab8.js} +1 -2
- package/dist/js/chunks/umd/{54.403470e1f7d0ef4424a7.js → 54.7fdfb4a031989470a70d.js} +1 -2
- package/dist/js/chunks/umd/{619.fa05ea98c10270eb64c5.js → 619.84a0c35ecee695250085.js} +1 -2
- package/dist/js/chunks/umd/{690.aa7054d1c53e5402c2d6.js → 690.d7041094a34a4a434be2.js} +1 -2
- package/dist/js/chunks/umd/{894.3e1eaf0a2aadf4434390.js → 894.c127ee4e9513c22ee97d.js} +1 -2
- package/dist/js/chunks/umd/{897.554ea37be4453698c167.js → 897.26932ac837a39fc91907.js} +1 -2
- package/dist/types/components/Badge/index.d.ts +3 -3
- package/dist/types/components/{Navbar → Navigation/Menu}/MegaMenu.d.ts +1 -1
- package/dist/types/components/{Navbar → Navigation/Menu}/Menu.d.ts +1 -1
- package/dist/types/components/Navigation/Nav/Nav.d.ts +20 -0
- package/dist/types/components/{Navbar → Navigation/Nav}/NavDropdown.d.ts +1 -1
- package/dist/types/components/Navigation/Nav/NavItem.d.ts +33 -0
- package/dist/types/components/Navigation/Navbar/Navbar.d.ts +19 -0
- package/dist/types/components/Navigation/SideMenu/SideMenu.d.ts +20 -0
- package/dist/types/components/Navigation/SideMenu/SideMenuItem.d.ts +30 -0
- package/dist/types/components/Navigation/SideMenu/SideMenuList.d.ts +17 -0
- package/dist/types/components/Navigation/index.d.ts +10 -0
- package/dist/types/components/PhotoViewer/PhotoViewer.d.ts +2 -2
- package/dist/types/components/PhotoViewer/PhotoViewerHeader.d.ts +2 -2
- package/dist/types/components/Tab/index.d.ts +2 -2
- package/dist/types/components/Toggle/index.d.ts +2 -2
- package/dist/types/components/Tooltip/index.d.ts +3 -3
- package/dist/types/components/index.d.ts +1 -1
- package/dist/types/lib/composables/index.d.ts +1 -0
- package/dist/types/lib/composables/useDatePicker.d.ts +1 -1
- package/dist/types/lib/composables/useDropdown.d.ts +1 -1
- package/dist/types/lib/composables/useModal.d.ts +1 -1
- package/dist/types/lib/composables/usePhotoViewer.d.ts +1 -1
- package/dist/types/lib/composables/useRating.d.ts +1 -1
- package/dist/types/lib/composables/useSideMenu.d.ts +28 -0
- package/dist/types/lib/constants/components.d.ts +72 -0
- package/dist/types/lib/types/components.d.ts +103 -0
- package/examples/nextjs-example.tsx +271 -0
- package/implementation-guide.md +505 -0
- package/next.config.js +69 -0
- package/package.json +80 -42
- package/postcss.config.js +28 -0
- package/src/Introduction.mdx +3 -5
- package/src/assets/fonts/HelveticaNeue/stylesheet.css +140 -127
- package/src/components/Accordion/Accordion.stories.tsx +58 -45
- package/src/components/Accordion/Accordion.tsx +14 -4
- package/src/components/Accordion/scripts/accordionInteractions.ts +9 -9
- package/src/components/Accordion/scripts/bundle.ts +1 -1
- package/src/components/Accordion/scripts/index.ts +3 -3
- package/src/components/AtomixLogo.tsx +13 -19
- package/src/components/Avatar/Avatar.stories.tsx +24 -21
- package/src/components/Avatar/Avatar.tsx +5 -8
- package/src/components/Avatar/AvatarGroup.tsx +11 -11
- package/src/components/Avatar/index.ts +1 -1
- package/src/components/Avatar/scripts/index.ts +66 -71
- package/src/components/Badge/Badge.stories.tsx +51 -21
- package/src/components/Badge/Badge.tsx +14 -12
- package/src/components/Badge/index.ts +3 -3
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +40 -40
- package/src/components/Breadcrumb/Breadcrumb.tsx +19 -26
- package/src/components/Breadcrumb/index.ts +1 -1
- package/src/components/Breadcrumb/scripts/breadcrumb.ts +36 -34
- package/src/components/Breadcrumb/scripts/index.ts +1 -1
- package/src/components/Breadcrumb/scripts/types.ts +9 -9
- package/src/components/Button/Button.stories.tsx +36 -12
- package/src/components/Button/Button.tsx +52 -39
- package/src/components/Button/index.ts +1 -1
- package/src/components/Button/scripts/buttonInteractions.ts +9 -9
- package/src/components/Button/scripts/index.ts +1 -1
- package/src/components/Callout/Callout.stories.tsx +207 -114
- package/src/components/Callout/Callout.tsx +12 -12
- package/src/components/Callout/index.ts +1 -1
- package/src/components/Callout/scripts/CalloutInteractions.ts +58 -48
- package/src/components/Callout/scripts/bundle.ts +2 -2
- package/src/components/Callout/scripts/index.ts +19 -15
- package/src/components/Card/Card.stories.tsx +2 -2
- package/src/components/Card/Card.tsx +49 -72
- package/src/components/Card/ElevationCard.tsx +4 -8
- package/src/components/Card/index.ts +1 -1
- package/src/components/Card/scripts/bundle.ts +7 -7
- package/src/components/Card/scripts/cardInteractions.ts +24 -24
- package/src/components/Card/scripts/index.ts +25 -26
- package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +6 -3
- package/src/components/ColorModeToggle/ColorModeToggle.tsx +12 -15
- package/src/components/ColorModeToggle/index.ts +1 -1
- package/src/components/Countdown/Countdown.stories.tsx +6 -2
- package/src/components/Countdown/Countdown.tsx +56 -48
- package/src/components/Countdown/index.ts +1 -1
- package/src/components/Countdown/scripts/index.ts +33 -28
- package/src/components/DataTable/DataTable.stories.tsx +23 -18
- package/src/components/DataTable/DataTable.tsx +39 -39
- package/src/components/DataTable/index.ts +1 -1
- package/src/components/DataTable/scripts/bundle.ts +8 -3
- package/src/components/DataTable/scripts/index.ts +182 -164
- package/src/components/DatePicker/DatePicker.stories.tsx +136 -148
- package/src/components/DatePicker/DatePicker.tsx +461 -420
- package/src/components/DatePicker/scripts/bundle.ts +12 -7
- package/src/components/DatePicker/scripts/componentInteractions.ts +76 -46
- package/src/components/DatePicker/scripts/index.ts +176 -156
- package/src/components/DatePicker/types.ts +32 -32
- package/src/components/DatePicker/utils.ts +41 -30
- package/src/components/Dropdown/Dropdown.stories.tsx +85 -55
- package/src/components/Dropdown/Dropdown.tsx +97 -88
- package/src/components/Dropdown/index.ts +5 -10
- package/src/components/Dropdown/scripts/bundle.ts +10 -10
- package/src/components/Dropdown/scripts/componentInteractions.ts +10 -2
- package/src/components/Dropdown/scripts/index.ts +122 -117
- package/src/components/EdgePanel/EdgePanel.stories.tsx +142 -58
- package/src/components/EdgePanel/EdgePanel.tsx +7 -13
- package/src/components/EdgePanel/index.ts +1 -1
- package/src/components/EdgePanel/scripts/bundle.ts +5 -5
- package/src/components/EdgePanel/scripts/edgePanelInteractions.ts +26 -26
- package/src/components/EdgePanel/scripts/index.ts +53 -53
- package/src/components/Form/Checkbox.stories.tsx +2 -2
- package/src/components/Form/Checkbox.tsx +13 -7
- package/src/components/Form/Form.stories.tsx +144 -218
- package/src/components/Form/Form.tsx +6 -6
- package/src/components/Form/FormGroup.stories.tsx +21 -38
- package/src/components/Form/FormGroup.tsx +18 -20
- package/src/components/Form/Input.stories.tsx +1 -1
- package/src/components/Form/Input.tsx +18 -8
- package/src/components/Form/Radio.stories.tsx +12 -25
- package/src/components/Form/Radio.tsx +11 -6
- package/src/components/Form/Select.stories.tsx +6 -6
- package/src/components/Form/Select.tsx +31 -33
- package/src/components/Form/Textarea.stories.tsx +7 -2
- package/src/components/Form/Textarea.tsx +17 -8
- package/src/components/Form/index.ts +1 -1
- package/src/components/Hero/Hero.stories.tsx +44 -42
- package/src/components/Hero/Hero.tsx +28 -38
- package/src/components/Hero/index.ts +1 -1
- package/src/components/Hero/scripts/bundle.ts +6 -6
- package/src/components/Hero/scripts/heroInteractions.ts +24 -29
- package/src/components/Hero/scripts/index.ts +16 -17
- package/src/components/Icon/Icon.tsx +16 -18
- package/src/components/Icon/index.ts +1 -1
- package/src/components/List/List.stories.tsx +1 -3
- package/src/components/List/List.tsx +6 -10
- package/src/components/List/ListGroup.tsx +1 -1
- package/src/components/List/index.ts +1 -1
- package/src/components/Messages/Messages.stories.tsx +30 -29
- package/src/components/Messages/Messages.tsx +60 -55
- package/src/components/Messages/index.ts +1 -1
- package/src/components/Messages/scripts/bundle.ts +1 -6
- package/src/components/Messages/scripts/componentInteractions.ts +32 -37
- package/src/components/Messages/scripts/index.ts +61 -55
- package/src/components/Modal/Modal.stories.tsx +77 -53
- package/src/components/Modal/Modal.tsx +63 -62
- package/src/components/Modal/index.ts +1 -1
- package/src/components/Modal/scripts/bundle.ts +3 -3
- package/src/components/Modal/scripts/index.ts +96 -84
- package/src/components/Modal/scripts/modalInteractions.ts +16 -14
- package/src/components/{Navbar → Navigation/Menu}/MegaMenu.tsx +50 -59
- package/src/components/Navigation/Menu/Menu.stories.tsx +340 -0
- package/src/components/Navigation/Menu/Menu.tsx +110 -0
- package/src/components/Navigation/Nav/Nav.stories.tsx +458 -0
- package/src/components/Navigation/Nav/Nav.tsx +50 -0
- package/src/components/Navigation/Nav/NavDropdown.tsx +105 -0
- package/src/components/Navigation/Nav/NavItem.tsx +159 -0
- package/src/components/{Navbar → Navigation/Navbar}/Navbar.stories.tsx +198 -104
- package/src/components/Navigation/Navbar/Navbar.tsx +150 -0
- package/src/components/Navigation/README.md +314 -0
- package/src/components/Navigation/SideMenu/SideMenu.README.md +494 -0
- package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +618 -0
- package/src/components/Navigation/SideMenu/SideMenu.tsx +101 -0
- package/src/components/Navigation/SideMenu/SideMenuItem.tsx +95 -0
- package/src/components/Navigation/SideMenu/SideMenuList.tsx +41 -0
- package/src/components/Navigation/index.ts +23 -0
- package/src/components/Navigation/scripts/NavbarInteractions.ts +171 -0
- package/src/components/Navigation/scripts/SideMenu.ts +319 -0
- package/src/components/Navigation/scripts/SideMenuBundle.ts +69 -0
- package/src/components/Navigation/scripts/SideMenuInteractions.ts +250 -0
- package/src/components/Navigation/scripts/bundle.ts +58 -0
- package/src/components/Navigation/scripts/index.ts +248 -0
- package/src/components/Pagination/Pagination.stories.tsx +34 -33
- package/src/components/Pagination/Pagination.tsx +25 -35
- package/src/components/Pagination/index.ts +1 -1
- package/src/components/Pagination/scripts/index.ts +42 -37
- package/src/components/PhotoViewer/PhotoViewer.stories.tsx +48 -48
- package/src/components/PhotoViewer/PhotoViewer.tsx +29 -46
- package/src/components/PhotoViewer/PhotoViewerHeader.tsx +20 -26
- package/src/components/PhotoViewer/PhotoViewerImage.tsx +19 -17
- package/src/components/PhotoViewer/PhotoViewerInfo.tsx +13 -5
- package/src/components/PhotoViewer/PhotoViewerNavigation.tsx +5 -5
- package/src/components/PhotoViewer/PhotoViewerThumbnails.tsx +31 -30
- package/src/components/PhotoViewer/examples/ImageGallery.tsx +27 -37
- package/src/components/PhotoViewer/examples/SimpleGallery.tsx +19 -13
- package/src/components/PhotoViewer/examples/index.ts +1 -1
- package/src/components/PhotoViewer/index.ts +1 -1
- package/src/components/PhotoViewer/scripts/PhotoViewerInteractions.ts +43 -33
- package/src/components/PhotoViewer/scripts/bundle.ts +14 -14
- package/src/components/PhotoViewer/scripts/index.ts +173 -129
- package/src/components/Popover/Popover.stories.tsx +11 -12
- package/src/components/Popover/Popover.tsx +36 -36
- package/src/components/Popover/index.ts +1 -1
- package/src/components/Popover/scripts/bundle.ts +1 -1
- package/src/components/Popover/scripts/componentInteractions.ts +34 -46
- package/src/components/Popover/scripts/index.ts +64 -53
- package/src/components/ProductReview/ProductReview.stories.tsx +10 -8
- package/src/components/ProductReview/ProductReview.tsx +28 -32
- package/src/components/ProductReview/scripts/componentInteractions.ts +20 -20
- package/src/components/Progress/Progress.tsx +36 -34
- package/src/components/Progress/scripts/bundle.ts +7 -2
- package/src/components/Progress/scripts/componentInteractions.ts +29 -23
- package/src/components/Progress/scripts/index.ts +45 -39
- package/src/components/Rating/Rating.stories.tsx +3 -16
- package/src/components/Rating/Rating.tsx +250 -231
- package/src/components/Rating/scripts/bundle.ts +11 -6
- package/src/components/Rating/scripts/index.ts +85 -80
- package/src/components/Rating/scripts/ratingInteractions.ts +27 -24
- package/src/components/River/River.stories.tsx +70 -24
- package/src/components/River/River.tsx +28 -38
- package/src/components/River/index.ts +1 -1
- package/src/components/River/scripts/index.ts +11 -12
- package/src/components/SectionIntro/SectionIntro.stories.tsx +12 -9
- package/src/components/SectionIntro/SectionIntro.tsx +25 -31
- package/src/components/SectionIntro/scripts/componentInteractions.ts +1 -1
- package/src/components/SectionIntro/scripts/index.ts +30 -16
- package/src/components/Spinner/Spinner.stories.tsx +5 -7
- package/src/components/Spinner/Spinner.tsx +11 -6
- package/src/components/Spinner/index.ts +2 -2
- package/src/components/Steps/Steps.stories.tsx +44 -48
- package/src/components/Steps/Steps.tsx +20 -20
- package/src/components/Steps/index.ts +1 -1
- package/src/components/Steps/scripts/index.ts +9 -9
- package/src/components/Tab/Tab.stories.tsx +14 -6
- package/src/components/Tab/Tab.tsx +16 -18
- package/src/components/Tab/index.ts +2 -2
- package/src/components/Tab/scripts/index.ts +13 -13
- package/src/components/Testimonial/Testimonial.stories.tsx +54 -51
- package/src/components/Testimonial/Testimonial.tsx +18 -19
- package/src/components/Testimonial/index.ts +1 -1
- package/src/components/Testimonial/scripts/index.ts +19 -8
- package/src/components/Todo/Todo.stories.tsx +7 -24
- package/src/components/Todo/Todo.tsx +35 -46
- package/src/components/Todo/index.ts +1 -1
- package/src/components/Todo/scripts/bundle.ts +1 -1
- package/src/components/Todo/scripts/index.ts +99 -81
- package/src/components/Todo/scripts/todoInteractions.ts +12 -12
- package/src/components/Todo/scripts/types.ts +3 -3
- package/src/components/Toggle/Toggle.stories.tsx +2 -2
- package/src/components/Toggle/Toggle.tsx +18 -18
- package/src/components/Toggle/index.ts +2 -2
- package/src/components/Toggle/scripts/bundle.ts +7 -2
- package/src/components/Toggle/scripts/index.ts +14 -10
- package/src/components/Toggle/scripts/toggleInteractions.ts +11 -14
- package/src/components/Tooltip/Tooltip.stories.tsx +13 -6
- package/src/components/Tooltip/Tooltip.tsx +25 -15
- package/src/components/Tooltip/index.ts +3 -3
- package/src/components/Tooltip/scripts/bundle.ts +0 -1
- package/src/components/Tooltip/scripts/index.ts +44 -41
- package/src/components/Tooltip/scripts/tooltipInteractions.ts +22 -22
- package/src/components/Upload/Upload.stories.tsx +28 -34
- package/src/components/Upload/Upload.tsx +86 -71
- package/src/components/Upload/index.ts +1 -1
- package/src/components/Upload/scripts/index.ts +58 -43
- package/src/components/index.ts +5 -6
- package/src/design-tokens/BoxShadow/BoxShadow.stories.tsx +13 -10
- package/src/design-tokens/Colors/colors.scss +10 -7
- package/src/design-tokens/Colors/colors.stories.tsx +46 -59
- package/src/design-tokens/Spacing/Spacing.scss +7 -5
- package/src/design-tokens/Spacing/Spacing.stories.tsx +19 -18
- package/src/design-tokens/Typography/Typography.scss +88 -25
- package/src/design-tokens/Typography/Typography.stories.tsx +22 -25
- package/src/docs/implementation-guide.mdx +2 -2
- package/src/htmlComponentsEntry.ts +23 -23
- package/src/index.ts +1 -1
- package/src/layouts/Grid/Container.tsx +6 -10
- package/src/layouts/Grid/Grid.stories.tsx +72 -34
- package/src/layouts/Grid/Grid.tsx +6 -13
- package/src/layouts/Grid/GridCol.tsx +29 -26
- package/src/layouts/Grid/Row.tsx +6 -13
- package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +79 -72
- package/src/layouts/MasonryGrid/MasonryGrid.tsx +23 -25
- package/src/layouts/MasonryGrid/MasonryGridItem.tsx +4 -12
- package/src/layouts/index.ts +3 -4
- package/src/lib/composables/index.ts +3 -3
- package/src/lib/composables/useAccordion.ts +15 -6
- package/src/lib/composables/useBadge.ts +3 -3
- package/src/lib/composables/useBreadcrumb.ts +6 -12
- package/src/lib/composables/useButton.ts +3 -3
- package/src/lib/composables/useCallout.ts +3 -3
- package/src/lib/composables/useCard.ts +50 -28
- package/src/lib/composables/useCheckbox.ts +7 -7
- package/src/lib/composables/useDataTable.ts +61 -57
- package/src/lib/composables/useDatePicker.ts +255 -231
- package/src/lib/composables/useDropdown.ts +90 -75
- package/src/lib/composables/useEdgePanel.ts +50 -47
- package/src/lib/composables/useForm.ts +4 -7
- package/src/lib/composables/useFormGroup.ts +11 -12
- package/src/lib/composables/useHero.ts +36 -38
- package/src/lib/composables/useInput.ts +9 -10
- package/src/lib/composables/useMessages.ts +12 -14
- package/src/lib/composables/useModal.ts +37 -34
- package/src/lib/composables/useNavbar.ts +33 -22
- package/src/lib/composables/usePagination.ts +3 -10
- package/src/lib/composables/usePhotoViewer.ts +625 -578
- package/src/lib/composables/usePopover.ts +68 -62
- package/src/lib/composables/useProgress.ts +9 -12
- package/src/lib/composables/useRadio.ts +4 -4
- package/src/lib/composables/useRating.ts +82 -70
- package/src/lib/composables/useRiver.ts +28 -31
- package/src/lib/composables/useSelect.ts +7 -8
- package/src/lib/composables/useSideMenu.ts +197 -0
- package/src/lib/composables/useSpinner.ts +3 -3
- package/src/lib/composables/useTextarea.ts +8 -9
- package/src/lib/composables/useTodo.ts +14 -18
- package/src/lib/constants/components.ts +191 -118
- package/src/lib/constants/index.ts +1 -1
- package/src/lib/types/components.ts +454 -324
- package/src/lib/utils/dom.ts +2 -6
- package/src/lib/utils/icons.ts +20 -12
- package/src/lib/utils/index.ts +2 -2
- package/src/lib/utils/useForkRef.ts +1 -2
- package/src/styles/01-settings/_index.scss +59 -59
- package/src/styles/01-settings/_settings.accordion.scss +21 -21
- package/src/styles/01-settings/_settings.animations.scss +2 -2
- package/src/styles/01-settings/_settings.avatar-group.scss +14 -14
- package/src/styles/01-settings/_settings.avatar.scss +31 -31
- package/src/styles/01-settings/_settings.badge.scss +11 -11
- package/src/styles/01-settings/_settings.border-radius.scss +10 -9
- package/src/styles/01-settings/_settings.border.scss +7 -7
- package/src/styles/01-settings/_settings.box-shadow.scss +24 -12
- package/src/styles/01-settings/_settings.breadcrumb.scss +18 -18
- package/src/styles/01-settings/_settings.btn-group.scss +1 -1
- package/src/styles/01-settings/_settings.button.scss +63 -49
- package/src/styles/01-settings/_settings.callout.scss +27 -7
- package/src/styles/01-settings/_settings.card.scss +27 -30
- package/src/styles/01-settings/_settings.checkbox-group.scss +2 -3
- package/src/styles/01-settings/_settings.checkbox.scss +17 -18
- package/src/styles/01-settings/_settings.color-mode.scss +1 -1
- package/src/styles/01-settings/_settings.colors.scss +197 -214
- package/src/styles/01-settings/_settings.config.scss +1 -3
- package/src/styles/01-settings/_settings.countdown.scss +14 -14
- package/src/styles/01-settings/_settings.data-table.scss +6 -6
- package/src/styles/01-settings/_settings.datepicker.scss +40 -42
- package/src/styles/01-settings/_settings.dropdown.scss +30 -30
- package/src/styles/01-settings/_settings.edge-panel.scss +16 -16
- package/src/styles/01-settings/_settings.fonts.scss +14 -12
- package/src/styles/01-settings/_settings.form-group.scss +10 -10
- package/src/styles/01-settings/_settings.form.scss +3 -3
- package/src/styles/01-settings/_settings.grid.scss +1 -1
- package/src/styles/01-settings/_settings.hero.scss +23 -23
- package/src/styles/01-settings/_settings.input.scss +32 -32
- package/src/styles/01-settings/_settings.link.scss +6 -6
- package/src/styles/01-settings/_settings.list-group.scss +12 -12
- package/src/styles/01-settings/_settings.list.scss +2 -2
- package/src/styles/01-settings/_settings.maps.scss +183 -188
- package/src/styles/01-settings/_settings.masonry-grid.scss +2 -2
- package/src/styles/01-settings/_settings.menu.scss +35 -38
- package/src/styles/01-settings/_settings.messages.scss +71 -77
- package/src/styles/01-settings/_settings.modal.scss +24 -24
- package/src/styles/01-settings/_settings.nav.scss +15 -15
- package/src/styles/01-settings/_settings.navbar.scss +39 -12
- package/src/styles/01-settings/_settings.pagination.scss +21 -21
- package/src/styles/01-settings/_settings.photoviewer.scss +1 -1
- package/src/styles/01-settings/_settings.popover.scss +3 -3
- package/src/styles/01-settings/_settings.position.scss +2 -2
- package/src/styles/01-settings/_settings.progress.scss +15 -18
- package/src/styles/01-settings/_settings.rating.scss +7 -7
- package/src/styles/01-settings/_settings.river.scss +25 -25
- package/src/styles/01-settings/_settings.sectionintro.scss +15 -16
- package/src/styles/01-settings/_settings.select.scss +31 -31
- package/src/styles/01-settings/_settings.side-menu.scss +64 -16
- package/src/styles/01-settings/_settings.skeleton.scss +12 -12
- package/src/styles/01-settings/_settings.spacing.scss +62 -33
- package/src/styles/01-settings/_settings.spinner.scss +10 -10
- package/src/styles/01-settings/_settings.steps.scss +22 -22
- package/src/styles/01-settings/_settings.tabs.scss +25 -25
- package/src/styles/01-settings/_settings.testimonials.scss +17 -19
- package/src/styles/01-settings/_settings.todo.scss +1 -1
- package/src/styles/01-settings/_settings.toggle.scss +26 -26
- package/src/styles/01-settings/_settings.tooltip.scss +15 -15
- package/src/styles/01-settings/_settings.typography.scss +65 -48
- package/src/styles/01-settings/_settings.upload.scss +70 -77
- package/src/styles/01-settings/_settings.z-layers.scss +1 -1
- package/src/styles/02-tools/_index.scss +19 -19
- package/src/styles/02-tools/_tools.animations.scss +4 -4
- package/src/styles/02-tools/_tools.border-radius.scss +4 -5
- package/src/styles/02-tools/_tools.breakpoints.scss +33 -34
- package/src/styles/02-tools/_tools.button.scss +49 -25
- package/src/styles/02-tools/_tools.color-mode.scss +11 -11
- package/src/styles/02-tools/_tools.event.scss +1 -1
- package/src/styles/02-tools/_tools.hidden-visually.scss +1 -1
- package/src/styles/02-tools/_tools.hidden.scss +1 -1
- package/src/styles/02-tools/_tools.map-loop.scss +9 -9
- package/src/styles/02-tools/_tools.media-queries.scss +5 -3
- package/src/styles/02-tools/_tools.object-fit.scss +3 -3
- package/src/styles/02-tools/_tools.placeholder.scss +0 -1
- package/src/styles/02-tools/_tools.rem.scss +1 -1
- package/src/styles/02-tools/_tools.spacing.scss +8 -34
- package/src/styles/02-tools/_tools.to-rgb.scss +3 -3
- package/src/styles/02-tools/_tools.transition.scss +1 -1
- package/src/styles/02-tools/_tools.utility-api.scss +29 -14
- package/src/styles/03-generic/_generic.fonts.scss +0 -1
- package/src/styles/03-generic/_generic.reset.scss +13 -8
- package/src/styles/03-generic/_generic.root.scss +5 -5
- package/src/styles/03-generic/_index.scss +4 -4
- package/src/styles/04-elements/_elements.all.scss +2 -2
- package/src/styles/04-elements/_elements.body.scss +1 -2
- package/src/styles/04-elements/_elements.heading.scss +37 -21
- package/src/styles/04-elements/_elements.links.scss +0 -1
- package/src/styles/04-elements/_index.scss +5 -5
- package/src/styles/05-objects/_index.scss +3 -3
- package/src/styles/05-objects/_objects.container.scss +5 -4
- package/src/styles/05-objects/_objects.grid.scss +12 -12
- package/src/styles/05-objects/_objects.masonry-grid.scss +80 -74
- package/src/styles/06-components/_components.accordion.scss +12 -6
- package/src/styles/06-components/_components.avatar-group.scss +9 -8
- package/src/styles/06-components/_components.avatar.scss +78 -77
- package/src/styles/06-components/_components.badge.scss +48 -48
- package/src/styles/06-components/_components.breadcrumb.scss +57 -58
- package/src/styles/06-components/_components.btn-group.scss +22 -22
- package/src/styles/06-components/_components.button.scss +118 -110
- package/src/styles/06-components/_components.callout.scss +21 -15
- package/src/styles/06-components/_components.card.scss +6 -10
- package/src/styles/06-components/_components.checkbox-group.scss +9 -10
- package/src/styles/06-components/_components.checkbox.scss +10 -17
- package/src/styles/06-components/_components.color-mode-toggle.scss +6 -6
- package/src/styles/06-components/_components.countdown.scss +53 -54
- package/src/styles/06-components/_components.data-table.scss +40 -36
- package/src/styles/06-components/_components.datepicker.scss +95 -73
- package/src/styles/06-components/_components.dropdown.scss +15 -9
- package/src/styles/06-components/_components.edge-panel.scss +87 -46
- package/src/styles/06-components/_components.form-group.scss +5 -4
- package/src/styles/06-components/_components.hero.scss +128 -132
- package/src/styles/06-components/_components.icon.scss +16 -16
- package/src/styles/06-components/_components.image-gallery.scss +9 -7
- package/src/styles/06-components/_components.input.scss +18 -16
- package/src/styles/06-components/_components.list-group.scss +52 -51
- package/src/styles/06-components/_components.list.scss +15 -15
- package/src/styles/06-components/_components.menu.scss +225 -220
- package/src/styles/06-components/_components.messages.scss +45 -32
- package/src/styles/06-components/_components.modal.scss +0 -1
- package/src/styles/06-components/_components.nav.scss +56 -11
- package/src/styles/06-components/_components.navbar.scss +278 -202
- package/src/styles/06-components/_components.pagination.scss +7 -6
- package/src/styles/06-components/_components.photoviewer.scss +121 -116
- package/src/styles/06-components/_components.popover.scss +10 -10
- package/src/styles/06-components/_components.product-review.scss +3 -3
- package/src/styles/06-components/_components.progress.scss +32 -35
- package/src/styles/06-components/_components.rating.scss +9 -8
- package/src/styles/06-components/_components.river.scss +4 -2
- package/src/styles/06-components/_components.sectionintro.scss +19 -26
- package/src/styles/06-components/_components.select.scss +7 -8
- package/src/styles/06-components/_components.side-menu.scss +154 -28
- package/src/styles/06-components/_components.skeleton.scss +0 -1
- package/src/styles/06-components/_components.spinner.scss +2 -4
- package/src/styles/06-components/_components.steps.scss +76 -77
- package/src/styles/06-components/_components.tabs.scss +17 -12
- package/src/styles/06-components/_components.testimonials.scss +49 -52
- package/src/styles/06-components/_components.todo.scss +26 -26
- package/src/styles/06-components/_components.tooltip.scss +114 -115
- package/src/styles/06-components/_components.upload.scss +8 -18
- package/src/styles/06-components/_index.scss +48 -48
- package/src/styles/99-utilities/_index.scss +18 -18
- package/src/styles/99-utilities/_utilities.background.scss +13 -13
- package/src/styles/99-utilities/_utilities.border.scss +30 -30
- package/src/styles/99-utilities/_utilities.clearfix.scss +1 -1
- package/src/styles/99-utilities/_utilities.display.scss +5 -4
- package/src/styles/99-utilities/_utilities.flex.scss +19 -19
- package/src/styles/99-utilities/_utilities.link.scss +52 -35
- package/src/styles/99-utilities/_utilities.object-fit.scss +3 -3
- package/src/styles/99-utilities/_utilities.opacity.scss +6 -6
- package/src/styles/99-utilities/_utilities.overflow.scss +4 -4
- package/src/styles/99-utilities/_utilities.position.scss +8 -8
- package/src/styles/99-utilities/_utilities.shadow.scss +13 -13
- package/src/styles/99-utilities/_utilities.sizes.scss +17 -17
- package/src/styles/99-utilities/_utilities.spacing.scss +72 -37
- package/src/styles/99-utilities/_utilities.text.scss +15 -15
- package/src/styles/99-utilities/_utilities.visibility.scss +8 -8
- package/src/styles/99-utilities/_utilities.visually-hidden.scss +1 -1
- package/src/styles/99-utilities/_utilities.z-index.scss +2 -2
- package/tsconfig.json +74 -0
- package/webpack.config.js +463 -0
- package/NPM_PUBLISHING.md +0 -221
- package/dist/css/atomix.css.map +0 -1
- package/dist/js/194.js.map +0 -1
- package/dist/js/atomix.react.esm.js.map +0 -1
- package/dist/js/atomix.react.umd.js.map +0 -1
- package/dist/js/chunks/esm/202.ff48d27672233280e021.js.map +0 -1
- package/dist/js/chunks/esm/308.f873332126eba90e5c62.js.map +0 -1
- package/dist/js/chunks/esm/54.4db919e5e4e5cc6d7c72.js.map +0 -1
- package/dist/js/chunks/esm/619.afc5a718eff77fa423b5.js.map +0 -1
- package/dist/js/chunks/esm/690.a9e968c7497d61e56cdc.js.map +0 -1
- package/dist/js/chunks/esm/894.f1091a4a8758c26d29e4.js.map +0 -1
- package/dist/js/chunks/esm/897.561a50f7d043d42169da.js.map +0 -1
- package/dist/js/chunks/umd/202.dac7605cc555b6bda542.js.map +0 -1
- package/dist/js/chunks/umd/308.6709979849dcbdb90c9b.js.map +0 -1
- package/dist/js/chunks/umd/54.403470e1f7d0ef4424a7.js.map +0 -1
- package/dist/js/chunks/umd/619.fa05ea98c10270eb64c5.js.map +0 -1
- package/dist/js/chunks/umd/690.aa7054d1c53e5402c2d6.js.map +0 -1
- package/dist/js/chunks/umd/894.3e1eaf0a2aadf4434390.js.map +0 -1
- package/dist/js/chunks/umd/897.554ea37be4453698c167.js.map +0 -1
- package/dist/types/components/Navbar/Nav.d.ts +0 -5
- package/dist/types/components/Navbar/NavItem.d.ts +0 -5
- package/dist/types/components/Navbar/Navbar.d.ts +0 -5
- package/dist/types/components/Navbar/index.d.ts +0 -6
- package/src/components/Navbar/Menu.tsx +0 -122
- package/src/components/Navbar/Nav.tsx +0 -35
- package/src/components/Navbar/NavDropdown.tsx +0 -108
- package/src/components/Navbar/NavItem.tsx +0 -128
- package/src/components/Navbar/Navbar.tsx +0 -124
- package/src/components/Navbar/index.ts +0 -6
|
@@ -20,12 +20,12 @@ interface ImageState {
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export const usePhotoViewer = ({
|
|
24
|
-
images,
|
|
25
|
-
startIndex = 0,
|
|
26
|
-
enableGestures = true,
|
|
27
|
-
onImageChange,
|
|
28
|
-
onClose
|
|
23
|
+
export const usePhotoViewer = ({
|
|
24
|
+
images,
|
|
25
|
+
startIndex = 0,
|
|
26
|
+
enableGestures = true,
|
|
27
|
+
onImageChange,
|
|
28
|
+
onClose,
|
|
29
29
|
}: UsePhotoViewerProps) => {
|
|
30
30
|
const [currentIndex, setCurrentIndex] = useState(startIndex);
|
|
31
31
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
@@ -37,11 +37,11 @@ export const usePhotoViewer = ({
|
|
|
37
37
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
38
38
|
const [isMounted, setIsMounted] = useState(false);
|
|
39
39
|
const [momentumZoom, setMomentumZoom] = useState({ velocity: 0, timestamp: 0 });
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
// Ref for the image element
|
|
42
42
|
const imageRef = useRef<HTMLImageElement>(null);
|
|
43
43
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
// Track touch points for pinch zoom
|
|
46
46
|
const touchPointsRef = useRef<{ x: number; y: number }[]>([]);
|
|
47
47
|
const lastDistanceRef = useRef<number | null>(null);
|
|
@@ -50,80 +50,86 @@ export const usePhotoViewer = ({
|
|
|
50
50
|
const momentumTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
51
51
|
|
|
52
52
|
// Calculate dragging bounds based on zoom level and image dimensions
|
|
53
|
-
const calculateBounds = useCallback(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
+
}
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Get natural image dimensions
|
|
67
|
-
const imageWidth = image.naturalWidth || image.width || 800;
|
|
68
|
-
const imageHeight = image.naturalHeight || image.height || 600;
|
|
69
|
-
|
|
70
|
-
// Get container dimensions with null check
|
|
71
|
-
try {
|
|
72
|
-
const containerRect = container.getBoundingClientRect();
|
|
73
|
-
if (!containerRect || containerRect.width === 0 || containerRect.height === 0) {
|
|
59
|
+
const image = imageRef.current;
|
|
60
|
+
const container = containerRef.current;
|
|
61
|
+
|
|
62
|
+
// Additional safety check for DOM readiness
|
|
63
|
+
if (!image.naturalWidth && !image.width) {
|
|
74
64
|
return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
|
|
75
65
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
+
);
|
|
119
122
|
|
|
120
123
|
// Constrain position within bounds
|
|
121
|
-
const constrainPosition = useCallback(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
+
);
|
|
127
133
|
|
|
128
134
|
// Mount tracking and ensure the current index is within bounds
|
|
129
135
|
useEffect(() => {
|
|
@@ -156,15 +162,15 @@ export const usePhotoViewer = ({
|
|
|
156
162
|
zoomLevel: 1,
|
|
157
163
|
position: { x: 0, y: 0 },
|
|
158
164
|
rotation: 0,
|
|
159
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
160
|
-
}
|
|
165
|
+
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
|
|
166
|
+
},
|
|
161
167
|
};
|
|
162
168
|
}
|
|
163
169
|
return prev;
|
|
164
170
|
});
|
|
165
171
|
}
|
|
166
172
|
}, [isModalOpen, currentIndex]);
|
|
167
|
-
|
|
173
|
+
|
|
168
174
|
// Call onImageChange callback when current index changes
|
|
169
175
|
useEffect(() => {
|
|
170
176
|
if (onImageChange) {
|
|
@@ -176,32 +182,32 @@ export const usePhotoViewer = ({
|
|
|
176
182
|
useEffect(() => {
|
|
177
183
|
const image = imageRef.current;
|
|
178
184
|
const container = containerRef.current;
|
|
179
|
-
|
|
185
|
+
|
|
180
186
|
const updateImageBounds = (): void => {
|
|
181
187
|
if (!isMounted || !image || !container) return undefined;
|
|
182
|
-
|
|
188
|
+
|
|
183
189
|
setImageStates(prev => {
|
|
184
190
|
const currentState = prev[currentIndex] || {
|
|
185
191
|
zoomLevel: 1,
|
|
186
192
|
position: { x: 0, y: 0 },
|
|
187
193
|
rotation: 0,
|
|
188
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
194
|
+
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
|
|
189
195
|
};
|
|
190
|
-
|
|
196
|
+
|
|
191
197
|
const newBounds = calculateBounds(currentState.zoomLevel, currentState.rotation);
|
|
192
198
|
const constrainedPosition = constrainPosition(currentState.position, newBounds);
|
|
193
|
-
|
|
199
|
+
|
|
194
200
|
return {
|
|
195
201
|
...prev,
|
|
196
202
|
[currentIndex]: {
|
|
197
203
|
...currentState,
|
|
198
204
|
bounds: newBounds,
|
|
199
|
-
position: constrainedPosition
|
|
200
|
-
}
|
|
205
|
+
position: constrainedPosition,
|
|
206
|
+
},
|
|
201
207
|
};
|
|
202
208
|
});
|
|
203
209
|
};
|
|
204
|
-
|
|
210
|
+
|
|
205
211
|
if (image && container && image.complete && isMounted) {
|
|
206
212
|
updateImageBounds();
|
|
207
213
|
return undefined;
|
|
@@ -216,29 +222,29 @@ export const usePhotoViewer = ({
|
|
|
216
222
|
useEffect(() => {
|
|
217
223
|
const handleResize = (): void => {
|
|
218
224
|
if (!isMounted || !imageRef.current || !containerRef.current) return undefined;
|
|
219
|
-
|
|
225
|
+
|
|
220
226
|
setImageStates(prev => {
|
|
221
227
|
const currentState = prev[currentIndex] || {
|
|
222
228
|
zoomLevel: 1,
|
|
223
229
|
position: { x: 0, y: 0 },
|
|
224
230
|
rotation: 0,
|
|
225
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
231
|
+
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
|
|
226
232
|
};
|
|
227
|
-
|
|
233
|
+
|
|
228
234
|
const newBounds = calculateBounds(currentState.zoomLevel, currentState.rotation);
|
|
229
235
|
const constrainedPosition = constrainPosition(currentState.position, newBounds);
|
|
230
|
-
|
|
236
|
+
|
|
231
237
|
return {
|
|
232
238
|
...prev,
|
|
233
239
|
[currentIndex]: {
|
|
234
240
|
...currentState,
|
|
235
241
|
bounds: newBounds,
|
|
236
|
-
position: constrainedPosition
|
|
237
|
-
}
|
|
242
|
+
position: constrainedPosition,
|
|
243
|
+
},
|
|
238
244
|
};
|
|
239
245
|
});
|
|
240
246
|
};
|
|
241
|
-
|
|
247
|
+
|
|
242
248
|
window.addEventListener('resize', handleResize);
|
|
243
249
|
return () => window.removeEventListener('resize', handleResize);
|
|
244
250
|
}, [currentIndex, calculateBounds, constrainPosition, isMounted]);
|
|
@@ -272,529 +278,570 @@ export const usePhotoViewer = ({
|
|
|
272
278
|
}
|
|
273
279
|
}, [currentIndex, images.length]);
|
|
274
280
|
|
|
275
|
-
const setZoomLevel = useCallback(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
+
);
|
|
350
371
|
|
|
351
372
|
// Handle mouse wheel for zooming with proper bounds
|
|
352
|
-
const handleWheel = useCallback(
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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
|
+
}
|
|
367
390
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
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;
|
|
399
432
|
shouldPreventDefault = true;
|
|
400
433
|
} else {
|
|
401
|
-
|
|
434
|
+
// Fallback for other input methods
|
|
435
|
+
zoomAmount = event.deltaY * -0.005;
|
|
436
|
+
shouldPreventDefault = true;
|
|
402
437
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
} else if (isRegularMouse) {
|
|
408
|
-
// Regular mouse wheel - medium sensitivity
|
|
409
|
-
zoomAmount = event.deltaY * -0.006;
|
|
410
|
-
shouldPreventDefault = true;
|
|
411
|
-
} else {
|
|
412
|
-
// Fallback for other input methods
|
|
413
|
-
zoomAmount = event.deltaY * -0.005;
|
|
414
|
-
shouldPreventDefault = true;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (shouldPreventDefault) {
|
|
418
|
-
event.preventDefault();
|
|
419
|
-
event.stopPropagation();
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Add momentum for trackpad gestures
|
|
423
|
-
const currentTime = Date.now();
|
|
424
|
-
const timeDelta = currentTime - lastWheelTime.current;
|
|
425
|
-
lastWheelTime.current = currentTime;
|
|
426
|
-
|
|
427
|
-
// Calculate velocity for momentum (trackpad specific)
|
|
428
|
-
if (isTrackpadPinch && timeDelta < 100) {
|
|
429
|
-
const velocity = Math.abs(zoomAmount) / timeDelta;
|
|
430
|
-
setMomentumZoom({ velocity, timestamp: currentTime });
|
|
431
|
-
|
|
432
|
-
// Clear any existing momentum timeout
|
|
433
|
-
if (momentumTimeoutRef.current) {
|
|
434
|
-
clearTimeout(momentumTimeoutRef.current);
|
|
438
|
+
|
|
439
|
+
if (shouldPreventDefault) {
|
|
440
|
+
event.preventDefault();
|
|
441
|
+
event.stopPropagation();
|
|
435
442
|
}
|
|
436
|
-
|
|
437
|
-
//
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
if (
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
[currentIndex]
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
472
|
-
|
|
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() };
|
|
473
502
|
});
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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,
|
|
481
536
|
};
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
+
}
|
|
493
550
|
return prev;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
y: currentState.position.y + cursorY * (1 - zoomFactor) * 0.5
|
|
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 },
|
|
514
570
|
};
|
|
515
|
-
|
|
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);
|
|
516
609
|
const constrainedPosition = constrainPosition(newPosition, newBounds);
|
|
517
|
-
|
|
610
|
+
|
|
518
611
|
return {
|
|
519
612
|
...prev,
|
|
520
613
|
[currentIndex]: {
|
|
521
614
|
...currentState,
|
|
522
615
|
zoomLevel: newZoom,
|
|
523
616
|
bounds: newBounds,
|
|
524
|
-
position: constrainedPosition
|
|
525
|
-
}
|
|
617
|
+
position: constrainedPosition,
|
|
618
|
+
},
|
|
526
619
|
};
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
620
|
+
});
|
|
621
|
+
},
|
|
622
|
+
[isMounted, currentIndex, calculateBounds, constrainPosition]
|
|
623
|
+
);
|
|
531
624
|
|
|
532
|
-
// Handle
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
console.warn('PhotoViewer: Error getting bounding rect in double click', error);
|
|
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
|
+
}
|
|
552
644
|
return prev;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
x: -cursorX * 0.5,
|
|
570
|
-
y: -cursorY * 0.5
|
|
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 },
|
|
571
661
|
};
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
y: -cursorY * 0.75
|
|
662
|
+
|
|
663
|
+
const newPosition = {
|
|
664
|
+
x: event.clientX - startDragPosition.x,
|
|
665
|
+
y: event.clientY - startDragPosition.y,
|
|
577
666
|
};
|
|
578
|
-
} else {
|
|
579
|
-
newZoom = 1;
|
|
580
|
-
newPosition = { x: 0, y: 0 };
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
const newBounds = calculateBounds(newZoom, currentState.rotation);
|
|
584
|
-
const constrainedPosition = constrainPosition(newPosition, newBounds);
|
|
585
|
-
|
|
586
|
-
return {
|
|
587
|
-
...prev,
|
|
588
|
-
[currentIndex]: {
|
|
589
|
-
...currentState,
|
|
590
|
-
zoomLevel: newZoom,
|
|
591
|
-
bounds: newBounds,
|
|
592
|
-
position: constrainedPosition
|
|
593
|
-
}
|
|
594
|
-
};
|
|
595
|
-
});
|
|
596
|
-
}, [isMounted, currentIndex, calculateBounds, constrainPosition]);
|
|
597
667
|
|
|
598
|
-
|
|
599
|
-
const handleMouseDown = useCallback((event: React.MouseEvent<HTMLDivElement | HTMLImageElement, MouseEvent>) => {
|
|
600
|
-
setImageStates(prev => {
|
|
601
|
-
const currentState = prev[currentIndex] || {
|
|
602
|
-
zoomLevel: 1,
|
|
603
|
-
position: { x: 0, y: 0 },
|
|
604
|
-
rotation: 0,
|
|
605
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
606
|
-
};
|
|
607
|
-
|
|
608
|
-
if (currentState.zoomLevel > 1) {
|
|
609
|
-
event.preventDefault();
|
|
610
|
-
setIsDragging(true);
|
|
611
|
-
setStartDragPosition({
|
|
612
|
-
x: event.clientX - currentState.position.x,
|
|
613
|
-
y: event.clientY - currentState.position.y
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
return prev;
|
|
617
|
-
});
|
|
618
|
-
}, [currentIndex]);
|
|
668
|
+
const constrainedPosition = constrainPosition(newPosition, currentState.bounds);
|
|
619
669
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const newPosition = {
|
|
633
|
-
x: event.clientX - startDragPosition.x,
|
|
634
|
-
y: event.clientY - startDragPosition.y
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
const constrainedPosition = constrainPosition(newPosition, currentState.bounds);
|
|
638
|
-
|
|
639
|
-
return {
|
|
640
|
-
...prev,
|
|
641
|
-
[currentIndex]: {
|
|
642
|
-
...currentState,
|
|
643
|
-
position: constrainedPosition
|
|
644
|
-
}
|
|
645
|
-
};
|
|
646
|
-
});
|
|
647
|
-
}, [isDragging, startDragPosition, currentIndex, constrainPosition]);
|
|
670
|
+
return {
|
|
671
|
+
...prev,
|
|
672
|
+
[currentIndex]: {
|
|
673
|
+
...currentState,
|
|
674
|
+
position: constrainedPosition,
|
|
675
|
+
},
|
|
676
|
+
};
|
|
677
|
+
});
|
|
678
|
+
},
|
|
679
|
+
[isDragging, startDragPosition, currentIndex, constrainPosition]
|
|
680
|
+
);
|
|
648
681
|
|
|
649
682
|
// Handle mouse up for panning
|
|
650
683
|
const handleMouseUp = useCallback(() => {
|
|
651
684
|
setIsDragging(false);
|
|
652
685
|
}, []);
|
|
653
|
-
|
|
686
|
+
|
|
654
687
|
// Touch handlers for mobile gestures with bounds
|
|
655
|
-
const handleTouchStart = useCallback(
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
touchPointsRef.current = Array.from(touches).map(touch => ({
|
|
667
|
-
x: touch.clientX,
|
|
668
|
-
y: touch.clientY
|
|
669
|
-
}));
|
|
670
|
-
|
|
671
|
-
setImageStates(prev => {
|
|
672
|
-
const currentState = prev[currentIndex] || {
|
|
673
|
-
zoomLevel: 1,
|
|
674
|
-
position: { x: 0, y: 0 },
|
|
675
|
-
rotation: 0,
|
|
676
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
677
|
-
};
|
|
678
|
-
|
|
679
|
-
if (touches.length === 1 && currentState.zoomLevel > 1) {
|
|
680
|
-
setIsDragging(true);
|
|
681
|
-
setStartDragPosition({
|
|
682
|
-
x: touches[0].clientX - currentState.position.x,
|
|
683
|
-
y: touches[0].clientY - currentState.position.y
|
|
684
|
-
});
|
|
685
|
-
} else if (touches.length === 2) {
|
|
686
|
-
const dx = touches[0].clientX - touches[1].clientX;
|
|
687
|
-
const dy = touches[0].clientY - touches[1].clientY;
|
|
688
|
-
lastDistanceRef.current = Math.sqrt(dx * dx + dy * dy);
|
|
689
|
-
|
|
690
|
-
lastMidpointRef.current = {
|
|
691
|
-
x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
692
|
-
y: (touches[0].clientY + touches[1].clientY) / 2
|
|
693
|
-
};
|
|
688
|
+
const handleTouchStart = useCallback(
|
|
689
|
+
(event: React.TouchEvent<HTMLImageElement | HTMLDivElement>) => {
|
|
690
|
+
if (!enableGestures) return;
|
|
691
|
+
|
|
692
|
+
const touches = event.touches;
|
|
693
|
+
|
|
694
|
+
// Always prevent default for multi-touch to stop page zoom
|
|
695
|
+
if (touches.length > 1) {
|
|
696
|
+
event.preventDefault();
|
|
697
|
+
event.stopPropagation();
|
|
694
698
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
699
|
+
|
|
700
|
+
touchPointsRef.current = Array.from(touches).map(touch => ({
|
|
701
|
+
x: touch.clientX,
|
|
702
|
+
y: touch.clientY,
|
|
703
|
+
}));
|
|
704
|
+
|
|
705
|
+
setImageStates(prev => {
|
|
706
|
+
const currentState = prev[currentIndex] || {
|
|
707
|
+
zoomLevel: 1,
|
|
708
|
+
position: { x: 0, y: 0 },
|
|
709
|
+
rotation: 0,
|
|
710
|
+
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
if (touches.length === 1 && currentState.zoomLevel > 1) {
|
|
714
|
+
setIsDragging(true);
|
|
715
|
+
setStartDragPosition({
|
|
716
|
+
x: touches[0].clientX - currentState.position.x,
|
|
717
|
+
y: touches[0].clientY - currentState.position.y,
|
|
718
|
+
});
|
|
719
|
+
} else if (touches.length === 2) {
|
|
720
|
+
const dx = touches[0].clientX - touches[1].clientX;
|
|
721
|
+
const dy = touches[0].clientY - touches[1].clientY;
|
|
722
|
+
lastDistanceRef.current = Math.sqrt(dx * dx + dy * dy);
|
|
723
|
+
|
|
724
|
+
lastMidpointRef.current = {
|
|
725
|
+
x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
726
|
+
y: (touches[0].clientY + touches[1].clientY) / 2,
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
return prev;
|
|
730
|
+
});
|
|
731
|
+
},
|
|
732
|
+
[enableGestures, currentIndex]
|
|
733
|
+
);
|
|
698
734
|
|
|
699
735
|
// Handle touch move for dragging and pinch zoom with bounds
|
|
700
|
-
const handleTouchMove = useCallback(
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
event.stopPropagation();
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
setImageStates(prev => {
|
|
712
|
-
const currentState = prev[currentIndex] || {
|
|
713
|
-
zoomLevel: 1,
|
|
714
|
-
position: { x: 0, y: 0 },
|
|
715
|
-
rotation: 0,
|
|
716
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
// Prevent default for single touch when zoomed in to avoid conflicts
|
|
720
|
-
if (currentState.zoomLevel > 1 && touches.length === 1) {
|
|
736
|
+
const handleTouchMove = useCallback(
|
|
737
|
+
(event: React.TouchEvent<HTMLImageElement | HTMLDivElement>) => {
|
|
738
|
+
if (!enableGestures) return;
|
|
739
|
+
|
|
740
|
+
const touches = event.touches;
|
|
741
|
+
|
|
742
|
+
// Always prevent default for multi-touch gestures to stop page zoom
|
|
743
|
+
if (touches.length > 1) {
|
|
721
744
|
event.preventDefault();
|
|
745
|
+
event.stopPropagation();
|
|
722
746
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
y:
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
return {
|
|
732
|
-
...prev,
|
|
733
|
-
[currentIndex]: {
|
|
734
|
-
...currentState,
|
|
735
|
-
position: constrainedPosition
|
|
736
|
-
}
|
|
737
|
-
};
|
|
738
|
-
} else if (touches.length === 2 && lastDistanceRef.current !== null) {
|
|
739
|
-
const dx = touches[0].clientX - touches[1].clientX;
|
|
740
|
-
const dy = touches[0].clientY - touches[1].clientY;
|
|
741
|
-
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
742
|
-
|
|
743
|
-
const zoomDelta = (distance - lastDistanceRef.current) * 0.005;
|
|
744
|
-
lastDistanceRef.current = distance;
|
|
745
|
-
|
|
746
|
-
const currentMidpoint = {
|
|
747
|
-
x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
748
|
-
y: (touches[0].clientY + touches[1].clientY) / 2
|
|
747
|
+
|
|
748
|
+
setImageStates(prev => {
|
|
749
|
+
const currentState = prev[currentIndex] || {
|
|
750
|
+
zoomLevel: 1,
|
|
751
|
+
position: { x: 0, y: 0 },
|
|
752
|
+
rotation: 0,
|
|
753
|
+
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
|
|
749
754
|
};
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
rect = event.currentTarget.getBoundingClientRect();
|
|
758
|
-
} catch (error) {
|
|
759
|
-
console.warn('PhotoViewer: Error getting bounding rect in touch move', error);
|
|
760
|
-
return prev;
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (!rect || rect.width === 0 || rect.height === 0) return prev;
|
|
764
|
-
|
|
765
|
-
const centerX = rect.width / 2;
|
|
766
|
-
const centerY = rect.height / 2;
|
|
767
|
-
const midpointX = currentMidpoint.x - rect.left - centerX;
|
|
768
|
-
const midpointY = currentMidpoint.y - rect.top - centerY;
|
|
769
|
-
|
|
770
|
-
const zoomFactor = newZoom / oldZoom;
|
|
771
|
-
const newBounds = calculateBounds(newZoom, currentState.rotation);
|
|
772
|
-
|
|
755
|
+
|
|
756
|
+
// Prevent default for single touch when zoomed in to avoid conflicts
|
|
757
|
+
if (currentState.zoomLevel > 1 && touches.length === 1) {
|
|
758
|
+
event.preventDefault();
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (touches.length === 1 && isDragging && currentState.zoomLevel > 1) {
|
|
773
762
|
const newPosition = {
|
|
774
|
-
x:
|
|
775
|
-
y:
|
|
763
|
+
x: touches[0].clientX - startDragPosition.x,
|
|
764
|
+
y: touches[0].clientY - startDragPosition.y,
|
|
776
765
|
};
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
lastMidpointRef.current = currentMidpoint;
|
|
781
|
-
|
|
766
|
+
const constrainedPosition = constrainPosition(newPosition, currentState.bounds);
|
|
767
|
+
|
|
782
768
|
return {
|
|
783
769
|
...prev,
|
|
784
770
|
[currentIndex]: {
|
|
785
771
|
...currentState,
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
position: constrainedPosition
|
|
789
|
-
}
|
|
772
|
+
position: constrainedPosition,
|
|
773
|
+
},
|
|
790
774
|
};
|
|
775
|
+
} else if (touches.length === 2 && lastDistanceRef.current !== null) {
|
|
776
|
+
const dx = touches[0].clientX - touches[1].clientX;
|
|
777
|
+
const dy = touches[0].clientY - touches[1].clientY;
|
|
778
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
779
|
+
|
|
780
|
+
const zoomDelta = (distance - lastDistanceRef.current) * 0.005;
|
|
781
|
+
lastDistanceRef.current = distance;
|
|
782
|
+
|
|
783
|
+
const currentMidpoint = {
|
|
784
|
+
x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
785
|
+
y: (touches[0].clientY + touches[1].clientY) / 2,
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
const oldZoom = currentState.zoomLevel;
|
|
789
|
+
const newZoom = Math.max(0.1, Math.min(5, oldZoom + zoomDelta));
|
|
790
|
+
|
|
791
|
+
if (newZoom !== oldZoom && lastMidpointRef.current) {
|
|
792
|
+
let rect;
|
|
793
|
+
try {
|
|
794
|
+
rect = event.currentTarget.getBoundingClientRect();
|
|
795
|
+
} catch (error) {
|
|
796
|
+
console.warn('PhotoViewer: Error getting bounding rect in touch move', error);
|
|
797
|
+
return prev;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
if (!rect || rect.width === 0 || rect.height === 0) return prev;
|
|
801
|
+
|
|
802
|
+
const centerX = rect.width / 2;
|
|
803
|
+
const centerY = rect.height / 2;
|
|
804
|
+
const midpointX = currentMidpoint.x - rect.left - centerX;
|
|
805
|
+
const midpointY = currentMidpoint.y - rect.top - centerY;
|
|
806
|
+
|
|
807
|
+
const zoomFactor = newZoom / oldZoom;
|
|
808
|
+
const newBounds = calculateBounds(newZoom, currentState.rotation);
|
|
809
|
+
|
|
810
|
+
const newPosition = {
|
|
811
|
+
x: currentState.position.x + midpointX * (1 - zoomFactor) * 0.5,
|
|
812
|
+
y: currentState.position.y + midpointY * (1 - zoomFactor) * 0.5,
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
const constrainedPosition = constrainPosition(newPosition, newBounds);
|
|
816
|
+
|
|
817
|
+
lastMidpointRef.current = currentMidpoint;
|
|
818
|
+
|
|
819
|
+
return {
|
|
820
|
+
...prev,
|
|
821
|
+
[currentIndex]: {
|
|
822
|
+
...currentState,
|
|
823
|
+
zoomLevel: newZoom,
|
|
824
|
+
bounds: newBounds,
|
|
825
|
+
position: constrainedPosition,
|
|
826
|
+
},
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
lastMidpointRef.current = currentMidpoint;
|
|
791
831
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
832
|
+
return prev;
|
|
833
|
+
});
|
|
834
|
+
},
|
|
835
|
+
[
|
|
836
|
+
isMounted,
|
|
837
|
+
enableGestures,
|
|
838
|
+
isDragging,
|
|
839
|
+
startDragPosition,
|
|
840
|
+
currentIndex,
|
|
841
|
+
constrainPosition,
|
|
842
|
+
calculateBounds,
|
|
843
|
+
]
|
|
844
|
+
);
|
|
798
845
|
|
|
799
846
|
// Handle touch end
|
|
800
847
|
const handleTouchEnd = useCallback(() => {
|
|
@@ -808,7 +855,7 @@ export const usePhotoViewer = ({
|
|
|
808
855
|
zoomLevel: 1,
|
|
809
856
|
position: { x: 0, y: 0 },
|
|
810
857
|
rotation: 0,
|
|
811
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
858
|
+
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
|
|
812
859
|
};
|
|
813
860
|
|
|
814
861
|
return {
|
|
@@ -849,9 +896,9 @@ export const usePhotoViewer = ({
|
|
|
849
896
|
zoomLevel: 1,
|
|
850
897
|
position: { x: 0, y: 0 },
|
|
851
898
|
rotation: 0,
|
|
852
|
-
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 }
|
|
853
|
-
}
|
|
899
|
+
bounds: { minX: 0, maxX: 0, minY: 0, maxY: 0 },
|
|
900
|
+
},
|
|
854
901
|
}));
|
|
855
|
-
}
|
|
902
|
+
},
|
|
856
903
|
};
|
|
857
|
-
};
|
|
904
|
+
};
|