@comitor/ui 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -24
- package/dist/chart/chart.d.ts +6 -1
- package/dist/chart/chart.js +3 -1
- package/dist/chart/chart.js.map +1 -1
- package/dist/chart/comitor-chart.d.ts +4 -1
- package/dist/chart/comitor-chart.js +3 -1
- package/dist/chart/comitor-chart.js.map +1 -1
- package/dist/components/composite/avatar-group.d.ts +9 -6
- package/dist/components/composite/avatar-group.js +6 -2
- package/dist/components/composite/avatar-group.js.map +1 -1
- package/dist/components/composite/combobox.d.ts +11 -11
- package/dist/components/composite/combobox.js +25 -11
- package/dist/components/composite/combobox.js.map +1 -1
- package/dist/components/composite/command-palette-constants.d.ts +15 -5
- package/dist/components/composite/command-palette-constants.js +3 -2
- package/dist/components/composite/command-palette-constants.js.map +1 -1
- package/dist/components/composite/command-palette.d.ts +2 -2
- package/dist/components/composite/command-palette.js +8 -5
- package/dist/components/composite/command-palette.js.map +1 -1
- package/dist/components/composite/confirm-dialog.d.ts +8 -8
- package/dist/components/composite/confirm-dialog.js +8 -3
- package/dist/components/composite/confirm-dialog.js.map +1 -1
- package/dist/components/composite/copy-button.d.ts +7 -3
- package/dist/components/composite/copy-button.js +7 -3
- package/dist/components/composite/copy-button.js.map +1 -1
- package/dist/components/composite/data-table-constants.d.ts +7 -3
- package/dist/components/composite/data-table-constants.js +2 -9
- package/dist/components/composite/data-table-constants.js.map +1 -1
- package/dist/components/composite/data-table.js +3 -3
- package/dist/components/composite/data-table.js.map +1 -1
- package/dist/components/composite/date-picker-constants.d.ts +32 -9
- package/dist/components/composite/date-picker-constants.js +16 -11
- package/dist/components/composite/date-picker-constants.js.map +1 -1
- package/dist/components/composite/date-picker.d.ts +19 -10
- package/dist/components/composite/date-picker.js +33 -9
- package/dist/components/composite/date-picker.js.map +1 -1
- package/dist/components/composite/filter-chips.d.ts +4 -3
- package/dist/components/composite/filter-chips.js +6 -2
- package/dist/components/composite/filter-chips.js.map +1 -1
- package/dist/components/composite/inline-edit.d.ts +14 -3
- package/dist/components/composite/inline-edit.js +8 -4
- package/dist/components/composite/inline-edit.js.map +1 -1
- package/dist/components/composite/relative-time.d.ts +4 -4
- package/dist/components/composite/relative-time.js +4 -2
- package/dist/components/composite/relative-time.js.map +1 -1
- package/dist/components/composite/route-tabs-nav.d.ts +9 -0
- package/dist/components/composite/route-tabs-nav.js +11 -0
- package/dist/components/composite/route-tabs-nav.js.map +1 -0
- package/dist/components/composite/route-tabs.d.ts +4 -1
- package/dist/components/composite/route-tabs.js +3 -2
- package/dist/components/composite/route-tabs.js.map +1 -1
- package/dist/components/composite/search-filter-bar-constants.d.ts +18 -8
- package/dist/components/composite/search-filter-bar-constants.js +2 -14
- package/dist/components/composite/search-filter-bar-constants.js.map +1 -1
- package/dist/components/composite/search-filter-bar.d.ts +5 -2
- package/dist/components/composite/search-filter-bar.js +2 -2
- package/dist/components/composite/search-filter-bar.js.map +1 -1
- package/dist/components/composite/stat-card.d.ts +1 -1
- package/dist/components/composite/table-pagination-constants.d.ts +16 -11
- package/dist/components/composite/table-pagination-constants.js +2 -12
- package/dist/components/composite/table-pagination-constants.js.map +1 -1
- package/dist/components/composite/table-pagination.d.ts +6 -3
- package/dist/components/composite/table-pagination.js +3 -5
- package/dist/components/composite/table-pagination.js.map +1 -1
- package/dist/components/composite/toast.d.ts +4 -2
- package/dist/components/composite/toast.js +9 -1
- package/dist/components/composite/toast.js.map +1 -1
- package/dist/components/ui/action-bar-constants.d.ts +8 -4
- package/dist/components/ui/action-bar-constants.js +2 -5
- package/dist/components/ui/action-bar-constants.js.map +1 -1
- package/dist/components/ui/action-bar.d.ts +5 -4
- package/dist/components/ui/action-bar.js +2 -2
- package/dist/components/ui/action-bar.js.map +1 -1
- package/dist/components/ui/alert.d.ts +1 -1
- package/dist/components/ui/badge-overflow.d.ts +2 -2
- package/dist/components/ui/badge-overflow.js +4 -2
- package/dist/components/ui/badge-overflow.js.map +1 -1
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/components/ui/banner.d.ts +6 -5
- package/dist/components/ui/banner.js +3 -1
- package/dist/components/ui/banner.js.map +1 -1
- package/dist/components/ui/breadcrumb.d.ts +11 -4
- package/dist/components/ui/breadcrumb.js +7 -2
- package/dist/components/ui/breadcrumb.js.map +1 -1
- package/dist/components/ui/button.d.ts +2 -2
- package/dist/components/ui/calendar.d.ts +12 -5
- package/dist/components/ui/calendar.js +38 -3
- package/dist/components/ui/calendar.js.map +1 -1
- package/dist/components/ui/carousel.d.ts +4 -3
- package/dist/components/ui/carousel.js +11 -4
- package/dist/components/ui/carousel.js.map +1 -1
- package/dist/components/ui/circular-progress.js.map +1 -1
- package/dist/components/ui/command.d.ts +5 -4
- package/dist/components/ui/command.js +6 -2
- package/dist/components/ui/command.js.map +1 -1
- package/dist/components/ui/cropper-constants.d.ts +8 -3
- package/dist/components/ui/cropper-constants.js +2 -6
- package/dist/components/ui/cropper-constants.js.map +1 -1
- package/dist/components/ui/cropper.d.ts +2 -1
- package/dist/components/ui/cropper.js +2 -2
- package/dist/components/ui/cropper.js.map +1 -1
- package/dist/components/ui/dialog.d.ts +2 -2
- package/dist/components/ui/dialog.js +4 -1
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/components/ui/item.d.ts +2 -2
- package/dist/components/ui/kanban-constants.d.ts +7 -1
- package/dist/components/ui/kanban-constants.js +2 -17
- package/dist/components/ui/kanban-constants.js.map +1 -1
- package/dist/components/ui/kanban.d.ts +2 -2
- package/dist/components/ui/kanban.js +2 -2
- package/dist/components/ui/kanban.js.map +1 -1
- package/dist/components/ui/key-value-constants.d.ts +7 -3
- package/dist/components/ui/key-value-constants.js +2 -7
- package/dist/components/ui/key-value-constants.js.map +1 -1
- package/dist/components/ui/key-value.d.ts +5 -5
- package/dist/components/ui/key-value.js +2 -2
- package/dist/components/ui/key-value.js.map +1 -1
- package/dist/components/ui/mask-input-constants.d.ts +2 -3
- package/dist/components/ui/mask-input-constants.js +5 -6
- package/dist/components/ui/mask-input-constants.js.map +1 -1
- package/dist/components/ui/mask-input.d.ts +7 -4
- package/dist/components/ui/mask-input.js +4 -2
- package/dist/components/ui/mask-input.js.map +1 -1
- package/dist/components/ui/mention.d.ts +3 -2
- package/dist/components/ui/mention.js +4 -6
- package/dist/components/ui/mention.js.map +1 -1
- package/dist/components/ui/pagination.d.ts +13 -9
- package/dist/components/ui/pagination.js +15 -6
- package/dist/components/ui/pagination.js.map +1 -1
- package/dist/components/ui/phone-input-constants.d.ts +17 -6
- package/dist/components/ui/phone-input-constants.js +2 -5
- package/dist/components/ui/phone-input-constants.js.map +1 -1
- package/dist/components/ui/phone-input.d.ts +18 -11
- package/dist/components/ui/phone-input.js +9 -10
- package/dist/components/ui/phone-input.js.map +1 -1
- package/dist/components/ui/progress.d.ts +2 -2
- package/dist/components/ui/rating.d.ts +2 -1
- package/dist/components/ui/rating.js +4 -2
- package/dist/components/ui/rating.js.map +1 -1
- package/dist/components/ui/scroll-spy.js +3 -1
- package/dist/components/ui/scroll-spy.js.map +1 -1
- package/dist/components/ui/sheet.d.ts +2 -2
- package/dist/components/ui/sheet.js +10 -1
- package/dist/components/ui/sheet.js.map +1 -1
- package/dist/components/ui/spinner.js +4 -1
- package/dist/components/ui/spinner.js.map +1 -1
- package/dist/components/ui/stepper-constants.d.ts +7 -2
- package/dist/components/ui/stepper-constants.js +2 -5
- package/dist/components/ui/stepper-constants.js.map +1 -1
- package/dist/components/ui/stepper.d.ts +2 -1
- package/dist/components/ui/stepper.js +2 -2
- package/dist/components/ui/stepper.js.map +1 -1
- package/dist/components/ui/tags-input.d.ts +3 -2
- package/dist/components/ui/tags-input.js +4 -2
- package/dist/components/ui/tags-input.js.map +1 -1
- package/dist/components/ui/time-picker-constants.d.ts +12 -9
- package/dist/components/ui/time-picker-constants.js +2 -10
- package/dist/components/ui/time-picker-constants.js.map +1 -1
- package/dist/components/ui/time-picker.d.ts +11 -6
- package/dist/components/ui/time-picker.js +5 -7
- package/dist/components/ui/time-picker.js.map +1 -1
- package/dist/components/ui/toggle.d.ts +1 -1
- package/dist/components/ui/tour-constants.d.ts +7 -2
- package/dist/components/ui/tour-constants.js +2 -8
- package/dist/components/ui/tour-constants.js.map +1 -1
- package/dist/components/ui/tour.d.ts +3 -2
- package/dist/components/ui/tour.js +2 -2
- package/dist/components/ui/tour.js.map +1 -1
- package/dist/data-grid/data-grid-cell-variants.js +4 -4
- package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
- package/dist/data-grid/data-grid-column-header.js +1 -1
- package/dist/data-grid/data-grid-column-header.js.map +1 -1
- package/dist/data-grid/data-grid-filter-menu.d.ts +5 -4
- package/dist/data-grid/data-grid-filter-menu.js +13 -8
- package/dist/data-grid/data-grid-filter-menu.js.map +1 -1
- package/dist/data-grid/data-grid-keyboard-shortcuts.d.ts +4 -4
- package/dist/data-grid/data-grid-keyboard-shortcuts.js.map +1 -1
- package/dist/data-grid/data-grid-locale.d.ts +58 -6
- package/dist/data-grid/data-grid-locale.js +41 -9
- package/dist/data-grid/data-grid-locale.js.map +1 -1
- package/dist/data-grid/data-grid-row-height-menu.d.ts +4 -3
- package/dist/data-grid/data-grid-row-height-menu.js.map +1 -1
- package/dist/data-grid/data-grid-sort-menu.d.ts +4 -4
- package/dist/data-grid/data-grid-sort-menu.js +1 -1
- package/dist/data-grid/data-grid-sort-menu.js.map +1 -1
- package/dist/data-grid/data-grid-view-menu.d.ts +4 -4
- package/dist/data-grid/data-grid-view-menu.js.map +1 -1
- package/dist/data-grid/data-grid.d.ts +4 -3
- package/dist/data-grid/data-grid.js +2 -3
- package/dist/data-grid/data-grid.js.map +1 -1
- package/dist/data-grid/index.d.ts +1 -0
- package/dist/data-grid/index.js.map +1 -1
- package/dist/data-grid/messages-en.d.ts +23 -4
- package/dist/data-grid/messages-en.js +20 -0
- package/dist/data-grid/messages-en.js.map +1 -1
- package/dist/data-grid/messages-vi.d.ts +3 -1
- package/dist/data-grid/messages-vi.js +14 -0
- package/dist/data-grid/messages-vi.js.map +1 -1
- package/dist/data-grid/messages.d.ts +29 -3
- package/dist/data-grid/messages.js.map +1 -1
- package/dist/data-grid/sortable.js +16 -19
- package/dist/data-grid/sortable.js.map +1 -1
- package/dist/data-grid/types.d.ts +1 -1
- package/dist/data-grid/use-data-grid-undo-redo.d.ts +5 -4
- package/dist/data-grid/use-data-grid-undo-redo.js +2 -2
- package/dist/data-grid/use-data-grid-undo-redo.js.map +1 -1
- package/dist/data-grid/use-data-grid.d.ts +21 -6
- package/dist/data-grid/use-data-grid.js +8 -6
- package/dist/data-grid/use-data-grid.js.map +1 -1
- package/dist/data-grid/utils.d.ts +24 -4
- package/dist/data-grid/utils.js +15 -5
- package/dist/data-grid/utils.js.map +1 -1
- package/dist/i18n/locale-provider.d.ts +109 -0
- package/dist/i18n/locale-provider.js +47 -0
- package/dist/i18n/locale-provider.js.map +1 -0
- package/dist/i18n/locale.d.ts +27 -0
- package/dist/i18n/locale.js +10 -0
- package/dist/i18n/locale.js.map +1 -0
- package/dist/i18n/messages.d.ts +116 -0
- package/dist/i18n/messages.js +149 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/i18n/namespaces/action-bar.d.ts +7 -0
- package/dist/i18n/namespaces/action-bar.js +15 -0
- package/dist/i18n/namespaces/action-bar.js.map +1 -0
- package/dist/i18n/namespaces/avatar-group.d.ts +14 -0
- package/dist/i18n/namespaces/avatar-group.js +13 -0
- package/dist/i18n/namespaces/avatar-group.js.map +1 -0
- package/dist/i18n/namespaces/badge-overflow.d.ts +12 -0
- package/dist/i18n/namespaces/badge-overflow.js +11 -0
- package/dist/i18n/namespaces/badge-overflow.js.map +1 -0
- package/dist/i18n/namespaces/banner.d.ts +9 -0
- package/dist/i18n/namespaces/banner.js +7 -0
- package/dist/i18n/namespaces/banner.js.map +1 -0
- package/dist/i18n/namespaces/breadcrumb.d.ts +11 -0
- package/dist/i18n/namespaces/breadcrumb.js +13 -0
- package/dist/i18n/namespaces/breadcrumb.js.map +1 -0
- package/dist/i18n/namespaces/calendar.d.ts +40 -0
- package/dist/i18n/namespaces/calendar.js +25 -0
- package/dist/i18n/namespaces/calendar.js.map +1 -0
- package/dist/i18n/namespaces/carousel.d.ts +15 -0
- package/dist/i18n/namespaces/carousel.js +17 -0
- package/dist/i18n/namespaces/carousel.js.map +1 -0
- package/dist/i18n/namespaces/combobox.d.ts +21 -0
- package/dist/i18n/namespaces/combobox.js +23 -0
- package/dist/i18n/namespaces/combobox.js.map +1 -0
- package/dist/i18n/namespaces/command-palette.d.ts +20 -0
- package/dist/i18n/namespaces/command-palette.js +19 -0
- package/dist/i18n/namespaces/command-palette.js.map +1 -0
- package/dist/i18n/namespaces/command.d.ts +11 -0
- package/dist/i18n/namespaces/command.js +13 -0
- package/dist/i18n/namespaces/command.js.map +1 -0
- package/dist/i18n/namespaces/confirm-dialog.d.ts +13 -0
- package/dist/i18n/namespaces/confirm-dialog.js +15 -0
- package/dist/i18n/namespaces/confirm-dialog.js.map +1 -0
- package/dist/i18n/namespaces/contrast.d.ts +7 -0
- package/dist/i18n/namespaces/contrast.js +13 -0
- package/dist/i18n/namespaces/contrast.js.map +1 -0
- package/dist/i18n/namespaces/copy-button.d.ts +11 -0
- package/dist/i18n/namespaces/copy-button.js +13 -0
- package/dist/i18n/namespaces/copy-button.js.map +1 -0
- package/dist/i18n/namespaces/cropper.d.ts +7 -0
- package/dist/i18n/namespaces/cropper.js +17 -0
- package/dist/i18n/namespaces/cropper.js.map +1 -0
- package/dist/i18n/namespaces/data-table.d.ts +7 -0
- package/dist/i18n/namespaces/data-table.js +23 -0
- package/dist/i18n/namespaces/data-table.js.map +1 -0
- package/dist/i18n/namespaces/date-picker.d.ts +42 -0
- package/dist/i18n/namespaces/date-picker.js +35 -0
- package/dist/i18n/namespaces/date-picker.js.map +1 -0
- package/dist/i18n/namespaces/dialog.d.ts +9 -0
- package/dist/i18n/namespaces/dialog.js +7 -0
- package/dist/i18n/namespaces/dialog.js.map +1 -0
- package/dist/i18n/namespaces/display-axis.d.ts +25 -0
- package/dist/i18n/namespaces/display-axis.js +21 -0
- package/dist/i18n/namespaces/display-axis.js.map +1 -0
- package/dist/i18n/namespaces/file-upload.d.ts +11 -0
- package/dist/i18n/namespaces/file-upload.js +19 -0
- package/dist/i18n/namespaces/file-upload.js.map +1 -0
- package/dist/i18n/namespaces/filter-chips.d.ts +11 -0
- package/dist/i18n/namespaces/filter-chips.js +13 -0
- package/dist/i18n/namespaces/filter-chips.js.map +1 -0
- package/dist/i18n/namespaces/image-upload-field.d.ts +12 -0
- package/dist/i18n/namespaces/image-upload-field.js +23 -0
- package/dist/i18n/namespaces/image-upload-field.js.map +1 -0
- package/dist/i18n/namespaces/inline-edit.d.ts +15 -0
- package/dist/i18n/namespaces/inline-edit.js +17 -0
- package/dist/i18n/namespaces/inline-edit.js.map +1 -0
- package/dist/i18n/namespaces/kanban.d.ts +11 -0
- package/dist/i18n/namespaces/kanban.js +39 -0
- package/dist/i18n/namespaces/kanban.js.map +1 -0
- package/dist/i18n/namespaces/key-value.d.ts +10 -0
- package/dist/i18n/namespaces/key-value.js +19 -0
- package/dist/i18n/namespaces/key-value.js.map +1 -0
- package/dist/i18n/namespaces/mention.d.ts +9 -0
- package/dist/i18n/namespaces/mention.js +7 -0
- package/dist/i18n/namespaces/mention.js.map +1 -0
- package/dist/i18n/namespaces/pagination.d.ts +19 -0
- package/dist/i18n/namespaces/pagination.js +21 -0
- package/dist/i18n/namespaces/pagination.js.map +1 -0
- package/dist/i18n/namespaces/phone-input.d.ts +10 -0
- package/dist/i18n/namespaces/phone-input.js +17 -0
- package/dist/i18n/namespaces/phone-input.js.map +1 -0
- package/dist/i18n/namespaces/rating.d.ts +12 -0
- package/dist/i18n/namespaces/rating.js +11 -0
- package/dist/i18n/namespaces/rating.js.map +1 -0
- package/dist/i18n/namespaces/route-tabs.d.ts +9 -0
- package/dist/i18n/namespaces/route-tabs.js +7 -0
- package/dist/i18n/namespaces/route-tabs.js.map +1 -0
- package/dist/i18n/namespaces/scroll-spy.d.ts +9 -0
- package/dist/i18n/namespaces/scroll-spy.js +7 -0
- package/dist/i18n/namespaces/scroll-spy.js.map +1 -0
- package/dist/i18n/namespaces/search-filter-bar.d.ts +15 -0
- package/dist/i18n/namespaces/search-filter-bar.js +32 -0
- package/dist/i18n/namespaces/search-filter-bar.js.map +1 -0
- package/dist/i18n/namespaces/sheet.d.ts +9 -0
- package/dist/i18n/namespaces/sheet.js +7 -0
- package/dist/i18n/namespaces/sheet.js.map +1 -0
- package/dist/i18n/namespaces/shell.d.ts +17 -0
- package/dist/i18n/namespaces/shell.js +75 -0
- package/dist/i18n/namespaces/shell.js.map +1 -0
- package/dist/i18n/namespaces/spinner.d.ts +9 -0
- package/dist/i18n/namespaces/spinner.js +7 -0
- package/dist/i18n/namespaces/spinner.js.map +1 -0
- package/dist/i18n/namespaces/stepper.d.ts +7 -0
- package/dist/i18n/namespaces/stepper.js +15 -0
- package/dist/i18n/namespaces/stepper.js.map +1 -0
- package/dist/i18n/namespaces/table-pagination.d.ts +7 -0
- package/dist/i18n/namespaces/table-pagination.js +29 -0
- package/dist/i18n/namespaces/table-pagination.js.map +1 -0
- package/dist/i18n/namespaces/tags-input.d.ts +12 -0
- package/dist/i18n/namespaces/tags-input.js +11 -0
- package/dist/i18n/namespaces/tags-input.js.map +1 -0
- package/dist/i18n/namespaces/time-picker.d.ts +15 -0
- package/dist/i18n/namespaces/time-picker.js +25 -0
- package/dist/i18n/namespaces/time-picker.js.map +1 -0
- package/dist/i18n/namespaces/toast.d.ts +15 -0
- package/dist/i18n/namespaces/toast.js +7 -0
- package/dist/i18n/namespaces/toast.js.map +1 -0
- package/dist/i18n/namespaces/tour.d.ts +7 -0
- package/dist/i18n/namespaces/tour.js +21 -0
- package/dist/i18n/namespaces/tour.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +24 -1
- package/dist/index.js.map +1 -1
- package/dist/shell/app-header.js.map +1 -1
- package/dist/shell/app-shell.d.ts +20 -2
- package/dist/shell/app-shell.js +4 -1
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/contrast-constants.d.ts +9 -1
- package/dist/shell/contrast-constants.js +2 -4
- package/dist/shell/contrast-constants.js.map +1 -1
- package/dist/shell/contrast-toggle.d.ts +4 -1
- package/dist/shell/contrast-toggle.js +2 -2
- package/dist/shell/contrast-toggle.js.map +1 -1
- package/dist/shell/display-axis-constants.d.ts +2 -1
- package/dist/shell/display-axis-constants.js.map +1 -1
- package/dist/shell/display-axis-controls.d.ts +15 -6
- package/dist/shell/display-axis-controls.js +11 -9
- package/dist/shell/display-axis-controls.js.map +1 -1
- package/dist/shell/mobile-menu.js.map +1 -1
- package/dist/shell/notifications-button.d.ts +1 -1
- package/dist/shell/notifications-button.js +3 -2
- package/dist/shell/notifications-button.js.map +1 -1
- package/dist/shell/shell-context.d.ts +4 -1
- package/dist/shell/shell-context.js +2 -4
- package/dist/shell/shell-context.js.map +1 -1
- package/dist/shell/sidebar.d.ts +1 -1
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/theme-toggle.d.ts +6 -3
- package/dist/shell/theme-toggle.js +2 -2
- package/dist/shell/theme-toggle.js.map +1 -1
- package/dist/shell/types.d.ts +14 -8
- package/dist/shell/types.js +2 -35
- package/dist/shell/types.js.map +1 -1
- package/dist/shell/user-menu.d.ts +6 -6
- package/dist/shell/user-menu.js.map +1 -1
- package/dist/shell/utils.d.ts +1 -1
- package/dist/shell/utils.js.map +1 -1
- package/dist/shell/workspace-switcher.js +1 -1
- package/dist/shell/workspace-switcher.js.map +1 -1
- package/dist/uploader/file-upload-constants.d.ts +13 -0
- package/dist/uploader/file-upload-constants.js +4 -16
- package/dist/uploader/file-upload-constants.js.map +1 -1
- package/dist/uploader/file-upload.d.ts +4 -1
- package/dist/uploader/file-upload.js +2 -2
- package/dist/uploader/file-upload.js.map +1 -1
- package/dist/uploader/image-upload-field.d.ts +5 -1
- package/dist/uploader/image-upload-field.js +2 -2
- package/dist/uploader/image-upload-field.js.map +1 -1
- package/dist/uploader/use-file-upload.d.ts +4 -0
- package/dist/uploader/use-file-upload.js +6 -2
- package/dist/uploader/use-file-upload.js.map +1 -1
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/command.tsx"],"sourcesContent":["\"use client\";\n\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { SearchIcon } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"./dialog.js\";\n\n/**\n * Command — danh sách lệnh có lọc theo phím gõ (cmdk).\n *\n * Đây là primitive trần: composite `CommandPalette` và `Combobox` (Tier 2) dựng lên\n * từ đây. `CommandDialog` bọc sẵn trong `Dialog` cho bảng lệnh Cmd/Ctrl+K.\n *\n * Lưu ý a11y: `CommandDialog` bắt buộc có tiêu đề + mô tả cho trình đọc màn hình\n * (đặt trong `DialogHeader` ẩn `sr-only`) — đổi bằng prop `title`/`description`.\n */\n\nexport type CommandProps = React.ComponentProps<typeof CommandPrimitive>;\n\nfunction Command({ className, ...props }: CommandProps) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n \"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandDialogProps = React.ComponentProps<typeof Dialog> & {\n /** Tiêu đề cho trình đọc màn hình. Mặc định
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/command.tsx"],"sourcesContent":["\"use client\";\n\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { SearchIcon } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { useComitorMessages } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"./dialog.js\";\n\n/**\n * Command — danh sách lệnh có lọc theo phím gõ (cmdk).\n *\n * Đây là primitive trần: composite `CommandPalette` và `Combobox` (Tier 2) dựng lên\n * từ đây. `CommandDialog` bọc sẵn trong `Dialog` cho bảng lệnh Cmd/Ctrl+K.\n *\n * Lưu ý a11y: `CommandDialog` bắt buộc có tiêu đề + mô tả cho trình đọc màn hình\n * (đặt trong `DialogHeader` ẩn `sr-only`) — mặc định theo `ComitorLocaleProvider` (namespace\n * `command`), đổi riêng bằng prop `title`/`description`.\n */\n\nexport type CommandProps = React.ComponentProps<typeof CommandPrimitive>;\n\nfunction Command({ className, ...props }: CommandProps) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n \"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandDialogProps = React.ComponentProps<typeof Dialog> & {\n /** Tiêu đề cho trình đọc màn hình. Mặc định: khoá `dialogTitle` của namespace `command`. */\n title?: string;\n /** Mô tả cho trình đọc màn hình. Mặc định: khoá `dialogDescription` của namespace `command`. */\n description?: string;\n className?: string;\n showCloseButton?: boolean;\n};\n\nfunction CommandDialog({\n title: titleProp,\n description: descriptionProp,\n children,\n className,\n showCloseButton = true,\n ...props\n}: CommandDialogProps) {\n const t = useComitorMessages(\"command\");\n const title = titleProp ?? t.dialogTitle;\n const description = descriptionProp ?? t.dialogDescription;\n return (\n <Dialog {...props}>\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <DialogContent className={cn(\"overflow-hidden p-0\", className)} showCloseButton={showCloseButton}>\n <Command className=\"[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n {children}\n </Command>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport type CommandInputProps = React.ComponentProps<typeof CommandPrimitive.Input>;\n\nfunction CommandInput({ className, ...props }: CommandInputProps) {\n return (\n <div data-slot=\"command-input-wrapper\" className=\"flex h-9 items-center gap-2 border-b px-3\">\n {/* Icon kính lúp là icon MANG NGHĨA (nói \"đây là ô tìm kiếm\") → ngưỡng 3:1.\n `opacity-50` cũ hạ màu kế thừa xuống 3,56:1 (light) / 4,99:1 (dark) — đạt nhưng sát,\n và là con số không token nào bảo vệ. `--muted-foreground` là bậc dành đúng cho vai trò\n này: 5,23:1 (light) · 5,35:1 (dark) trên nền popover. */}\n <SearchIcon className=\"size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n data-slot=\"command-input\"\n className={cn(\n \"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport type CommandListProps = React.ComponentProps<typeof CommandPrimitive.List>;\n\nfunction CommandList({ className, ...props }: CommandListProps) {\n return (\n <CommandPrimitive.List\n data-slot=\"command-list\"\n className={cn(\"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\nexport type CommandEmptyProps = React.ComponentProps<typeof CommandPrimitive.Empty>;\n\nfunction CommandEmpty({ ...props }: CommandEmptyProps) {\n return <CommandPrimitive.Empty data-slot=\"command-empty\" className=\"py-6 text-center text-sm\" {...props} />;\n}\n\nexport type CommandGroupProps = React.ComponentProps<typeof CommandPrimitive.Group>;\n\nfunction CommandGroup({ className, ...props }: CommandGroupProps) {\n return (\n <CommandPrimitive.Group\n data-slot=\"command-group\"\n className={cn(\n \"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandSeparatorProps = React.ComponentProps<typeof CommandPrimitive.Separator>;\n\nfunction CommandSeparator({ className, ...props }: CommandSeparatorProps) {\n return (\n <CommandPrimitive.Separator\n data-slot=\"command-separator\"\n className={cn(\"bg-border -mx-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nexport type CommandItemProps = React.ComponentProps<typeof CommandPrimitive.Item>;\n\nfunction CommandItem({ className, ...props }: CommandItemProps) {\n return (\n <CommandPrimitive.Item\n data-slot=\"command-item\"\n className={cn(\n \"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 mt-1 first:mt-0 rounded-sm px-2 py-(--menu-item-py) text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandShortcutProps = React.ComponentProps<\"span\">;\n\nfunction CommandShortcut({ className, ...props }: CommandShortcutProps) {\n return (\n <span\n data-slot=\"command-shortcut\"\n className={cn(\"text-muted-foreground ml-auto text-xs tracking-widest\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut\n};\n"],"mappings":";AAwBI,cAiCE,YAjCF;AAtBJ,SAAS,WAAW,wBAAwB;AAC5C,SAAS,kBAAkB;AAE3B,SAAS,0BAA0B;AACnC,SAAS,UAAU;AACnB,SAAS,QAAQ,eAAe,mBAAmB,cAAc,mBAAmB;AAepF,SAAS,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAiB;AACtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAWA,SAAS,cAAc;AAAA,EACrB,OAAO;AAAA,EACP,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,GAAG;AACL,GAAuB;AACrB,QAAM,IAAI,mBAAmB,SAAS;AACtC,QAAM,QAAQ,aAAa,EAAE;AAC7B,QAAM,cAAc,mBAAmB,EAAE;AACzC,SACE,qBAAC,UAAQ,GAAG,OACV;AAAA,yBAAC,gBAAa,WAAU,WACtB;AAAA,0BAAC,eAAa,iBAAM;AAAA,MACpB,oBAAC,qBAAmB,uBAAY;AAAA,OAClC;AAAA,IACA,oBAAC,iBAAc,WAAW,GAAG,uBAAuB,SAAS,GAAG,iBAC9D,8BAAC,WAAQ,WAAU,yZAChB,UACH,GACF;AAAA,KACF;AAEJ;AAIA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,SACE,qBAAC,SAAI,aAAU,yBAAwB,WAAU,6CAK/C;AAAA,wBAAC,cAAW,WAAU,8BAA6B;AAAA,IACnD;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC,aAAU;AAAA,QACV,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QACC,GAAG;AAAA;AAAA,IACN;AAAA,KACF;AAEJ;AAIA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAqB;AAC9D,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,+DAA+D,SAAS;AAAA,MACrF,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,aAAa,EAAE,GAAG,MAAM,GAAsB;AACrD,SAAO,oBAAC,iBAAiB,OAAjB,EAAuB,aAAU,iBAAgB,WAAU,4BAA4B,GAAG,OAAO;AAC3G;AAIA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,iBAAiB,EAAE,WAAW,GAAG,MAAM,GAA0B;AACxE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,wBAAwB,SAAS;AAAA,MAC9C,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAqB;AAC9D,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,gBAAgB,EAAE,WAAW,GAAG,MAAM,GAAyB;AACtE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,yDAAyD,SAAS;AAAA,MAC/E,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* `src/chart/chart-colors.ts`. Barrel xuất module này TRỰC TIẾP; `cropper.tsx` chỉ `import`.
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* Chuỗi a11y của `Cropper
|
|
9
|
+
* Chuỗi a11y của `Cropper`. Theo `ComitorLocaleProvider` (mặc định tiếng Anh, bảng tiếng Việt
|
|
10
|
+
* dựng sẵn); truyền `labels` cho `Cropper` để ghi đè từng khoá.
|
|
10
11
|
*
|
|
11
12
|
* ⚠ Thượng nguồn (Dice UI) KHÔNG có chuỗi nào: vùng cắt nhận focus bằng Tab (`tabIndex=0`) nhưng
|
|
12
13
|
* không role, không tên, không mô tả — trình đọc màn hình gặp một phần tử focus được mà không
|
|
@@ -18,7 +19,7 @@ interface CropperLabels {
|
|
|
18
19
|
* đó thắng, vì nó được trải SAU giá trị mặc định.
|
|
19
20
|
*/
|
|
20
21
|
label: string;
|
|
21
|
-
/** `aria-roledescription` — tên loại control mà trình đọc màn hình đọc thay cho "
|
|
22
|
+
/** `aria-roledescription` — tên loại control mà trình đọc màn hình đọc thay cho "application". */
|
|
22
23
|
roleDescription: string;
|
|
23
24
|
/** Hướng dẫn phím, gắn vào vùng cắt qua `aria-describedby`. */
|
|
24
25
|
instructions: string;
|
|
@@ -28,7 +29,11 @@ interface CropperLabels {
|
|
|
28
29
|
*/
|
|
29
30
|
zoomStatus: (zoom: number) => string;
|
|
30
31
|
}
|
|
31
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Nhãn TIẾNG ANH mặc định (từ `3.0.0`; trước đó là tiếng Việt). Bảng tiếng Việt:
|
|
34
|
+
* `comitorMessagesVi.cropper`. Component không đọc thẳng hằng này — nó đọc bảng của
|
|
35
|
+
* `ComitorLocaleProvider`; hằng ở đây để app trải ra khi tự dựng nhãn.
|
|
36
|
+
*/
|
|
32
37
|
declare const DEFAULT_CROPPER_LABELS: CropperLabels;
|
|
33
38
|
|
|
34
39
|
export { type CropperLabels, DEFAULT_CROPPER_LABELS };
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
roleDescription: "tr\xECnh c\u1EAFt \u1EA3nh",
|
|
4
|
-
instructions: "D\xF9ng c\xE1c ph\xEDm m\u0169i t\xEAn \u0111\u1EC3 di chuy\u1EC3n \u1EA3nh, gi\u1EEF Shift \u0111\u1EC3 di chuy\u1EC3n ch\u1EADm h\u01A1n. Ph\xEDm + v\xE0 - \u0111\u1EC3 ph\xF3ng to, thu nh\u1ECF.",
|
|
5
|
-
zoomStatus: (zoom) => `Thu ph\xF3ng ${Math.round(zoom * 100)}%`
|
|
6
|
-
};
|
|
1
|
+
import { cropperEn } from "../../i18n/namespaces/cropper.js";
|
|
2
|
+
const DEFAULT_CROPPER_LABELS = { ...cropperEn };
|
|
7
3
|
export {
|
|
8
4
|
DEFAULT_CROPPER_LABELS
|
|
9
5
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/cropper-constants.ts"],"sourcesContent":["/**\n * Nhãn mặc định của `Cropper`.\n *\n * Module **CỐ Ý không có `\"use client\"`**: mọi export của một file `\"use client\"` tới Server\n * Component là client-reference proxy, đọc ra `undefined` mà KHÔNG throw — xem\n * `src/chart/chart-colors.ts`. Barrel xuất module này TRỰC TIẾP; `cropper.tsx` chỉ `import`.\n */\n\n/**\n * Chuỗi a11y của `Cropper`
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/cropper-constants.ts"],"sourcesContent":["/**\n * Nhãn mặc định của `Cropper`.\n *\n * Module **CỐ Ý không có `\"use client\"`**: mọi export của một file `\"use client\"` tới Server\n * Component là client-reference proxy, đọc ra `undefined` mà KHÔNG throw — xem\n * `src/chart/chart-colors.ts`. Barrel xuất module này TRỰC TIẾP; `cropper.tsx` chỉ `import`.\n */\n\nimport { cropperEn } from \"../../i18n/namespaces/cropper.js\";\n\n/**\n * Chuỗi a11y của `Cropper`. Theo `ComitorLocaleProvider` (mặc định tiếng Anh, bảng tiếng Việt\n * dựng sẵn); truyền `labels` cho `Cropper` để ghi đè từng khoá.\n *\n * ⚠ Thượng nguồn (Dice UI) KHÔNG có chuỗi nào: vùng cắt nhận focus bằng Tab (`tabIndex=0`) nhưng\n * không role, không tên, không mô tả — trình đọc màn hình gặp một phần tử focus được mà không\n * biết nó là gì, và người dùng không có cách nào biết phím nào điều khiển được nó.\n */\nexport interface CropperLabels {\n /**\n * Tên của vùng cắt (`aria-label`). Truyền thẳng `aria-label` cho `Cropper` cũng được — prop\n * đó thắng, vì nó được trải SAU giá trị mặc định.\n */\n label: string;\n /** `aria-roledescription` — tên loại control mà trình đọc màn hình đọc thay cho \"application\". */\n roleDescription: string;\n /** Hướng dẫn phím, gắn vào vùng cắt qua `aria-describedby`. */\n instructions: string;\n /**\n * Câu đọc qua vùng `aria-live` sau mỗi lần phóng/thu bằng phím. `zoom` là hệ số thô (1 = vừa\n * khung). Là HÀM vì có số chèn vào giữa câu.\n */\n zoomStatus: (zoom: number) => string;\n}\n\n/**\n * Nhãn TIẾNG ANH mặc định (từ `3.0.0`; trước đó là tiếng Việt). Bảng tiếng Việt:\n * `comitorMessagesVi.cropper`. Component không đọc thẳng hằng này — nó đọc bảng của\n * `ComitorLocaleProvider`; hằng ở đây để app trải ra khi tự dựng nhãn.\n */\nexport const DEFAULT_CROPPER_LABELS: CropperLabels = { ...cropperEn };\n"],"mappings":"AAQA,SAAS,iBAAiB;AAgCnB,MAAM,yBAAwC,EAAE,GAAG,UAAU;","names":[]}
|
|
@@ -53,7 +53,8 @@ interface CropperProps extends DivProps {
|
|
|
53
53
|
preventScrollZoom?: boolean;
|
|
54
54
|
withGrid?: boolean;
|
|
55
55
|
/**
|
|
56
|
-
* Chuỗi a11y của vùng cắt — ghi đè từng kho
|
|
56
|
+
* Chuỗi a11y của vùng cắt — ghi đè từng khoá. Không truyền thì theo namespace `cropper` của
|
|
57
|
+
* `ComitorLocaleProvider` (mặc định tiếng Anh).
|
|
57
58
|
*
|
|
58
59
|
* ⚠ Thêm so với thượng nguồn — xem `CropperLabels`.
|
|
59
60
|
*/
|
|
@@ -3,12 +3,12 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { Slot } from "@radix-ui/react-slot";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import * as React from "react";
|
|
6
|
+
import { useComitorLabels } from "../../i18n/locale-provider.js";
|
|
6
7
|
import { cn } from "../../lib/cn.js";
|
|
7
8
|
import { useComposedRefs } from "../../lib/compose-refs.js";
|
|
8
9
|
import { useAsRef } from "../../lib/use-as-ref.js";
|
|
9
10
|
import { useIsomorphicLayoutEffect } from "../../lib/use-isomorphic-layout-effect.js";
|
|
10
11
|
import { useLazyRef } from "../../lib/use-lazy-ref.js";
|
|
11
|
-
import { DEFAULT_CROPPER_LABELS } from "./cropper-constants.js";
|
|
12
12
|
const ROOT_NAME = "Cropper";
|
|
13
13
|
const ROOT_IMPL_NAME = "CropperImpl";
|
|
14
14
|
const IMAGE_NAME = "CropperImage";
|
|
@@ -408,7 +408,7 @@ function Cropper(props) {
|
|
|
408
408
|
}
|
|
409
409
|
}
|
|
410
410
|
}, [cropProp, zoomProp, rotationProp, store, allowOverflow]);
|
|
411
|
-
const labels =
|
|
411
|
+
const labels = useComitorLabels("cropper", labelsProp);
|
|
412
412
|
const contextValue = React.useMemo(
|
|
413
413
|
() => ({
|
|
414
414
|
minZoom,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ui/cropper.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/cropper) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { type CropperLabels, DEFAULT_CROPPER_LABELS } from \"./cropper-constants.js\";\n\nconst ROOT_NAME = \"Cropper\";\nconst ROOT_IMPL_NAME = \"CropperImpl\";\nconst IMAGE_NAME = \"CropperImage\";\nconst VIDEO_NAME = \"CropperVideo\";\nconst AREA_NAME = \"CropperArea\";\n\ninterface Point {\n x: number;\n y: number;\n}\n\ninterface GestureEvent extends UIEvent {\n rotation: number;\n scale: number;\n clientX: number;\n clientY: number;\n}\n\ninterface Size {\n width: number;\n height: number;\n}\n\ninterface Area {\n width: number;\n height: number;\n x: number;\n y: number;\n}\n\ninterface MediaSize {\n width: number;\n height: number;\n naturalWidth: number;\n naturalHeight: number;\n}\n\ntype Shape = \"rectangle\" | \"circle\";\ntype ObjectFit = \"contain\" | \"cover\" | \"horizontal-cover\" | \"vertical-cover\";\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\nconst MAX_CACHE_SIZE = 200;\n\n/*\n * ⚠ Thêm so với thượng nguồn: phím + / - để thu phóng (xem `onKeyDown` của `CropperImpl`).\n * `=` và `_` là cùng phím với `+` / `-` khi KHÔNG giữ Shift trên bàn phím US.\n */\nconst ZOOM_IN_KEYS = new Set([\"+\", \"=\"]);\nconst ZOOM_OUT_KEYS = new Set([\"-\", \"_\"]);\nconst KEYBOARD_ZOOM_STEP = 0.1;\n\n/*\n * ⚠ Khác thượng nguồn: bản gốc chụp `window.devicePixelRatio` vào một HẰNG ở cấp module\n * (`const DPR = typeof window …`). Hệ quả: module chạm `window` ngay lúc nạp; server luôn ra 1 còn\n * client ra 2 nên `style` của ảnh lệch nhau lúc hydrate khi bật `snapPixels`; và zoom trình duyệt\n * thì con số không bao giờ cập nhật. Nay đọc LƯỜI — trong handler/effect gọi hàm này, còn lượt\n * render đi qua `useDevicePixelRatio` (server và lượt hydrate luôn nhận 1).\n */\nfunction getDevicePixelRatio(): number {\n return typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1;\n}\n\nfunction getServerDevicePixelRatio(): number {\n return 1;\n}\n\nfunction subscribeToDevicePixelRatio(onChange: () => void) {\n // Zoom trình duyệt đổi DPR và bắn `resize`.\n window.addEventListener(\"resize\", onChange);\n return () => window.removeEventListener(\"resize\", onChange);\n}\n\nfunction useDevicePixelRatio(): number {\n return React.useSyncExternalStore(subscribeToDevicePixelRatio, getDevicePixelRatio, getServerDevicePixelRatio);\n}\n\nconst rotationSizeCache = new Map<string, Size>();\nconst cropSizeCache = new Map<string, Size>();\nconst croppedAreaCache = new Map<string, { croppedAreaPercentages: Area; croppedAreaPixels: Area }>();\nconst onPositionClampCache = new Map<string, Point>();\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction quantize(n: number, step = 2 / getDevicePixelRatio()): number {\n return Math.round(n / step) * step;\n}\n\nfunction quantizePosition(n: number, step = 4 / getDevicePixelRatio()): number {\n return Math.round(n / step) * step;\n}\n\nfunction quantizeZoom(n: number, step = 0.01): number {\n return Math.round(n / step) * step;\n}\n\nfunction quantizeRotation(n: number, step = 1.0): number {\n return Math.round(n / step) * step;\n}\n\nfunction snapToDevicePixel(n: number, dpr: number): number {\n return Math.round(n * dpr) / dpr;\n}\n\nfunction lruGet<K, V>(map: Map<K, V>, key: K): V | undefined {\n const v = map.get(key);\n if (v !== undefined) {\n map.delete(key);\n map.set(key, v);\n }\n return v;\n}\n\nfunction lruSet<K, V>(map: Map<K, V>, key: K, val: V, max = MAX_CACHE_SIZE): void {\n if (map.has(key)) {\n map.delete(key);\n }\n map.set(key, val);\n if (map.size > max) {\n const firstKey = map.keys().next().value;\n if (firstKey !== undefined) {\n map.delete(firstKey);\n }\n }\n}\n\nfunction getDistanceBetweenPoints(pointA: Point, pointB: Point): number {\n return Math.sqrt((pointA.y - pointB.y) ** 2 + (pointA.x - pointB.x) ** 2);\n}\n\nfunction getCenter(a: Point, b: Point): Point {\n return {\n x: (b.x + a.x) * 0.5,\n y: (b.y + a.y) * 0.5\n };\n}\n\nfunction getRotationBetweenPoints(pointA: Point, pointB: Point): number {\n return (Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x) * 180) / Math.PI;\n}\n\nfunction getRadianAngle(degreeValue: number): number {\n return (degreeValue * Math.PI) / 180;\n}\n\nfunction rotateSize(width: number, height: number, rotation: number): Size {\n const cacheKey = `${quantize(width)}-${quantize(height)}-${quantizeRotation(rotation)}`;\n\n const cached = lruGet(rotationSizeCache, cacheKey);\n if (cached) {\n return cached;\n }\n const rotRad = getRadianAngle(rotation);\n const cosRot = Math.cos(rotRad);\n const sinRot = Math.sin(rotRad);\n\n const result: Size = {\n width: Math.abs(cosRot * width) + Math.abs(sinRot * height),\n height: Math.abs(sinRot * width) + Math.abs(cosRot * height)\n };\n\n lruSet(rotationSizeCache, cacheKey, result, MAX_CACHE_SIZE);\n return result;\n}\n\nfunction getCropSize(\n mediaWidth: number,\n mediaHeight: number,\n contentWidth: number,\n contentHeight: number,\n aspect: number,\n rotation = 0\n): Size {\n const cacheKey = `${quantize(mediaWidth, 8)}-${quantize(mediaHeight, 8)}-${quantize(contentWidth, 8)}-${quantize(contentHeight, 8)}-${quantize(aspect, 0.01)}-${quantizeRotation(rotation)}`;\n\n const cached = lruGet(cropSizeCache, cacheKey);\n if (cached) {\n return cached;\n }\n const { width, height } = rotateSize(mediaWidth, mediaHeight, rotation);\n const fittingWidth = Math.min(width, contentWidth);\n const fittingHeight = Math.min(height, contentHeight);\n\n const result: Size =\n fittingWidth > fittingHeight * aspect\n ? {\n width: fittingHeight * aspect,\n height: fittingHeight\n }\n : {\n width: fittingWidth,\n height: fittingWidth / aspect\n };\n\n lruSet(cropSizeCache, cacheKey, result, MAX_CACHE_SIZE);\n return result;\n}\n\nfunction onPositionClamp(position: Point, mediaSize: Size, cropSize: Size, zoom: number, rotation = 0): Point {\n /*\n * ⚠ Khác thượng nguồn: bản gốc cache CẢ KẾT QUẢ, với khoá chứa vị trí đã lượng tử hoá (bước\n * 4/DPR px) — hai vị trí khác nhau rơi cùng một ô thì nhận lại kết quả của vị trí TRƯỚC. Phím\n * mũi tên dời 1px (Shift: 0,2px) nên vị trí mới luôn rơi vào ô của vị trí cũ và cache trả lại\n * đúng vị trí cũ: ảnh KẸT sau lần bấm đầu tiên — đo trên trình duyệt thật, 20 lần → phải đúng\n * 1px. Tức bàn phím không dời được ảnh. Nay chỉ cache GIỚI HẠN kẹp (thứ phụ thuộc kích thước,\n * zoom, góc — không phụ thuộc vị trí, cùng cách lượng tử hoá như bản gốc) và kẹp vị trí THẬT.\n */\n const cacheKey = `${quantize(mediaSize.width)}-${quantize(mediaSize.height)}-${quantize(cropSize.width)}-${quantize(cropSize.height)}-${quantizeZoom(zoom)}-${quantizeRotation(rotation)}`;\n\n let maxPosition = lruGet(onPositionClampCache, cacheKey);\n if (!maxPosition) {\n const { width, height } = rotateSize(mediaSize.width, mediaSize.height, rotation);\n\n maxPosition = {\n x: width * zoom * 0.5 - cropSize.width * 0.5,\n y: height * zoom * 0.5 - cropSize.height * 0.5\n };\n\n lruSet(onPositionClampCache, cacheKey, maxPosition, MAX_CACHE_SIZE);\n }\n\n return {\n x: clamp(position.x, -maxPosition.x, maxPosition.x),\n y: clamp(position.y, -maxPosition.y, maxPosition.y)\n };\n}\n\nfunction getCroppedArea(\n crop: Point,\n mediaSize: MediaSize,\n cropSize: Size,\n aspect: number,\n zoom: number,\n rotation = 0,\n allowOverflow = false\n): { croppedAreaPercentages: Area; croppedAreaPixels: Area } {\n const cacheKey = `${quantizePosition(crop.x)}-${quantizePosition(crop.y)}-${quantize(mediaSize.width)}-${quantize(mediaSize.height)}-${quantize(mediaSize.naturalWidth)}-${quantize(mediaSize.naturalHeight)}-${quantize(cropSize.width)}-${quantize(cropSize.height)}-${quantize(aspect, 0.01)}-${quantizeZoom(zoom)}-${quantizeRotation(rotation)}-${allowOverflow}`;\n\n const cached = lruGet(croppedAreaCache, cacheKey);\n\n if (cached) return cached;\n\n const onAreaLimit = !allowOverflow\n ? (max: number, value: number) => Math.min(max, Math.max(0, value))\n : (_max: number, value: number) => value;\n\n const mediaBBoxSize = rotateSize(mediaSize.width, mediaSize.height, rotation);\n const mediaNaturalBBoxSize = rotateSize(mediaSize.naturalWidth, mediaSize.naturalHeight, rotation);\n\n const croppedAreaPercentages: Area = {\n x: onAreaLimit(\n 100,\n (((mediaBBoxSize.width - cropSize.width / zoom) / 2 - crop.x / zoom) / mediaBBoxSize.width) * 100\n ),\n y: onAreaLimit(\n 100,\n (((mediaBBoxSize.height - cropSize.height / zoom) / 2 - crop.y / zoom) / mediaBBoxSize.height) * 100\n ),\n width: onAreaLimit(100, ((cropSize.width / mediaBBoxSize.width) * 100) / zoom),\n height: onAreaLimit(100, ((cropSize.height / mediaBBoxSize.height) * 100) / zoom)\n };\n\n const widthInPixels = Math.round(\n onAreaLimit(mediaNaturalBBoxSize.width, (croppedAreaPercentages.width * mediaNaturalBBoxSize.width) / 100)\n );\n const heightInPixels = Math.round(\n onAreaLimit(mediaNaturalBBoxSize.height, (croppedAreaPercentages.height * mediaNaturalBBoxSize.height) / 100)\n );\n const isImageWiderThanHigh = mediaNaturalBBoxSize.width >= mediaNaturalBBoxSize.height * aspect;\n\n const sizePixels: Size = isImageWiderThanHigh\n ? {\n width: Math.round(heightInPixels * aspect),\n height: heightInPixels\n }\n : {\n width: widthInPixels,\n height: Math.round(widthInPixels / aspect)\n };\n\n const croppedAreaPixels: Area = {\n ...sizePixels,\n x: Math.round(\n onAreaLimit(\n mediaNaturalBBoxSize.width - sizePixels.width,\n (croppedAreaPercentages.x * mediaNaturalBBoxSize.width) / 100\n )\n ),\n y: Math.round(\n onAreaLimit(\n mediaNaturalBBoxSize.height - sizePixels.height,\n (croppedAreaPercentages.y * mediaNaturalBBoxSize.height) / 100\n )\n )\n };\n\n const result = { croppedAreaPercentages, croppedAreaPixels };\n\n lruSet(croppedAreaCache, cacheKey, result, MAX_CACHE_SIZE);\n return result;\n}\n\ninterface StoreState {\n crop: Point;\n zoom: number;\n rotation: number;\n mediaSize: MediaSize | null;\n cropSize: Size | null;\n isDragging: boolean;\n isWheelZooming: boolean;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;\n notify: () => void;\n batch: (fn: () => void) => void;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T): T {\n // Tên trong thông báo lỗi là tên XUẤT RA NGOÀI (`useCropper`), không phải tên nội bộ.\n const store = useStoreContext(\"useCropper\");\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ntype RootElement = React.ComponentRef<typeof CropperImpl>;\n\ninterface CropperContextValue {\n aspectRatio: number;\n minZoom: number;\n maxZoom: number;\n zoomSpeed: number;\n keyboardStep: number;\n shape: Shape;\n objectFit: ObjectFit;\n rootRef: React.RefObject<RootElement | null>;\n allowOverflow: boolean;\n preventScrollZoom: boolean;\n withGrid: boolean;\n labels: CropperLabels;\n}\n\nconst CropperContext = React.createContext<CropperContextValue | null>(null);\n\nfunction useCropperContext(consumerName: string) {\n const context = React.useContext(CropperContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface CropperProps extends DivProps {\n crop?: Point;\n zoom?: number;\n minZoom?: number;\n maxZoom?: number;\n zoomSpeed?: number;\n rotation?: number;\n keyboardStep?: number;\n aspectRatio?: number;\n shape?: Shape;\n objectFit?: ObjectFit;\n allowOverflow?: boolean;\n preventScrollZoom?: boolean;\n withGrid?: boolean;\n /**\n * Chuỗi a11y của vùng cắt — ghi đè từng khoá, mặc định `DEFAULT_CROPPER_LABELS` (tiếng Việt).\n *\n * ⚠ Thêm so với thượng nguồn — xem `CropperLabels`.\n */\n labels?: Partial<CropperLabels>;\n onCropChange?: (crop: Point) => void;\n onCropSizeChange?: (cropSize: Size) => void;\n onCropAreaChange?: (croppedArea: Area, croppedAreaPixels: Area) => void;\n onCropComplete?: (croppedArea: Area, croppedAreaPixels: Area) => void;\n onZoomChange?: (zoom: number) => void;\n onRotationChange?: (rotation: number) => void;\n onMediaLoaded?: (mediaSize: MediaSize) => void;\n onInteractionStart?: () => void;\n onInteractionEnd?: () => void;\n onWheelZoom?: (event: WheelEvent) => void;\n}\n\n/**\n * Cropper — cắt ảnh/video: kéo để dời, lăn chuột/chụm hai ngón để phóng, phím mũi tên và + / -.\n *\n * Ở Comitor dùng để cắt ảnh đại diện hoặc logo công ty TRƯỚC khi tải lên. Component chỉ BÁO vùng\n * cắt (`onCropComplete(croppedArea, croppedAreaPixels)`) — việc vẽ ra canvas và tải lên là của\n * app. Cố ý không phụ thuộc gì ngoài peer bắt buộc để sống được ở entry chính; `ImageUploadField`\n * (entry `/uploader`, kéo theo `@uppy/*`) ghép với nó ở tầng app, không ở đây.\n *\n * `crop` / `zoom` / `rotation` là controlled KHI được truyền, uncontrolled khi bỏ trống.\n */\nfunction Cropper(props: CropperProps) {\n const {\n /*\n * ⚠ Khác thượng nguồn: bản gốc gán mặc định ngay ở đây (`crop = { x: 0, y: 0 }`, `zoom = 1`,\n * `rotation = 0`), nên nhánh `!== undefined` trong effect đồng bộ bên dưới LUÔN đúng, và\n * `{ x: 0, y: 0 }` là object MỚI mỗi lượt render. Hệ quả ở chế độ không kiểm soát: mỗi lần\n * component cha render lại — kể cả vì chính `onCropComplete` gọi `setState` ở cha — vị trí và\n * độ phóng bị kéo về mặc định ngay sau khi người dùng vừa chỉnh xong. Mặc định nay chỉ dùng\n * cho state KHỞI TẠO; effect chỉ đồng bộ prop nào thật sự được truyền, đúng ý của nhánh đó.\n */\n crop: cropProp,\n zoom: zoomProp,\n minZoom = 1,\n maxZoom = 3,\n zoomSpeed = 1,\n rotation: rotationProp,\n keyboardStep = 1,\n aspectRatio = 4 / 3,\n shape = \"rectangle\",\n objectFit = \"contain\",\n allowOverflow = false,\n preventScrollZoom = false,\n withGrid = false,\n labels: labelsProp,\n onCropChange,\n onCropSizeChange,\n onCropAreaChange,\n onCropComplete,\n onZoomChange,\n onRotationChange,\n onMediaLoaded,\n onInteractionStart,\n onInteractionEnd,\n className,\n ...rootProps\n } = props;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => ({\n crop: cropProp ?? { x: 0, y: 0 },\n zoom: zoomProp ?? 1,\n rotation: rotationProp ?? 0,\n mediaSize: null,\n cropSize: null,\n isDragging: false,\n isWheelZooming: false\n }));\n\n const propsRef = useAsRef({\n onCropChange,\n onCropSizeChange,\n onCropAreaChange,\n onCropComplete,\n onZoomChange,\n onRotationChange,\n onMediaLoaded,\n onInteractionStart,\n onInteractionEnd\n });\n\n const rootRef = React.useRef<RootElement | null>(null);\n\n const store = React.useMemo<Store>(() => {\n let isBatching = false;\n let raf: number | null = null;\n\n function notifyCropAreaChange() {\n if (raf != null) return;\n raf = requestAnimationFrame(() => {\n raf = null;\n const s = stateRef.current;\n if (s?.mediaSize && s.cropSize && propsRef.current.onCropAreaChange) {\n const { croppedAreaPercentages, croppedAreaPixels } = getCroppedArea(\n s.crop,\n s.mediaSize,\n s.cropSize,\n aspectRatio,\n s.zoom,\n s.rotation\n );\n propsRef.current.onCropAreaChange(croppedAreaPercentages, croppedAreaPixels);\n }\n });\n }\n\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n stateRef.current[key] = value;\n\n if (key === \"crop\" && typeof value === \"object\" && value && \"x\" in value) {\n propsRef.current.onCropChange?.(value);\n } else if (key === \"zoom\" && typeof value === \"number\") {\n propsRef.current.onZoomChange?.(value);\n } else if (key === \"rotation\" && typeof value === \"number\") {\n propsRef.current.onRotationChange?.(value);\n } else if (key === \"cropSize\" && typeof value === \"object\" && value && \"width\" in value) {\n propsRef.current.onCropSizeChange?.(value);\n } else if (key === \"mediaSize\" && typeof value === \"object\" && value && \"naturalWidth\" in value) {\n propsRef.current.onMediaLoaded?.(value);\n } else if (key === \"isDragging\") {\n if (value) {\n propsRef.current.onInteractionStart?.();\n } else {\n propsRef.current.onInteractionEnd?.();\n const currentState = stateRef.current;\n if (currentState?.mediaSize && currentState.cropSize && propsRef.current.onCropComplete) {\n const { croppedAreaPercentages, croppedAreaPixels } = getCroppedArea(\n currentState.crop,\n currentState.mediaSize,\n currentState.cropSize,\n aspectRatio,\n currentState.zoom,\n currentState.rotation\n );\n propsRef.current.onCropComplete(croppedAreaPercentages, croppedAreaPixels);\n }\n }\n }\n\n if (\n (key === \"crop\" || key === \"zoom\" || key === \"rotation\" || key === \"mediaSize\" || key === \"cropSize\") &&\n propsRef.current.onCropAreaChange\n ) {\n notifyCropAreaChange();\n }\n\n if (!isBatching) {\n store.notify();\n }\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n },\n batch: (fn: () => void) => {\n if (isBatching) {\n fn();\n return;\n }\n isBatching = true;\n try {\n fn();\n } finally {\n isBatching = false;\n store.notify();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef, aspectRatio]);\n\n useIsomorphicLayoutEffect(() => {\n const updates: Partial<StoreState> = {};\n let hasUpdates = false;\n let shouldRecompute = false;\n\n if (cropProp !== undefined) {\n const currentState = store.getState();\n if (!Object.is(currentState.crop, cropProp)) {\n updates.crop = cropProp;\n hasUpdates = true;\n }\n }\n\n if (zoomProp !== undefined) {\n const currentState = store.getState();\n if (currentState.zoom !== zoomProp) {\n updates.zoom = zoomProp;\n hasUpdates = true;\n shouldRecompute = true;\n }\n }\n\n if (rotationProp !== undefined) {\n const currentState = store.getState();\n if (currentState.rotation !== rotationProp) {\n updates.rotation = rotationProp;\n hasUpdates = true;\n shouldRecompute = true;\n }\n }\n\n if (hasUpdates) {\n store.batch(() => {\n Object.entries(updates).forEach(([key, value]) => {\n store.setState(key as keyof StoreState, value);\n });\n });\n\n if (shouldRecompute && rootRef.current) {\n requestAnimationFrame(() => {\n const currentState = store.getState();\n if (currentState.cropSize && currentState.mediaSize) {\n const newPosition = !allowOverflow\n ? onPositionClamp(\n currentState.crop,\n currentState.mediaSize,\n currentState.cropSize,\n currentState.zoom,\n currentState.rotation\n )\n : currentState.crop;\n\n if (\n Math.abs(newPosition.x - currentState.crop.x) > 0.001 ||\n Math.abs(newPosition.y - currentState.crop.y) > 0.001\n ) {\n store.setState(\"crop\", newPosition);\n }\n }\n });\n }\n }\n }, [cropProp, zoomProp, rotationProp, store, allowOverflow]);\n\n const labels = React.useMemo<CropperLabels>(() => ({ ...DEFAULT_CROPPER_LABELS, ...labelsProp }), [labelsProp]);\n\n const contextValue = React.useMemo<CropperContextValue>(\n () => ({\n minZoom,\n maxZoom,\n zoomSpeed,\n keyboardStep,\n aspectRatio,\n shape,\n objectFit,\n preventScrollZoom,\n allowOverflow,\n withGrid,\n rootRef,\n labels\n }),\n [\n minZoom,\n maxZoom,\n zoomSpeed,\n keyboardStep,\n aspectRatio,\n shape,\n objectFit,\n preventScrollZoom,\n allowOverflow,\n withGrid,\n labels\n ]\n );\n\n return (\n <StoreContext.Provider value={store}>\n <CropperContext.Provider value={contextValue}>\n <div data-slot=\"cropper-wrapper\" className={cn(\"relative size-full overflow-hidden\", className)}>\n <CropperImpl {...rootProps} />\n </div>\n </CropperContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface CropperImplProps extends CropperProps {\n onWheelZoom?: (event: WheelEvent) => void;\n}\n\nfunction CropperImpl(props: CropperImplProps) {\n const {\n onWheelZoom: onWheelZoomProp,\n onKeyUp: onKeyUpProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onTouchStart: onTouchStartProp,\n \"aria-describedby\": ariaDescribedByProp,\n asChild,\n className,\n ref,\n ...rootImplProps\n } = props;\n\n const context = useCropperContext(ROOT_IMPL_NAME);\n const store = useStoreContext(ROOT_IMPL_NAME);\n const crop = useStore((state) => state.crop);\n const zoom = useStore((state) => state.zoom);\n const rotation = useStore((state) => state.rotation);\n const mediaSize = useStore((state) => state.mediaSize);\n const cropSize = useStore((state) => state.cropSize);\n\n const descriptionId = React.useId();\n // Câu đọc qua vùng `aria-live` — chỉ đổi khi phóng/thu BẰNG PHÍM (con lăn/chụm là thao tác nhìn).\n const [zoomStatus, setZoomStatus] = React.useState(\"\");\n\n const propsRef = useAsRef({\n onWheelZoom: onWheelZoomProp,\n onKeyUp: onKeyUpProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onTouchStart: onTouchStartProp\n });\n\n const composedRef = useComposedRefs(ref, context.rootRef);\n const dragStartPositionRef = React.useRef<Point>({ x: 0, y: 0 });\n const dragStartCropRef = React.useRef<Point>({ x: 0, y: 0 });\n const contentPositionRef = React.useRef<Point>({ x: 0, y: 0 });\n const lastPinchDistanceRef = React.useRef(0);\n const lastPinchRotationRef = React.useRef(0);\n const rafDragTimeoutRef = React.useRef<number | null>(null);\n const rafPinchTimeoutRef = React.useRef<number | null>(null);\n const wheelTimerRef = React.useRef<number | null>(null);\n const isTouchingRef = React.useRef(false);\n const gestureZoomStartRef = React.useRef(0);\n const gestureRotationStartRef = React.useRef(0);\n\n const onRefsCleanup = React.useCallback(() => {\n if (rafDragTimeoutRef.current) {\n cancelAnimationFrame(rafDragTimeoutRef.current);\n rafDragTimeoutRef.current = null;\n }\n if (rafPinchTimeoutRef.current) {\n cancelAnimationFrame(rafPinchTimeoutRef.current);\n rafPinchTimeoutRef.current = null;\n }\n if (wheelTimerRef.current) {\n clearTimeout(wheelTimerRef.current);\n wheelTimerRef.current = null;\n }\n isTouchingRef.current = false;\n }, []);\n\n const onCacheCleanup = React.useCallback(() => {\n if (onPositionClampCache.size > MAX_CACHE_SIZE * 1.5) {\n onPositionClampCache.clear();\n }\n if (croppedAreaCache.size > MAX_CACHE_SIZE * 1.5) {\n croppedAreaCache.clear();\n }\n }, []);\n\n const getMousePoint = React.useCallback(\n (event: MouseEvent | React.MouseEvent) => ({\n x: Number(event.clientX),\n y: Number(event.clientY)\n }),\n []\n );\n\n const getTouchPoint = React.useCallback(\n (touch: Touch | React.Touch) => ({\n x: Number(touch.clientX),\n y: Number(touch.clientY)\n }),\n []\n );\n\n const onContentPositionChange = React.useCallback(() => {\n if (context.rootRef?.current) {\n const bounds = context.rootRef.current.getBoundingClientRect();\n contentPositionRef.current = { x: bounds.left, y: bounds.top };\n }\n }, [context.rootRef]);\n\n const getPointOnContent = React.useCallback(\n ({ x, y }: Point, contentTopLeft: Point): Point => {\n if (!context.rootRef?.current) {\n return { x: 0, y: 0 };\n }\n const contentRect = context.rootRef.current.getBoundingClientRect();\n return {\n x: contentRect.width / 2 - (x - contentTopLeft.x),\n y: contentRect.height / 2 - (y - contentTopLeft.y)\n };\n },\n [context.rootRef]\n );\n\n const getPointOnMedia = React.useCallback(\n ({ x, y }: Point) => {\n return {\n x: (x + crop.x) / zoom,\n y: (y + crop.y) / zoom\n };\n },\n [crop, zoom]\n );\n\n const recomputeCropPosition = React.useCallback(() => {\n if (!cropSize || !mediaSize) return;\n\n const newPosition = !context.allowOverflow ? onPositionClamp(crop, mediaSize, cropSize, zoom, rotation) : crop;\n\n if (Math.abs(newPosition.x - crop.x) > 0.001 || Math.abs(newPosition.y - crop.y) > 0.001) {\n store.setState(\"crop\", newPosition);\n }\n }, [cropSize, mediaSize, context.allowOverflow, crop, zoom, rotation, store]);\n\n const onZoomChange = React.useCallback(\n (newZoom: number, point: Point, shouldUpdatePosition = true) => {\n if (!cropSize || !mediaSize) return;\n\n const clampedZoom = clamp(newZoom, context.minZoom, context.maxZoom);\n\n store.batch(() => {\n if (shouldUpdatePosition) {\n const zoomPoint = getPointOnContent(point, contentPositionRef.current);\n const zoomTarget = getPointOnMedia(zoomPoint);\n const requestedPosition = {\n x: zoomTarget.x * clampedZoom - zoomPoint.x,\n y: zoomTarget.y * clampedZoom - zoomPoint.y\n };\n\n const newPosition = !context.allowOverflow\n ? onPositionClamp(requestedPosition, mediaSize, cropSize, clampedZoom, rotation)\n : requestedPosition;\n\n store.setState(\"crop\", newPosition);\n }\n store.setState(\"zoom\", clampedZoom);\n });\n\n requestAnimationFrame(() => {\n recomputeCropPosition();\n });\n },\n [\n cropSize,\n mediaSize,\n context.minZoom,\n context.maxZoom,\n context.allowOverflow,\n getPointOnContent,\n getPointOnMedia,\n rotation,\n store,\n recomputeCropPosition\n ]\n );\n\n const onDragStart = React.useCallback(\n ({ x, y }: Point) => {\n dragStartPositionRef.current = { x, y };\n dragStartCropRef.current = { ...crop };\n store.setState(\"isDragging\", true);\n },\n [crop, store]\n );\n\n const onDrag = React.useCallback(\n ({ x, y }: Point) => {\n if (rafDragTimeoutRef.current) {\n cancelAnimationFrame(rafDragTimeoutRef.current);\n }\n\n rafDragTimeoutRef.current = requestAnimationFrame(() => {\n if (!cropSize || !mediaSize) return;\n if (x === undefined || y === undefined) return;\n\n const offsetX = x - dragStartPositionRef.current.x;\n const offsetY = y - dragStartPositionRef.current.y;\n\n if (Math.abs(offsetX) < 2 && Math.abs(offsetY) < 2) {\n return;\n }\n\n const requestedPosition = {\n x: dragStartCropRef.current.x + offsetX,\n y: dragStartCropRef.current.y + offsetY\n };\n\n const newPosition = !context.allowOverflow\n ? onPositionClamp(requestedPosition, mediaSize, cropSize, zoom, rotation)\n : requestedPosition;\n\n const currentCrop = store.getState().crop;\n if (Math.abs(newPosition.x - currentCrop.x) > 1 || Math.abs(newPosition.y - currentCrop.y) > 1) {\n store.setState(\"crop\", newPosition);\n }\n });\n },\n [cropSize, mediaSize, context.allowOverflow, zoom, rotation, store]\n );\n\n const onMouseMove = React.useCallback((event: MouseEvent) => onDrag(getMousePoint(event)), [getMousePoint, onDrag]);\n\n const onTouchMove = React.useCallback(\n (event: TouchEvent) => {\n event.preventDefault();\n if (event.touches.length === 2) {\n const [firstTouch, secondTouch] = event.touches ?? [];\n if (firstTouch && secondTouch) {\n const pointA = getTouchPoint(firstTouch);\n const pointB = getTouchPoint(secondTouch);\n const center = getCenter(pointA, pointB);\n onDrag(center);\n\n if (rafPinchTimeoutRef.current) {\n cancelAnimationFrame(rafPinchTimeoutRef.current);\n }\n\n rafPinchTimeoutRef.current = requestAnimationFrame(() => {\n const distance = getDistanceBetweenPoints(pointA, pointB);\n const distanceRatio = distance / lastPinchDistanceRef.current;\n\n if (Math.abs(distanceRatio - 1) > 0.01) {\n const newZoom = zoom * distanceRatio;\n onZoomChange(newZoom, center, false);\n lastPinchDistanceRef.current = distance;\n }\n\n const rotationAngle = getRotationBetweenPoints(pointA, pointB);\n const rotationDiff = rotationAngle - lastPinchRotationRef.current;\n\n if (Math.abs(rotationDiff) > 0.5) {\n const newRotation = rotation + rotationDiff;\n store.setState(\"rotation\", newRotation);\n lastPinchRotationRef.current = rotationAngle;\n }\n });\n }\n } else if (event.touches.length === 1) {\n const firstTouch = event.touches[0];\n if (firstTouch) {\n onDrag(getTouchPoint(firstTouch));\n }\n }\n },\n [getTouchPoint, onDrag, zoom, onZoomChange, rotation, store]\n );\n\n const onGestureChange = React.useCallback(\n (event: GestureEvent) => {\n event.preventDefault();\n if (isTouchingRef.current) {\n return;\n }\n\n const point = { x: Number(event.clientX), y: Number(event.clientY) };\n const newZoom = gestureZoomStartRef.current - 1 + event.scale;\n onZoomChange(newZoom, point, true);\n\n const newRotation = gestureRotationStartRef.current + event.rotation;\n store.setState(\"rotation\", newRotation);\n },\n [onZoomChange, store]\n );\n\n const onGestureEnd = React.useCallback(() => {\n document.removeEventListener(\"gesturechange\", onGestureChange as EventListener);\n document.removeEventListener(\"gestureend\", onGestureEnd as EventListener);\n }, [onGestureChange]);\n\n const onGestureStart = React.useCallback(\n (event: GestureEvent) => {\n event.preventDefault();\n // ⚠ Khác thượng nguồn: cập nhật toạ độ khung trước khi phóng — xem chú thích ở `onWheelZoom`.\n onContentPositionChange();\n document.addEventListener(\"gesturechange\", onGestureChange as EventListener);\n document.addEventListener(\"gestureend\", onGestureEnd as EventListener);\n gestureZoomStartRef.current = zoom;\n gestureRotationStartRef.current = rotation;\n },\n [zoom, rotation, onGestureChange, onGestureEnd, onContentPositionChange]\n );\n\n const onSafariZoomPrevent = React.useCallback((event: Event) => event.preventDefault(), []);\n\n const onEventsCleanup = React.useCallback(() => {\n document.removeEventListener(\"mousemove\", onMouseMove);\n document.removeEventListener(\"touchmove\", onTouchMove);\n document.removeEventListener(\"gesturechange\", onGestureChange as EventListener);\n document.removeEventListener(\"gestureend\", onGestureEnd as EventListener);\n }, [onMouseMove, onTouchMove, onGestureChange, onGestureEnd]);\n\n const onDragStopped = React.useCallback(() => {\n isTouchingRef.current = false;\n store.setState(\"isDragging\", false);\n onRefsCleanup();\n document.removeEventListener(\"mouseup\", onDragStopped);\n document.removeEventListener(\"touchend\", onDragStopped);\n onEventsCleanup();\n }, [store, onEventsCleanup, onRefsCleanup]);\n\n const getWheelDelta = React.useCallback((event: WheelEvent) => {\n let deltaX = event.deltaX;\n let deltaY = event.deltaY;\n let deltaZ = event.deltaZ;\n\n if (event.deltaMode === 1) {\n deltaX *= 16;\n deltaY *= 16;\n deltaZ *= 16;\n } else if (event.deltaMode === 2) {\n deltaX *= 400;\n deltaY *= 400;\n deltaZ *= 400;\n }\n\n return { deltaX, deltaY, deltaZ };\n }, []);\n\n const onWheelZoom = React.useCallback(\n (event: WheelEvent) => {\n propsRef.current.onWheelZoom?.(event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n /*\n * ⚠ Khác thượng nguồn: bản gốc chỉ cập nhật `contentPositionRef` ở `mousedown`/`touchstart`,\n * nên lăn chuột khi CHƯA kéo lần nào (hoặc sau khi trang đã cuộn) tính điểm neo bằng toạ độ\n * khung cũ — mặc định (0, 0) — và ảnh phóng lệch khỏi con trỏ đúng bằng khoảng cách từ mép\n * trang tới khung cắt.\n */\n onContentPositionChange();\n const point = getMousePoint(event);\n const { deltaY } = getWheelDelta(event);\n const newZoom = zoom - (deltaY * context.zoomSpeed) / 200;\n onZoomChange(newZoom, point, true);\n\n store.batch(() => {\n const currentState = store.getState();\n if (!currentState.isWheelZooming) {\n store.setState(\"isWheelZooming\", true);\n }\n if (!currentState.isDragging) {\n store.setState(\"isDragging\", true);\n }\n });\n\n if (wheelTimerRef.current) {\n clearTimeout(wheelTimerRef.current);\n }\n wheelTimerRef.current = window.setTimeout(() => {\n store.batch(() => {\n store.setState(\"isWheelZooming\", false);\n store.setState(\"isDragging\", false);\n });\n }, 250);\n },\n [propsRef, getMousePoint, zoom, context.zoomSpeed, onZoomChange, getWheelDelta, store, onContentPositionChange]\n );\n\n const onKeyUp = React.useCallback(\n (event: React.KeyboardEvent<RootElement>) => {\n propsRef.current.onKeyUp?.(event);\n if (event.defaultPrevented) return;\n\n const arrowKeys = new Set([\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\"]);\n\n // Phím thu phóng cũng khép một lượt tương tác, để `onCropComplete` bắn như khi thả phím mũi tên.\n if (arrowKeys.has(event.key) || ZOOM_IN_KEYS.has(event.key) || ZOOM_OUT_KEYS.has(event.key)) {\n event.preventDefault();\n store.setState(\"isDragging\", false);\n }\n },\n [propsRef, store]\n );\n\n const onKeyDown = React.useCallback(\n (event: React.KeyboardEvent<RootElement>) => {\n propsRef.current.onKeyDown?.(event);\n if (event.defaultPrevented || !cropSize || !mediaSize) return;\n\n /*\n * ⚠ Khác thượng nguồn: thêm + / - để thu phóng quanh TÂM khung. Bản gốc chỉ phóng được bằng\n * con lăn chuột và cử chỉ chụm ngón — người chỉ dùng bàn phím không có đường nào đổi `zoom`\n * nếu app không tự dựng thêm Slider (WCAG 2.1.1). Ctrl/Cmd/Alt + phím là zoom TRÌNH DUYỆT,\n * nên để nguyên cho trình duyệt.\n */\n const zoomDirection = ZOOM_IN_KEYS.has(event.key) ? 1 : ZOOM_OUT_KEYS.has(event.key) ? -1 : 0;\n if (zoomDirection !== 0) {\n if (event.metaKey || event.ctrlKey || event.altKey) return;\n const root = context.rootRef.current;\n if (!root) return;\n\n event.preventDefault();\n\n if (!event.repeat) {\n store.setState(\"isDragging\", true);\n }\n\n const nextZoom = clamp(zoom + zoomDirection * KEYBOARD_ZOOM_STEP, context.minZoom, context.maxZoom);\n onContentPositionChange();\n const rect = root.getBoundingClientRect();\n onZoomChange(nextZoom, { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 }, true);\n setZoomStatus(context.labels.zoomStatus(nextZoom));\n return;\n }\n\n let step = context.keyboardStep;\n if (event.shiftKey) {\n step *= 0.2;\n }\n\n const keyCallbacks: Record<string, () => Point> = {\n ArrowUp: () => ({ ...crop, y: crop.y - step }),\n ArrowDown: () => ({ ...crop, y: crop.y + step }),\n ArrowLeft: () => ({ ...crop, x: crop.x - step }),\n ArrowRight: () => ({ ...crop, x: crop.x + step })\n } as const;\n\n const callback = keyCallbacks[event.key];\n if (!callback) return;\n\n event.preventDefault();\n\n let newCrop = callback();\n\n if (!context.allowOverflow) {\n newCrop = onPositionClamp(newCrop, mediaSize, cropSize, zoom, rotation);\n }\n\n if (!event.repeat) {\n store.setState(\"isDragging\", true);\n }\n\n store.setState(\"crop\", newCrop);\n },\n [\n propsRef,\n cropSize,\n mediaSize,\n context.keyboardStep,\n context.allowOverflow,\n context.rootRef,\n context.minZoom,\n context.maxZoom,\n context.labels,\n crop,\n zoom,\n rotation,\n store,\n onContentPositionChange,\n onZoomChange\n ]\n );\n\n const onMouseDown = React.useCallback(\n (event: React.MouseEvent<RootElement>) => {\n propsRef.current.onMouseDown?.(event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n document.addEventListener(\"mousemove\", onMouseMove);\n document.addEventListener(\"mouseup\", onDragStopped);\n onContentPositionChange();\n onDragStart(getMousePoint(event));\n },\n [propsRef, getMousePoint, onDragStart, onDragStopped, onMouseMove, onContentPositionChange]\n );\n\n const onTouchStart = React.useCallback(\n (event: React.TouchEvent<RootElement>) => {\n propsRef.current.onTouchStart?.(event);\n if (event.defaultPrevented) return;\n\n isTouchingRef.current = true;\n document.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n document.addEventListener(\"touchend\", onDragStopped);\n onContentPositionChange();\n\n if (event.touches.length === 2) {\n const [firstTouch, secondTouch] = event.touches ? Array.from(event.touches) : [];\n if (firstTouch && secondTouch) {\n const pointA = getTouchPoint(firstTouch);\n const pointB = getTouchPoint(secondTouch);\n lastPinchDistanceRef.current = getDistanceBetweenPoints(pointA, pointB);\n lastPinchRotationRef.current = getRotationBetweenPoints(pointA, pointB);\n onDragStart(getCenter(pointA, pointB));\n }\n } else if (event.touches.length === 1) {\n const firstTouch = event.touches[0];\n if (firstTouch) {\n onDragStart(getTouchPoint(firstTouch));\n }\n }\n },\n [propsRef, onDragStopped, onTouchMove, onContentPositionChange, getTouchPoint, onDragStart]\n );\n\n React.useEffect(() => {\n const content = context.rootRef?.current;\n if (!content) return;\n\n if (!context.preventScrollZoom) {\n content.addEventListener(\"wheel\", onWheelZoom, { passive: false });\n }\n\n content.addEventListener(\"gesturestart\", onSafariZoomPrevent);\n content.addEventListener(\"gesturestart\", onGestureStart as EventListener);\n\n return () => {\n if (!context.preventScrollZoom) {\n content.removeEventListener(\"wheel\", onWheelZoom);\n }\n content.removeEventListener(\"gesturestart\", onSafariZoomPrevent);\n content.removeEventListener(\"gesturestart\", onGestureStart as EventListener);\n /*\n * ⚠ Khác thượng nguồn: bản gốc gọi `onRefsCleanup()` ở đây. Effect này chạy lại MỖI lần\n * `zoom` đổi (vì `onWheelZoom` phụ thuộc `zoom`), nên nó huỷ đúng cái hẹn giờ 250ms mà lượt\n * lăn chuột vừa đặt để khép tương tác: `isDragging` kẹt ở `true`, và `onCropComplete` /\n * `onInteractionEnd` KHÔNG BAO GIỜ bắn sau khi phóng bằng con lăn (đo trên trình duyệt thật:\n * lăn một nấc, chờ 400ms, `onCropComplete` 0 lần). Dọn khi gỡ component đã có effect ngay dưới.\n */\n };\n }, [context.rootRef, context.preventScrollZoom, onWheelZoom, onSafariZoomPrevent, onGestureStart]);\n\n React.useEffect(() => {\n return () => {\n onRefsCleanup();\n onCacheCleanup();\n };\n }, [onRefsCleanup, onCacheCleanup]);\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n const describedBy = [descriptionId, ariaDescribedByProp].filter(Boolean).join(\" \");\n\n return (\n <>\n <RootPrimitive\n /*\n * ⚠ Khác thượng nguồn: bản gốc là một `<div tabIndex={0}>` KHÔNG role, KHÔNG tên — Tab tới\n * được nhưng trình đọc màn hình không biết đó là gì, cũng không biết phím nào dùng được.\n * `role=\"application\"` (không phải `group`) là CỐ Ý: vùng này sống nhờ phím mũi tên và\n * + / -, mà với `group` thì NVDA/JAWS ở chế độ duyệt nuốt mất phím mũi tên trước khi tới\n * handler; `application` bật chế độ focus. Bên trong không có nội dung đọc được nào bị\n * che đi — chỉ có ảnh đang cắt và khung vẽ. App ghi đè được cả ba qua `labels` hoặc\n * truyền thẳng `aria-label` / `aria-roledescription`.\n */\n role=\"application\"\n aria-roledescription={context.labels.roleDescription}\n aria-label={context.labels.label}\n aria-describedby={describedBy}\n data-slot=\"cropper\"\n tabIndex={0}\n {...rootImplProps}\n ref={composedRef}\n className={cn(\n \"absolute inset-0 flex cursor-move touch-none items-center justify-center overflow-hidden outline-none select-none\",\n /*\n * ⚠ Khác thượng nguồn: bản gốc `outline-none` mà KHÔNG có chỉ báo focus nào (WCAG 2.4.7).\n * Vòng focus vẽ trên `::after` phủ kín khung chứ không trên chính phần tử: ảnh và khung\n * cắt là con `absolute` nên được vẽ ĐÈ lên outline của cha, còn `::after` là con cuối\n * cùng nên nằm trên cùng. Cùng khuôn `outline-ring` với `Button`, thụt vào trong vì hai\n * lớp bọc ngoài đều `overflow-hidden`.\n */\n \"after:pointer-events-none after:absolute after:inset-0 focus-visible:after:-outline-offset-2 focus-visible:after:outline-2 focus-visible:after:outline-ring\",\n className\n )}\n onKeyUp={onKeyUp}\n onKeyDown={onKeyDown}\n onMouseDown={onMouseDown}\n onTouchStart={onTouchStart}\n />\n {/* `hidden` vẫn làm nguồn được cho `aria-describedby`, và không bị đọc lặp ở chế độ duyệt. */}\n <span id={descriptionId} hidden>\n {context.labels.instructions}\n </span>\n <span aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {zoomStatus}\n </span>\n </>\n );\n}\n\nconst cropperMediaVariants = cva(\"will-change-transform\", {\n variants: {\n objectFit: {\n contain: \"absolute inset-0 m-auto max-h-full max-w-full\",\n cover: \"h-auto w-full\",\n \"horizontal-cover\": \"h-auto w-full\",\n \"vertical-cover\": \"h-full w-auto\"\n }\n },\n defaultVariants: {\n objectFit: \"contain\"\n }\n});\n\ninterface UseMediaComputationProps<T extends HTMLImageElement | HTMLVideoElement> {\n mediaRef: React.RefObject<T | null>;\n context: CropperContextValue;\n store: Store;\n rotation: number;\n getNaturalDimensions: (media: T) => Size;\n}\n\nfunction useMediaComputation<T extends HTMLImageElement | HTMLVideoElement>({\n mediaRef,\n context,\n store,\n rotation,\n getNaturalDimensions\n}: UseMediaComputationProps<T>) {\n const computeSizes = React.useCallback(() => {\n const media = mediaRef.current;\n const content = context.rootRef?.current;\n if (!media || !content) return;\n\n const contentRect = content.getBoundingClientRect();\n const containerAspect = contentRect.width / contentRect.height;\n const { width: naturalWidth, height: naturalHeight } = getNaturalDimensions(media);\n const isScaledDown = media.offsetWidth < naturalWidth || media.offsetHeight < naturalHeight;\n const mediaAspect = naturalWidth / naturalHeight;\n\n let renderedMediaSize: Size;\n\n if (isScaledDown) {\n const objectFitCallbacks = {\n contain: () =>\n containerAspect > mediaAspect\n ? {\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }\n : {\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n },\n \"horizontal-cover\": () => ({\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n }),\n \"vertical-cover\": () => ({\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }),\n cover: () =>\n containerAspect < mediaAspect\n ? {\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n }\n : {\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }\n } as const;\n\n const callback = objectFitCallbacks[context.objectFit];\n renderedMediaSize = callback\n ? callback()\n : containerAspect > mediaAspect\n ? {\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }\n : {\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n };\n } else {\n renderedMediaSize = {\n width: media.offsetWidth,\n height: media.offsetHeight\n };\n }\n\n const mediaSize: MediaSize = {\n ...renderedMediaSize,\n naturalWidth,\n naturalHeight\n };\n\n store.setState(\"mediaSize\", mediaSize);\n\n const cropSize = getCropSize(\n mediaSize.width,\n mediaSize.height,\n contentRect.width,\n contentRect.height,\n context.aspectRatio,\n rotation\n );\n\n store.setState(\"cropSize\", cropSize);\n\n requestAnimationFrame(() => {\n const currentState = store.getState();\n if (currentState.cropSize && currentState.mediaSize) {\n const newPosition = onPositionClamp(\n currentState.crop,\n currentState.mediaSize,\n currentState.cropSize,\n currentState.zoom,\n currentState.rotation\n );\n\n if (\n Math.abs(newPosition.x - currentState.crop.x) > 0.001 ||\n Math.abs(newPosition.y - currentState.crop.y) > 0.001\n ) {\n store.setState(\"crop\", newPosition);\n }\n }\n });\n\n return { mediaSize, cropSize };\n }, [mediaRef, context.aspectRatio, context.rootRef, context.objectFit, store, rotation, getNaturalDimensions]);\n\n return { computeSizes };\n}\n\ninterface CropperImageProps extends React.ComponentProps<\"img\">, VariantProps<typeof cropperMediaVariants> {\n asChild?: boolean;\n snapPixels?: boolean;\n}\n\n/** Ảnh cần cắt. Nhớ truyền `alt` — ảnh ở đây mang nội dung, không phải trang trí. */\nfunction CropperImage(props: CropperImageProps) {\n const { className, style, asChild, ref, onLoad, objectFit, snapPixels = false, ...imageProps } = props;\n\n const context = useCropperContext(IMAGE_NAME);\n const store = useStoreContext(IMAGE_NAME);\n const crop = useStore((state) => state.crop);\n const zoom = useStore((state) => state.zoom);\n const rotation = useStore((state) => state.rotation);\n const dpr = useDevicePixelRatio();\n\n const imageRef = React.useRef<HTMLImageElement>(null);\n const composedRef = useComposedRefs(ref, imageRef);\n\n const getNaturalDimensions = React.useCallback(\n (image: HTMLImageElement) => ({\n width: image.naturalWidth,\n height: image.naturalHeight\n }),\n []\n );\n\n const { computeSizes } = useMediaComputation({\n mediaRef: imageRef,\n context,\n store,\n rotation,\n getNaturalDimensions\n });\n\n const onMediaLoad = React.useCallback(() => {\n const image = imageRef.current;\n if (!image) return;\n\n computeSizes();\n\n onLoad?.(new Event(\"load\") as unknown as React.SyntheticEvent<HTMLImageElement>);\n }, [computeSizes, onLoad]);\n\n React.useEffect(() => {\n const image = imageRef.current;\n if (image?.complete && image.naturalWidth > 0) {\n onMediaLoad();\n }\n }, [onMediaLoad]);\n\n React.useEffect(() => {\n const content = context.rootRef?.current;\n if (!content) return;\n\n if (typeof ResizeObserver !== \"undefined\") {\n let isFirstResize = true;\n const resizeObserver = new ResizeObserver(() => {\n if (isFirstResize) {\n isFirstResize = false;\n return;\n }\n\n const callback = () => {\n const image = imageRef.current;\n if (image?.complete && image.naturalWidth > 0) {\n computeSizes();\n }\n };\n\n if (\"requestIdleCallback\" in window) {\n requestIdleCallback(callback);\n } else {\n setTimeout(callback, 16);\n }\n });\n\n resizeObserver.observe(content);\n\n return () => {\n resizeObserver.disconnect();\n };\n } else {\n const onWindowResize = () => {\n const image = imageRef.current;\n if (image?.complete && image.naturalWidth > 0) {\n computeSizes();\n }\n };\n\n window.addEventListener(\"resize\", onWindowResize);\n return () => {\n window.removeEventListener(\"resize\", onWindowResize);\n };\n }\n }, [context.rootRef, computeSizes]);\n\n const ImagePrimitive = asChild ? Slot : \"img\";\n\n return (\n <ImagePrimitive\n data-slot=\"cropper-image\"\n {...imageProps}\n ref={composedRef}\n className={cn(\n cropperMediaVariants({\n objectFit: objectFit ?? context.objectFit,\n className\n })\n )}\n style={{\n transform: snapPixels\n ? `translate(${snapToDevicePixel(crop.x, dpr)}px, ${snapToDevicePixel(crop.y, dpr)}px) rotate(${rotation}deg) scale(${zoom})`\n : `translate(${crop.x}px, ${crop.y}px) rotate(${rotation}deg) scale(${zoom})`,\n ...style\n }}\n onLoad={onMediaLoad}\n />\n );\n}\n\ninterface CropperVideoProps extends React.ComponentProps<\"video\">, VariantProps<typeof cropperMediaVariants> {\n asChild?: boolean;\n snapPixels?: boolean;\n}\n\nfunction CropperVideo(props: CropperVideoProps) {\n const { className, style, asChild, ref, onLoadedMetadata, objectFit, snapPixels = false, ...videoProps } = props;\n\n const context = useCropperContext(VIDEO_NAME);\n const store = useStoreContext(VIDEO_NAME);\n const crop = useStore((state) => state.crop);\n const zoom = useStore((state) => state.zoom);\n const rotation = useStore((state) => state.rotation);\n const dpr = useDevicePixelRatio();\n\n const videoRef = React.useRef<HTMLVideoElement>(null);\n const composedRef = useComposedRefs(ref, videoRef);\n\n const getNaturalDimensions = React.useCallback(\n (video: HTMLVideoElement) => ({\n width: video.videoWidth,\n height: video.videoHeight\n }),\n []\n );\n\n const { computeSizes } = useMediaComputation({\n mediaRef: videoRef,\n context,\n store,\n rotation,\n getNaturalDimensions\n });\n\n const onMediaLoad = React.useCallback(() => {\n const video = videoRef.current;\n if (!video) return;\n\n computeSizes();\n\n onLoadedMetadata?.(new Event(\"loadedmetadata\") as unknown as React.SyntheticEvent<HTMLVideoElement>);\n }, [computeSizes, onLoadedMetadata]);\n\n React.useEffect(() => {\n const content = context.rootRef?.current;\n if (!content) return;\n\n if (typeof ResizeObserver !== \"undefined\") {\n let isFirstResize = true;\n const resizeObserver = new ResizeObserver(() => {\n if (isFirstResize) {\n isFirstResize = false;\n return;\n }\n\n const callback = () => {\n const video = videoRef.current;\n if (video && video.videoWidth > 0 && video.videoHeight > 0) {\n computeSizes();\n }\n };\n\n if (\"requestIdleCallback\" in window) {\n requestIdleCallback(callback);\n } else {\n setTimeout(callback, 16);\n }\n });\n\n resizeObserver.observe(content);\n\n return () => {\n resizeObserver.disconnect();\n };\n } else {\n const onWindowResize = () => {\n const video = videoRef.current;\n if (video && video.videoWidth > 0 && video.videoHeight > 0) {\n computeSizes();\n }\n };\n\n window.addEventListener(\"resize\", onWindowResize);\n return () => {\n window.removeEventListener(\"resize\", onWindowResize);\n };\n }\n }, [context.rootRef, computeSizes]);\n\n const VideoPrimitive = asChild ? Slot : \"video\";\n\n return (\n <VideoPrimitive\n data-slot=\"cropper-video\"\n autoPlay\n playsInline\n loop\n muted\n controls={false}\n {...videoProps}\n ref={composedRef}\n className={cn(\n cropperMediaVariants({\n objectFit: objectFit ?? context.objectFit,\n className\n })\n )}\n style={{\n transform: snapPixels\n ? `translate(${snapToDevicePixel(crop.x, dpr)}px, ${snapToDevicePixel(crop.y, dpr)}px) rotate(${rotation}deg) scale(${zoom})`\n : `translate(${crop.x}px, ${crop.y}px) rotate(${rotation}deg) scale(${zoom})`,\n ...style\n }}\n onLoadedMetadata={onMediaLoad}\n />\n );\n}\n\n/*\n * ⚠ Khác thượng nguồn — màu. Khung cắt nằm trên ẢNH, không trên nền trang, nên cặp màu ở đây\n * không đổi theo theme (ảnh là ảnh ở cả sáng lẫn tối):\n * · vùng ngoài khung tối đi bằng MÀU LỚP PHỦ của `DialogOverlay` (`ink/60`, `ink/80` ở tối),\n * vẽ bằng bóng 9999em như bản gốc — bản gốc viết thẳng `rgba(0,0,0,0.5)`. Đây là một tấm\n * phủ, KHÔNG phải bóng đổ độ cao, nên không đi qua thang `shadow-card`/`shadow-overlay`;\n * màu vẫn là token nên đổi theo `--ink` của app.\n * · khung là `paper` (bản gốc `white/90`): màu đi cặp với lớp phủ mực, sáng ở MỌI theme và mọi\n * bảng màu. Ca tệ nhất — điểm ảnh TRẮNG nằm dưới lớp phủ: 4,65:1 (ink/60) · 9,60:1 (ink/80),\n * ≥ 3:1 cho thành phần phi văn bản. `--background`/`--foreground` KHÔNG dùng được: chúng đảo\n * theo theme trong khi lớp phủ thì luôn tối.\n * · lưới 1/3 (`paper/50`) là đường gióng bố cục thuần trang trí, nằm trên phần ảnh KHÔNG phủ.\n */\nconst cropperAreaVariants = cva(\n \"absolute top-1/2 left-1/2 box-border -translate-x-1/2 -translate-y-1/2 overflow-hidden border border-[2.5px] border-paper shadow-[0_0_0_9999em] shadow-ink/60 dark:shadow-ink/80\",\n {\n variants: {\n shape: {\n rectangle: \"\",\n circle: \"rounded-full\"\n },\n withGrid: {\n true: \"before:absolute before:top-0 before:right-1/3 before:bottom-0 before:left-1/3 before:box-border before:border before:border-t-0 before:border-b-0 before:border-paper/50 before:content-[''] after:absolute after:top-1/3 after:right-0 after:bottom-1/3 after:left-0 after:box-border after:border after:border-r-0 after:border-l-0 after:border-paper/50 after:content-['']\",\n false: \"\"\n }\n },\n defaultVariants: {\n shape: \"rectangle\",\n withGrid: false\n }\n }\n);\n\ninterface CropperAreaProps extends DivProps, VariantProps<typeof cropperAreaVariants> {\n snapPixels?: boolean;\n}\n\nfunction CropperArea(props: CropperAreaProps) {\n const { className, style, asChild, ref, snapPixels = false, shape, withGrid, ...areaProps } = props;\n\n const context = useCropperContext(AREA_NAME);\n const cropSize = useStore((state) => state.cropSize);\n\n if (!cropSize) return null;\n\n const AreaPrimitive = asChild ? Slot : \"div\";\n\n return (\n <AreaPrimitive\n data-slot=\"cropper-area\"\n {...areaProps}\n ref={ref}\n className={cn(\n cropperAreaVariants({\n shape: shape ?? context.shape,\n withGrid: withGrid ?? context.withGrid,\n className\n })\n )}\n style={{\n width: snapPixels ? Math.round(cropSize.width) : cropSize.width,\n height: snapPixels ? Math.round(cropSize.height) : cropSize.height,\n ...style\n }}\n />\n );\n}\n\nexport {\n type Area as CropperAreaData,\n Cropper,\n CropperArea,\n type CropperAreaProps,\n CropperImage,\n type CropperImageProps,\n type CropperProps,\n CropperVideo,\n type CropperVideoProps,\n type MediaSize as CropperMediaSize,\n type ObjectFit as CropperObjectFit,\n type Point as CropperPoint,\n type Shape as CropperShape,\n type Size as CropperSize,\n useStore as useCropper\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/cropper.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/cropper) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { useComitorLabels } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport type { CropperLabels } from \"./cropper-constants.js\";\n\nconst ROOT_NAME = \"Cropper\";\nconst ROOT_IMPL_NAME = \"CropperImpl\";\nconst IMAGE_NAME = \"CropperImage\";\nconst VIDEO_NAME = \"CropperVideo\";\nconst AREA_NAME = \"CropperArea\";\n\ninterface Point {\n x: number;\n y: number;\n}\n\ninterface GestureEvent extends UIEvent {\n rotation: number;\n scale: number;\n clientX: number;\n clientY: number;\n}\n\ninterface Size {\n width: number;\n height: number;\n}\n\ninterface Area {\n width: number;\n height: number;\n x: number;\n y: number;\n}\n\ninterface MediaSize {\n width: number;\n height: number;\n naturalWidth: number;\n naturalHeight: number;\n}\n\ntype Shape = \"rectangle\" | \"circle\";\ntype ObjectFit = \"contain\" | \"cover\" | \"horizontal-cover\" | \"vertical-cover\";\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\nconst MAX_CACHE_SIZE = 200;\n\n/*\n * ⚠ Thêm so với thượng nguồn: phím + / - để thu phóng (xem `onKeyDown` của `CropperImpl`).\n * `=` và `_` là cùng phím với `+` / `-` khi KHÔNG giữ Shift trên bàn phím US.\n */\nconst ZOOM_IN_KEYS = new Set([\"+\", \"=\"]);\nconst ZOOM_OUT_KEYS = new Set([\"-\", \"_\"]);\nconst KEYBOARD_ZOOM_STEP = 0.1;\n\n/*\n * ⚠ Khác thượng nguồn: bản gốc chụp `window.devicePixelRatio` vào một HẰNG ở cấp module\n * (`const DPR = typeof window …`). Hệ quả: module chạm `window` ngay lúc nạp; server luôn ra 1 còn\n * client ra 2 nên `style` của ảnh lệch nhau lúc hydrate khi bật `snapPixels`; và zoom trình duyệt\n * thì con số không bao giờ cập nhật. Nay đọc LƯỜI — trong handler/effect gọi hàm này, còn lượt\n * render đi qua `useDevicePixelRatio` (server và lượt hydrate luôn nhận 1).\n */\nfunction getDevicePixelRatio(): number {\n return typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1;\n}\n\nfunction getServerDevicePixelRatio(): number {\n return 1;\n}\n\nfunction subscribeToDevicePixelRatio(onChange: () => void) {\n // Zoom trình duyệt đổi DPR và bắn `resize`.\n window.addEventListener(\"resize\", onChange);\n return () => window.removeEventListener(\"resize\", onChange);\n}\n\nfunction useDevicePixelRatio(): number {\n return React.useSyncExternalStore(subscribeToDevicePixelRatio, getDevicePixelRatio, getServerDevicePixelRatio);\n}\n\nconst rotationSizeCache = new Map<string, Size>();\nconst cropSizeCache = new Map<string, Size>();\nconst croppedAreaCache = new Map<string, { croppedAreaPercentages: Area; croppedAreaPixels: Area }>();\nconst onPositionClampCache = new Map<string, Point>();\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction quantize(n: number, step = 2 / getDevicePixelRatio()): number {\n return Math.round(n / step) * step;\n}\n\nfunction quantizePosition(n: number, step = 4 / getDevicePixelRatio()): number {\n return Math.round(n / step) * step;\n}\n\nfunction quantizeZoom(n: number, step = 0.01): number {\n return Math.round(n / step) * step;\n}\n\nfunction quantizeRotation(n: number, step = 1.0): number {\n return Math.round(n / step) * step;\n}\n\nfunction snapToDevicePixel(n: number, dpr: number): number {\n return Math.round(n * dpr) / dpr;\n}\n\nfunction lruGet<K, V>(map: Map<K, V>, key: K): V | undefined {\n const v = map.get(key);\n if (v !== undefined) {\n map.delete(key);\n map.set(key, v);\n }\n return v;\n}\n\nfunction lruSet<K, V>(map: Map<K, V>, key: K, val: V, max = MAX_CACHE_SIZE): void {\n if (map.has(key)) {\n map.delete(key);\n }\n map.set(key, val);\n if (map.size > max) {\n const firstKey = map.keys().next().value;\n if (firstKey !== undefined) {\n map.delete(firstKey);\n }\n }\n}\n\nfunction getDistanceBetweenPoints(pointA: Point, pointB: Point): number {\n return Math.sqrt((pointA.y - pointB.y) ** 2 + (pointA.x - pointB.x) ** 2);\n}\n\nfunction getCenter(a: Point, b: Point): Point {\n return {\n x: (b.x + a.x) * 0.5,\n y: (b.y + a.y) * 0.5\n };\n}\n\nfunction getRotationBetweenPoints(pointA: Point, pointB: Point): number {\n return (Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x) * 180) / Math.PI;\n}\n\nfunction getRadianAngle(degreeValue: number): number {\n return (degreeValue * Math.PI) / 180;\n}\n\nfunction rotateSize(width: number, height: number, rotation: number): Size {\n const cacheKey = `${quantize(width)}-${quantize(height)}-${quantizeRotation(rotation)}`;\n\n const cached = lruGet(rotationSizeCache, cacheKey);\n if (cached) {\n return cached;\n }\n const rotRad = getRadianAngle(rotation);\n const cosRot = Math.cos(rotRad);\n const sinRot = Math.sin(rotRad);\n\n const result: Size = {\n width: Math.abs(cosRot * width) + Math.abs(sinRot * height),\n height: Math.abs(sinRot * width) + Math.abs(cosRot * height)\n };\n\n lruSet(rotationSizeCache, cacheKey, result, MAX_CACHE_SIZE);\n return result;\n}\n\nfunction getCropSize(\n mediaWidth: number,\n mediaHeight: number,\n contentWidth: number,\n contentHeight: number,\n aspect: number,\n rotation = 0\n): Size {\n const cacheKey = `${quantize(mediaWidth, 8)}-${quantize(mediaHeight, 8)}-${quantize(contentWidth, 8)}-${quantize(contentHeight, 8)}-${quantize(aspect, 0.01)}-${quantizeRotation(rotation)}`;\n\n const cached = lruGet(cropSizeCache, cacheKey);\n if (cached) {\n return cached;\n }\n const { width, height } = rotateSize(mediaWidth, mediaHeight, rotation);\n const fittingWidth = Math.min(width, contentWidth);\n const fittingHeight = Math.min(height, contentHeight);\n\n const result: Size =\n fittingWidth > fittingHeight * aspect\n ? {\n width: fittingHeight * aspect,\n height: fittingHeight\n }\n : {\n width: fittingWidth,\n height: fittingWidth / aspect\n };\n\n lruSet(cropSizeCache, cacheKey, result, MAX_CACHE_SIZE);\n return result;\n}\n\nfunction onPositionClamp(position: Point, mediaSize: Size, cropSize: Size, zoom: number, rotation = 0): Point {\n /*\n * ⚠ Khác thượng nguồn: bản gốc cache CẢ KẾT QUẢ, với khoá chứa vị trí đã lượng tử hoá (bước\n * 4/DPR px) — hai vị trí khác nhau rơi cùng một ô thì nhận lại kết quả của vị trí TRƯỚC. Phím\n * mũi tên dời 1px (Shift: 0,2px) nên vị trí mới luôn rơi vào ô của vị trí cũ và cache trả lại\n * đúng vị trí cũ: ảnh KẸT sau lần bấm đầu tiên — đo trên trình duyệt thật, 20 lần → phải đúng\n * 1px. Tức bàn phím không dời được ảnh. Nay chỉ cache GIỚI HẠN kẹp (thứ phụ thuộc kích thước,\n * zoom, góc — không phụ thuộc vị trí, cùng cách lượng tử hoá như bản gốc) và kẹp vị trí THẬT.\n */\n const cacheKey = `${quantize(mediaSize.width)}-${quantize(mediaSize.height)}-${quantize(cropSize.width)}-${quantize(cropSize.height)}-${quantizeZoom(zoom)}-${quantizeRotation(rotation)}`;\n\n let maxPosition = lruGet(onPositionClampCache, cacheKey);\n if (!maxPosition) {\n const { width, height } = rotateSize(mediaSize.width, mediaSize.height, rotation);\n\n maxPosition = {\n x: width * zoom * 0.5 - cropSize.width * 0.5,\n y: height * zoom * 0.5 - cropSize.height * 0.5\n };\n\n lruSet(onPositionClampCache, cacheKey, maxPosition, MAX_CACHE_SIZE);\n }\n\n return {\n x: clamp(position.x, -maxPosition.x, maxPosition.x),\n y: clamp(position.y, -maxPosition.y, maxPosition.y)\n };\n}\n\nfunction getCroppedArea(\n crop: Point,\n mediaSize: MediaSize,\n cropSize: Size,\n aspect: number,\n zoom: number,\n rotation = 0,\n allowOverflow = false\n): { croppedAreaPercentages: Area; croppedAreaPixels: Area } {\n const cacheKey = `${quantizePosition(crop.x)}-${quantizePosition(crop.y)}-${quantize(mediaSize.width)}-${quantize(mediaSize.height)}-${quantize(mediaSize.naturalWidth)}-${quantize(mediaSize.naturalHeight)}-${quantize(cropSize.width)}-${quantize(cropSize.height)}-${quantize(aspect, 0.01)}-${quantizeZoom(zoom)}-${quantizeRotation(rotation)}-${allowOverflow}`;\n\n const cached = lruGet(croppedAreaCache, cacheKey);\n\n if (cached) return cached;\n\n const onAreaLimit = !allowOverflow\n ? (max: number, value: number) => Math.min(max, Math.max(0, value))\n : (_max: number, value: number) => value;\n\n const mediaBBoxSize = rotateSize(mediaSize.width, mediaSize.height, rotation);\n const mediaNaturalBBoxSize = rotateSize(mediaSize.naturalWidth, mediaSize.naturalHeight, rotation);\n\n const croppedAreaPercentages: Area = {\n x: onAreaLimit(\n 100,\n (((mediaBBoxSize.width - cropSize.width / zoom) / 2 - crop.x / zoom) / mediaBBoxSize.width) * 100\n ),\n y: onAreaLimit(\n 100,\n (((mediaBBoxSize.height - cropSize.height / zoom) / 2 - crop.y / zoom) / mediaBBoxSize.height) * 100\n ),\n width: onAreaLimit(100, ((cropSize.width / mediaBBoxSize.width) * 100) / zoom),\n height: onAreaLimit(100, ((cropSize.height / mediaBBoxSize.height) * 100) / zoom)\n };\n\n const widthInPixels = Math.round(\n onAreaLimit(mediaNaturalBBoxSize.width, (croppedAreaPercentages.width * mediaNaturalBBoxSize.width) / 100)\n );\n const heightInPixels = Math.round(\n onAreaLimit(mediaNaturalBBoxSize.height, (croppedAreaPercentages.height * mediaNaturalBBoxSize.height) / 100)\n );\n const isImageWiderThanHigh = mediaNaturalBBoxSize.width >= mediaNaturalBBoxSize.height * aspect;\n\n const sizePixels: Size = isImageWiderThanHigh\n ? {\n width: Math.round(heightInPixels * aspect),\n height: heightInPixels\n }\n : {\n width: widthInPixels,\n height: Math.round(widthInPixels / aspect)\n };\n\n const croppedAreaPixels: Area = {\n ...sizePixels,\n x: Math.round(\n onAreaLimit(\n mediaNaturalBBoxSize.width - sizePixels.width,\n (croppedAreaPercentages.x * mediaNaturalBBoxSize.width) / 100\n )\n ),\n y: Math.round(\n onAreaLimit(\n mediaNaturalBBoxSize.height - sizePixels.height,\n (croppedAreaPercentages.y * mediaNaturalBBoxSize.height) / 100\n )\n )\n };\n\n const result = { croppedAreaPercentages, croppedAreaPixels };\n\n lruSet(croppedAreaCache, cacheKey, result, MAX_CACHE_SIZE);\n return result;\n}\n\ninterface StoreState {\n crop: Point;\n zoom: number;\n rotation: number;\n mediaSize: MediaSize | null;\n cropSize: Size | null;\n isDragging: boolean;\n isWheelZooming: boolean;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;\n notify: () => void;\n batch: (fn: () => void) => void;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\nfunction useStore<T>(selector: (state: StoreState) => T): T {\n // Tên trong thông báo lỗi là tên XUẤT RA NGOÀI (`useCropper`), không phải tên nội bộ.\n const store = useStoreContext(\"useCropper\");\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ntype RootElement = React.ComponentRef<typeof CropperImpl>;\n\ninterface CropperContextValue {\n aspectRatio: number;\n minZoom: number;\n maxZoom: number;\n zoomSpeed: number;\n keyboardStep: number;\n shape: Shape;\n objectFit: ObjectFit;\n rootRef: React.RefObject<RootElement | null>;\n allowOverflow: boolean;\n preventScrollZoom: boolean;\n withGrid: boolean;\n labels: CropperLabels;\n}\n\nconst CropperContext = React.createContext<CropperContextValue | null>(null);\n\nfunction useCropperContext(consumerName: string) {\n const context = React.useContext(CropperContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface CropperProps extends DivProps {\n crop?: Point;\n zoom?: number;\n minZoom?: number;\n maxZoom?: number;\n zoomSpeed?: number;\n rotation?: number;\n keyboardStep?: number;\n aspectRatio?: number;\n shape?: Shape;\n objectFit?: ObjectFit;\n allowOverflow?: boolean;\n preventScrollZoom?: boolean;\n withGrid?: boolean;\n /**\n * Chuỗi a11y của vùng cắt — ghi đè từng khoá. Không truyền thì theo namespace `cropper` của\n * `ComitorLocaleProvider` (mặc định tiếng Anh).\n *\n * ⚠ Thêm so với thượng nguồn — xem `CropperLabels`.\n */\n labels?: Partial<CropperLabels>;\n onCropChange?: (crop: Point) => void;\n onCropSizeChange?: (cropSize: Size) => void;\n onCropAreaChange?: (croppedArea: Area, croppedAreaPixels: Area) => void;\n onCropComplete?: (croppedArea: Area, croppedAreaPixels: Area) => void;\n onZoomChange?: (zoom: number) => void;\n onRotationChange?: (rotation: number) => void;\n onMediaLoaded?: (mediaSize: MediaSize) => void;\n onInteractionStart?: () => void;\n onInteractionEnd?: () => void;\n onWheelZoom?: (event: WheelEvent) => void;\n}\n\n/**\n * Cropper — cắt ảnh/video: kéo để dời, lăn chuột/chụm hai ngón để phóng, phím mũi tên và + / -.\n *\n * Ở Comitor dùng để cắt ảnh đại diện hoặc logo công ty TRƯỚC khi tải lên. Component chỉ BÁO vùng\n * cắt (`onCropComplete(croppedArea, croppedAreaPixels)`) — việc vẽ ra canvas và tải lên là của\n * app. Cố ý không phụ thuộc gì ngoài peer bắt buộc để sống được ở entry chính; `ImageUploadField`\n * (entry `/uploader`, kéo theo `@uppy/*`) ghép với nó ở tầng app, không ở đây.\n *\n * `crop` / `zoom` / `rotation` là controlled KHI được truyền, uncontrolled khi bỏ trống.\n */\nfunction Cropper(props: CropperProps) {\n const {\n /*\n * ⚠ Khác thượng nguồn: bản gốc gán mặc định ngay ở đây (`crop = { x: 0, y: 0 }`, `zoom = 1`,\n * `rotation = 0`), nên nhánh `!== undefined` trong effect đồng bộ bên dưới LUÔN đúng, và\n * `{ x: 0, y: 0 }` là object MỚI mỗi lượt render. Hệ quả ở chế độ không kiểm soát: mỗi lần\n * component cha render lại — kể cả vì chính `onCropComplete` gọi `setState` ở cha — vị trí và\n * độ phóng bị kéo về mặc định ngay sau khi người dùng vừa chỉnh xong. Mặc định nay chỉ dùng\n * cho state KHỞI TẠO; effect chỉ đồng bộ prop nào thật sự được truyền, đúng ý của nhánh đó.\n */\n crop: cropProp,\n zoom: zoomProp,\n minZoom = 1,\n maxZoom = 3,\n zoomSpeed = 1,\n rotation: rotationProp,\n keyboardStep = 1,\n aspectRatio = 4 / 3,\n shape = \"rectangle\",\n objectFit = \"contain\",\n allowOverflow = false,\n preventScrollZoom = false,\n withGrid = false,\n labels: labelsProp,\n onCropChange,\n onCropSizeChange,\n onCropAreaChange,\n onCropComplete,\n onZoomChange,\n onRotationChange,\n onMediaLoaded,\n onInteractionStart,\n onInteractionEnd,\n className,\n ...rootProps\n } = props;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<StoreState>(() => ({\n crop: cropProp ?? { x: 0, y: 0 },\n zoom: zoomProp ?? 1,\n rotation: rotationProp ?? 0,\n mediaSize: null,\n cropSize: null,\n isDragging: false,\n isWheelZooming: false\n }));\n\n const propsRef = useAsRef({\n onCropChange,\n onCropSizeChange,\n onCropAreaChange,\n onCropComplete,\n onZoomChange,\n onRotationChange,\n onMediaLoaded,\n onInteractionStart,\n onInteractionEnd\n });\n\n const rootRef = React.useRef<RootElement | null>(null);\n\n const store = React.useMemo<Store>(() => {\n let isBatching = false;\n let raf: number | null = null;\n\n function notifyCropAreaChange() {\n if (raf != null) return;\n raf = requestAnimationFrame(() => {\n raf = null;\n const s = stateRef.current;\n if (s?.mediaSize && s.cropSize && propsRef.current.onCropAreaChange) {\n const { croppedAreaPercentages, croppedAreaPixels } = getCroppedArea(\n s.crop,\n s.mediaSize,\n s.cropSize,\n aspectRatio,\n s.zoom,\n s.rotation\n );\n propsRef.current.onCropAreaChange(croppedAreaPercentages, croppedAreaPixels);\n }\n });\n }\n\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n stateRef.current[key] = value;\n\n if (key === \"crop\" && typeof value === \"object\" && value && \"x\" in value) {\n propsRef.current.onCropChange?.(value);\n } else if (key === \"zoom\" && typeof value === \"number\") {\n propsRef.current.onZoomChange?.(value);\n } else if (key === \"rotation\" && typeof value === \"number\") {\n propsRef.current.onRotationChange?.(value);\n } else if (key === \"cropSize\" && typeof value === \"object\" && value && \"width\" in value) {\n propsRef.current.onCropSizeChange?.(value);\n } else if (key === \"mediaSize\" && typeof value === \"object\" && value && \"naturalWidth\" in value) {\n propsRef.current.onMediaLoaded?.(value);\n } else if (key === \"isDragging\") {\n if (value) {\n propsRef.current.onInteractionStart?.();\n } else {\n propsRef.current.onInteractionEnd?.();\n const currentState = stateRef.current;\n if (currentState?.mediaSize && currentState.cropSize && propsRef.current.onCropComplete) {\n const { croppedAreaPercentages, croppedAreaPixels } = getCroppedArea(\n currentState.crop,\n currentState.mediaSize,\n currentState.cropSize,\n aspectRatio,\n currentState.zoom,\n currentState.rotation\n );\n propsRef.current.onCropComplete(croppedAreaPercentages, croppedAreaPixels);\n }\n }\n }\n\n if (\n (key === \"crop\" || key === \"zoom\" || key === \"rotation\" || key === \"mediaSize\" || key === \"cropSize\") &&\n propsRef.current.onCropAreaChange\n ) {\n notifyCropAreaChange();\n }\n\n if (!isBatching) {\n store.notify();\n }\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n },\n batch: (fn: () => void) => {\n if (isBatching) {\n fn();\n return;\n }\n isBatching = true;\n try {\n fn();\n } finally {\n isBatching = false;\n store.notify();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef, aspectRatio]);\n\n useIsomorphicLayoutEffect(() => {\n const updates: Partial<StoreState> = {};\n let hasUpdates = false;\n let shouldRecompute = false;\n\n if (cropProp !== undefined) {\n const currentState = store.getState();\n if (!Object.is(currentState.crop, cropProp)) {\n updates.crop = cropProp;\n hasUpdates = true;\n }\n }\n\n if (zoomProp !== undefined) {\n const currentState = store.getState();\n if (currentState.zoom !== zoomProp) {\n updates.zoom = zoomProp;\n hasUpdates = true;\n shouldRecompute = true;\n }\n }\n\n if (rotationProp !== undefined) {\n const currentState = store.getState();\n if (currentState.rotation !== rotationProp) {\n updates.rotation = rotationProp;\n hasUpdates = true;\n shouldRecompute = true;\n }\n }\n\n if (hasUpdates) {\n store.batch(() => {\n Object.entries(updates).forEach(([key, value]) => {\n store.setState(key as keyof StoreState, value);\n });\n });\n\n if (shouldRecompute && rootRef.current) {\n requestAnimationFrame(() => {\n const currentState = store.getState();\n if (currentState.cropSize && currentState.mediaSize) {\n const newPosition = !allowOverflow\n ? onPositionClamp(\n currentState.crop,\n currentState.mediaSize,\n currentState.cropSize,\n currentState.zoom,\n currentState.rotation\n )\n : currentState.crop;\n\n if (\n Math.abs(newPosition.x - currentState.crop.x) > 0.001 ||\n Math.abs(newPosition.y - currentState.crop.y) > 0.001\n ) {\n store.setState(\"crop\", newPosition);\n }\n }\n });\n }\n }\n }, [cropProp, zoomProp, rotationProp, store, allowOverflow]);\n\n const labels = useComitorLabels(\"cropper\", labelsProp);\n\n const contextValue = React.useMemo<CropperContextValue>(\n () => ({\n minZoom,\n maxZoom,\n zoomSpeed,\n keyboardStep,\n aspectRatio,\n shape,\n objectFit,\n preventScrollZoom,\n allowOverflow,\n withGrid,\n rootRef,\n labels\n }),\n [\n minZoom,\n maxZoom,\n zoomSpeed,\n keyboardStep,\n aspectRatio,\n shape,\n objectFit,\n preventScrollZoom,\n allowOverflow,\n withGrid,\n labels\n ]\n );\n\n return (\n <StoreContext.Provider value={store}>\n <CropperContext.Provider value={contextValue}>\n <div data-slot=\"cropper-wrapper\" className={cn(\"relative size-full overflow-hidden\", className)}>\n <CropperImpl {...rootProps} />\n </div>\n </CropperContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface CropperImplProps extends CropperProps {\n onWheelZoom?: (event: WheelEvent) => void;\n}\n\nfunction CropperImpl(props: CropperImplProps) {\n const {\n onWheelZoom: onWheelZoomProp,\n onKeyUp: onKeyUpProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onTouchStart: onTouchStartProp,\n \"aria-describedby\": ariaDescribedByProp,\n asChild,\n className,\n ref,\n ...rootImplProps\n } = props;\n\n const context = useCropperContext(ROOT_IMPL_NAME);\n const store = useStoreContext(ROOT_IMPL_NAME);\n const crop = useStore((state) => state.crop);\n const zoom = useStore((state) => state.zoom);\n const rotation = useStore((state) => state.rotation);\n const mediaSize = useStore((state) => state.mediaSize);\n const cropSize = useStore((state) => state.cropSize);\n\n const descriptionId = React.useId();\n // Câu đọc qua vùng `aria-live` — chỉ đổi khi phóng/thu BẰNG PHÍM (con lăn/chụm là thao tác nhìn).\n const [zoomStatus, setZoomStatus] = React.useState(\"\");\n\n const propsRef = useAsRef({\n onWheelZoom: onWheelZoomProp,\n onKeyUp: onKeyUpProp,\n onKeyDown: onKeyDownProp,\n onMouseDown: onMouseDownProp,\n onTouchStart: onTouchStartProp\n });\n\n const composedRef = useComposedRefs(ref, context.rootRef);\n const dragStartPositionRef = React.useRef<Point>({ x: 0, y: 0 });\n const dragStartCropRef = React.useRef<Point>({ x: 0, y: 0 });\n const contentPositionRef = React.useRef<Point>({ x: 0, y: 0 });\n const lastPinchDistanceRef = React.useRef(0);\n const lastPinchRotationRef = React.useRef(0);\n const rafDragTimeoutRef = React.useRef<number | null>(null);\n const rafPinchTimeoutRef = React.useRef<number | null>(null);\n const wheelTimerRef = React.useRef<number | null>(null);\n const isTouchingRef = React.useRef(false);\n const gestureZoomStartRef = React.useRef(0);\n const gestureRotationStartRef = React.useRef(0);\n\n const onRefsCleanup = React.useCallback(() => {\n if (rafDragTimeoutRef.current) {\n cancelAnimationFrame(rafDragTimeoutRef.current);\n rafDragTimeoutRef.current = null;\n }\n if (rafPinchTimeoutRef.current) {\n cancelAnimationFrame(rafPinchTimeoutRef.current);\n rafPinchTimeoutRef.current = null;\n }\n if (wheelTimerRef.current) {\n clearTimeout(wheelTimerRef.current);\n wheelTimerRef.current = null;\n }\n isTouchingRef.current = false;\n }, []);\n\n const onCacheCleanup = React.useCallback(() => {\n if (onPositionClampCache.size > MAX_CACHE_SIZE * 1.5) {\n onPositionClampCache.clear();\n }\n if (croppedAreaCache.size > MAX_CACHE_SIZE * 1.5) {\n croppedAreaCache.clear();\n }\n }, []);\n\n const getMousePoint = React.useCallback(\n (event: MouseEvent | React.MouseEvent) => ({\n x: Number(event.clientX),\n y: Number(event.clientY)\n }),\n []\n );\n\n const getTouchPoint = React.useCallback(\n (touch: Touch | React.Touch) => ({\n x: Number(touch.clientX),\n y: Number(touch.clientY)\n }),\n []\n );\n\n const onContentPositionChange = React.useCallback(() => {\n if (context.rootRef?.current) {\n const bounds = context.rootRef.current.getBoundingClientRect();\n contentPositionRef.current = { x: bounds.left, y: bounds.top };\n }\n }, [context.rootRef]);\n\n const getPointOnContent = React.useCallback(\n ({ x, y }: Point, contentTopLeft: Point): Point => {\n if (!context.rootRef?.current) {\n return { x: 0, y: 0 };\n }\n const contentRect = context.rootRef.current.getBoundingClientRect();\n return {\n x: contentRect.width / 2 - (x - contentTopLeft.x),\n y: contentRect.height / 2 - (y - contentTopLeft.y)\n };\n },\n [context.rootRef]\n );\n\n const getPointOnMedia = React.useCallback(\n ({ x, y }: Point) => {\n return {\n x: (x + crop.x) / zoom,\n y: (y + crop.y) / zoom\n };\n },\n [crop, zoom]\n );\n\n const recomputeCropPosition = React.useCallback(() => {\n if (!cropSize || !mediaSize) return;\n\n const newPosition = !context.allowOverflow ? onPositionClamp(crop, mediaSize, cropSize, zoom, rotation) : crop;\n\n if (Math.abs(newPosition.x - crop.x) > 0.001 || Math.abs(newPosition.y - crop.y) > 0.001) {\n store.setState(\"crop\", newPosition);\n }\n }, [cropSize, mediaSize, context.allowOverflow, crop, zoom, rotation, store]);\n\n const onZoomChange = React.useCallback(\n (newZoom: number, point: Point, shouldUpdatePosition = true) => {\n if (!cropSize || !mediaSize) return;\n\n const clampedZoom = clamp(newZoom, context.minZoom, context.maxZoom);\n\n store.batch(() => {\n if (shouldUpdatePosition) {\n const zoomPoint = getPointOnContent(point, contentPositionRef.current);\n const zoomTarget = getPointOnMedia(zoomPoint);\n const requestedPosition = {\n x: zoomTarget.x * clampedZoom - zoomPoint.x,\n y: zoomTarget.y * clampedZoom - zoomPoint.y\n };\n\n const newPosition = !context.allowOverflow\n ? onPositionClamp(requestedPosition, mediaSize, cropSize, clampedZoom, rotation)\n : requestedPosition;\n\n store.setState(\"crop\", newPosition);\n }\n store.setState(\"zoom\", clampedZoom);\n });\n\n requestAnimationFrame(() => {\n recomputeCropPosition();\n });\n },\n [\n cropSize,\n mediaSize,\n context.minZoom,\n context.maxZoom,\n context.allowOverflow,\n getPointOnContent,\n getPointOnMedia,\n rotation,\n store,\n recomputeCropPosition\n ]\n );\n\n const onDragStart = React.useCallback(\n ({ x, y }: Point) => {\n dragStartPositionRef.current = { x, y };\n dragStartCropRef.current = { ...crop };\n store.setState(\"isDragging\", true);\n },\n [crop, store]\n );\n\n const onDrag = React.useCallback(\n ({ x, y }: Point) => {\n if (rafDragTimeoutRef.current) {\n cancelAnimationFrame(rafDragTimeoutRef.current);\n }\n\n rafDragTimeoutRef.current = requestAnimationFrame(() => {\n if (!cropSize || !mediaSize) return;\n if (x === undefined || y === undefined) return;\n\n const offsetX = x - dragStartPositionRef.current.x;\n const offsetY = y - dragStartPositionRef.current.y;\n\n if (Math.abs(offsetX) < 2 && Math.abs(offsetY) < 2) {\n return;\n }\n\n const requestedPosition = {\n x: dragStartCropRef.current.x + offsetX,\n y: dragStartCropRef.current.y + offsetY\n };\n\n const newPosition = !context.allowOverflow\n ? onPositionClamp(requestedPosition, mediaSize, cropSize, zoom, rotation)\n : requestedPosition;\n\n const currentCrop = store.getState().crop;\n if (Math.abs(newPosition.x - currentCrop.x) > 1 || Math.abs(newPosition.y - currentCrop.y) > 1) {\n store.setState(\"crop\", newPosition);\n }\n });\n },\n [cropSize, mediaSize, context.allowOverflow, zoom, rotation, store]\n );\n\n const onMouseMove = React.useCallback((event: MouseEvent) => onDrag(getMousePoint(event)), [getMousePoint, onDrag]);\n\n const onTouchMove = React.useCallback(\n (event: TouchEvent) => {\n event.preventDefault();\n if (event.touches.length === 2) {\n const [firstTouch, secondTouch] = event.touches ?? [];\n if (firstTouch && secondTouch) {\n const pointA = getTouchPoint(firstTouch);\n const pointB = getTouchPoint(secondTouch);\n const center = getCenter(pointA, pointB);\n onDrag(center);\n\n if (rafPinchTimeoutRef.current) {\n cancelAnimationFrame(rafPinchTimeoutRef.current);\n }\n\n rafPinchTimeoutRef.current = requestAnimationFrame(() => {\n const distance = getDistanceBetweenPoints(pointA, pointB);\n const distanceRatio = distance / lastPinchDistanceRef.current;\n\n if (Math.abs(distanceRatio - 1) > 0.01) {\n const newZoom = zoom * distanceRatio;\n onZoomChange(newZoom, center, false);\n lastPinchDistanceRef.current = distance;\n }\n\n const rotationAngle = getRotationBetweenPoints(pointA, pointB);\n const rotationDiff = rotationAngle - lastPinchRotationRef.current;\n\n if (Math.abs(rotationDiff) > 0.5) {\n const newRotation = rotation + rotationDiff;\n store.setState(\"rotation\", newRotation);\n lastPinchRotationRef.current = rotationAngle;\n }\n });\n }\n } else if (event.touches.length === 1) {\n const firstTouch = event.touches[0];\n if (firstTouch) {\n onDrag(getTouchPoint(firstTouch));\n }\n }\n },\n [getTouchPoint, onDrag, zoom, onZoomChange, rotation, store]\n );\n\n const onGestureChange = React.useCallback(\n (event: GestureEvent) => {\n event.preventDefault();\n if (isTouchingRef.current) {\n return;\n }\n\n const point = { x: Number(event.clientX), y: Number(event.clientY) };\n const newZoom = gestureZoomStartRef.current - 1 + event.scale;\n onZoomChange(newZoom, point, true);\n\n const newRotation = gestureRotationStartRef.current + event.rotation;\n store.setState(\"rotation\", newRotation);\n },\n [onZoomChange, store]\n );\n\n const onGestureEnd = React.useCallback(() => {\n document.removeEventListener(\"gesturechange\", onGestureChange as EventListener);\n document.removeEventListener(\"gestureend\", onGestureEnd as EventListener);\n }, [onGestureChange]);\n\n const onGestureStart = React.useCallback(\n (event: GestureEvent) => {\n event.preventDefault();\n // ⚠ Khác thượng nguồn: cập nhật toạ độ khung trước khi phóng — xem chú thích ở `onWheelZoom`.\n onContentPositionChange();\n document.addEventListener(\"gesturechange\", onGestureChange as EventListener);\n document.addEventListener(\"gestureend\", onGestureEnd as EventListener);\n gestureZoomStartRef.current = zoom;\n gestureRotationStartRef.current = rotation;\n },\n [zoom, rotation, onGestureChange, onGestureEnd, onContentPositionChange]\n );\n\n const onSafariZoomPrevent = React.useCallback((event: Event) => event.preventDefault(), []);\n\n const onEventsCleanup = React.useCallback(() => {\n document.removeEventListener(\"mousemove\", onMouseMove);\n document.removeEventListener(\"touchmove\", onTouchMove);\n document.removeEventListener(\"gesturechange\", onGestureChange as EventListener);\n document.removeEventListener(\"gestureend\", onGestureEnd as EventListener);\n }, [onMouseMove, onTouchMove, onGestureChange, onGestureEnd]);\n\n const onDragStopped = React.useCallback(() => {\n isTouchingRef.current = false;\n store.setState(\"isDragging\", false);\n onRefsCleanup();\n document.removeEventListener(\"mouseup\", onDragStopped);\n document.removeEventListener(\"touchend\", onDragStopped);\n onEventsCleanup();\n }, [store, onEventsCleanup, onRefsCleanup]);\n\n const getWheelDelta = React.useCallback((event: WheelEvent) => {\n let deltaX = event.deltaX;\n let deltaY = event.deltaY;\n let deltaZ = event.deltaZ;\n\n if (event.deltaMode === 1) {\n deltaX *= 16;\n deltaY *= 16;\n deltaZ *= 16;\n } else if (event.deltaMode === 2) {\n deltaX *= 400;\n deltaY *= 400;\n deltaZ *= 400;\n }\n\n return { deltaX, deltaY, deltaZ };\n }, []);\n\n const onWheelZoom = React.useCallback(\n (event: WheelEvent) => {\n propsRef.current.onWheelZoom?.(event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n /*\n * ⚠ Khác thượng nguồn: bản gốc chỉ cập nhật `contentPositionRef` ở `mousedown`/`touchstart`,\n * nên lăn chuột khi CHƯA kéo lần nào (hoặc sau khi trang đã cuộn) tính điểm neo bằng toạ độ\n * khung cũ — mặc định (0, 0) — và ảnh phóng lệch khỏi con trỏ đúng bằng khoảng cách từ mép\n * trang tới khung cắt.\n */\n onContentPositionChange();\n const point = getMousePoint(event);\n const { deltaY } = getWheelDelta(event);\n const newZoom = zoom - (deltaY * context.zoomSpeed) / 200;\n onZoomChange(newZoom, point, true);\n\n store.batch(() => {\n const currentState = store.getState();\n if (!currentState.isWheelZooming) {\n store.setState(\"isWheelZooming\", true);\n }\n if (!currentState.isDragging) {\n store.setState(\"isDragging\", true);\n }\n });\n\n if (wheelTimerRef.current) {\n clearTimeout(wheelTimerRef.current);\n }\n wheelTimerRef.current = window.setTimeout(() => {\n store.batch(() => {\n store.setState(\"isWheelZooming\", false);\n store.setState(\"isDragging\", false);\n });\n }, 250);\n },\n [propsRef, getMousePoint, zoom, context.zoomSpeed, onZoomChange, getWheelDelta, store, onContentPositionChange]\n );\n\n const onKeyUp = React.useCallback(\n (event: React.KeyboardEvent<RootElement>) => {\n propsRef.current.onKeyUp?.(event);\n if (event.defaultPrevented) return;\n\n const arrowKeys = new Set([\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\"]);\n\n // Phím thu phóng cũng khép một lượt tương tác, để `onCropComplete` bắn như khi thả phím mũi tên.\n if (arrowKeys.has(event.key) || ZOOM_IN_KEYS.has(event.key) || ZOOM_OUT_KEYS.has(event.key)) {\n event.preventDefault();\n store.setState(\"isDragging\", false);\n }\n },\n [propsRef, store]\n );\n\n const onKeyDown = React.useCallback(\n (event: React.KeyboardEvent<RootElement>) => {\n propsRef.current.onKeyDown?.(event);\n if (event.defaultPrevented || !cropSize || !mediaSize) return;\n\n /*\n * ⚠ Khác thượng nguồn: thêm + / - để thu phóng quanh TÂM khung. Bản gốc chỉ phóng được bằng\n * con lăn chuột và cử chỉ chụm ngón — người chỉ dùng bàn phím không có đường nào đổi `zoom`\n * nếu app không tự dựng thêm Slider (WCAG 2.1.1). Ctrl/Cmd/Alt + phím là zoom TRÌNH DUYỆT,\n * nên để nguyên cho trình duyệt.\n */\n const zoomDirection = ZOOM_IN_KEYS.has(event.key) ? 1 : ZOOM_OUT_KEYS.has(event.key) ? -1 : 0;\n if (zoomDirection !== 0) {\n if (event.metaKey || event.ctrlKey || event.altKey) return;\n const root = context.rootRef.current;\n if (!root) return;\n\n event.preventDefault();\n\n if (!event.repeat) {\n store.setState(\"isDragging\", true);\n }\n\n const nextZoom = clamp(zoom + zoomDirection * KEYBOARD_ZOOM_STEP, context.minZoom, context.maxZoom);\n onContentPositionChange();\n const rect = root.getBoundingClientRect();\n onZoomChange(nextZoom, { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 }, true);\n setZoomStatus(context.labels.zoomStatus(nextZoom));\n return;\n }\n\n let step = context.keyboardStep;\n if (event.shiftKey) {\n step *= 0.2;\n }\n\n const keyCallbacks: Record<string, () => Point> = {\n ArrowUp: () => ({ ...crop, y: crop.y - step }),\n ArrowDown: () => ({ ...crop, y: crop.y + step }),\n ArrowLeft: () => ({ ...crop, x: crop.x - step }),\n ArrowRight: () => ({ ...crop, x: crop.x + step })\n } as const;\n\n const callback = keyCallbacks[event.key];\n if (!callback) return;\n\n event.preventDefault();\n\n let newCrop = callback();\n\n if (!context.allowOverflow) {\n newCrop = onPositionClamp(newCrop, mediaSize, cropSize, zoom, rotation);\n }\n\n if (!event.repeat) {\n store.setState(\"isDragging\", true);\n }\n\n store.setState(\"crop\", newCrop);\n },\n [\n propsRef,\n cropSize,\n mediaSize,\n context.keyboardStep,\n context.allowOverflow,\n context.rootRef,\n context.minZoom,\n context.maxZoom,\n context.labels,\n crop,\n zoom,\n rotation,\n store,\n onContentPositionChange,\n onZoomChange\n ]\n );\n\n const onMouseDown = React.useCallback(\n (event: React.MouseEvent<RootElement>) => {\n propsRef.current.onMouseDown?.(event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n document.addEventListener(\"mousemove\", onMouseMove);\n document.addEventListener(\"mouseup\", onDragStopped);\n onContentPositionChange();\n onDragStart(getMousePoint(event));\n },\n [propsRef, getMousePoint, onDragStart, onDragStopped, onMouseMove, onContentPositionChange]\n );\n\n const onTouchStart = React.useCallback(\n (event: React.TouchEvent<RootElement>) => {\n propsRef.current.onTouchStart?.(event);\n if (event.defaultPrevented) return;\n\n isTouchingRef.current = true;\n document.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n document.addEventListener(\"touchend\", onDragStopped);\n onContentPositionChange();\n\n if (event.touches.length === 2) {\n const [firstTouch, secondTouch] = event.touches ? Array.from(event.touches) : [];\n if (firstTouch && secondTouch) {\n const pointA = getTouchPoint(firstTouch);\n const pointB = getTouchPoint(secondTouch);\n lastPinchDistanceRef.current = getDistanceBetweenPoints(pointA, pointB);\n lastPinchRotationRef.current = getRotationBetweenPoints(pointA, pointB);\n onDragStart(getCenter(pointA, pointB));\n }\n } else if (event.touches.length === 1) {\n const firstTouch = event.touches[0];\n if (firstTouch) {\n onDragStart(getTouchPoint(firstTouch));\n }\n }\n },\n [propsRef, onDragStopped, onTouchMove, onContentPositionChange, getTouchPoint, onDragStart]\n );\n\n React.useEffect(() => {\n const content = context.rootRef?.current;\n if (!content) return;\n\n if (!context.preventScrollZoom) {\n content.addEventListener(\"wheel\", onWheelZoom, { passive: false });\n }\n\n content.addEventListener(\"gesturestart\", onSafariZoomPrevent);\n content.addEventListener(\"gesturestart\", onGestureStart as EventListener);\n\n return () => {\n if (!context.preventScrollZoom) {\n content.removeEventListener(\"wheel\", onWheelZoom);\n }\n content.removeEventListener(\"gesturestart\", onSafariZoomPrevent);\n content.removeEventListener(\"gesturestart\", onGestureStart as EventListener);\n /*\n * ⚠ Khác thượng nguồn: bản gốc gọi `onRefsCleanup()` ở đây. Effect này chạy lại MỖI lần\n * `zoom` đổi (vì `onWheelZoom` phụ thuộc `zoom`), nên nó huỷ đúng cái hẹn giờ 250ms mà lượt\n * lăn chuột vừa đặt để khép tương tác: `isDragging` kẹt ở `true`, và `onCropComplete` /\n * `onInteractionEnd` KHÔNG BAO GIỜ bắn sau khi phóng bằng con lăn (đo trên trình duyệt thật:\n * lăn một nấc, chờ 400ms, `onCropComplete` 0 lần). Dọn khi gỡ component đã có effect ngay dưới.\n */\n };\n }, [context.rootRef, context.preventScrollZoom, onWheelZoom, onSafariZoomPrevent, onGestureStart]);\n\n React.useEffect(() => {\n return () => {\n onRefsCleanup();\n onCacheCleanup();\n };\n }, [onRefsCleanup, onCacheCleanup]);\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n const describedBy = [descriptionId, ariaDescribedByProp].filter(Boolean).join(\" \");\n\n return (\n <>\n <RootPrimitive\n /*\n * ⚠ Khác thượng nguồn: bản gốc là một `<div tabIndex={0}>` KHÔNG role, KHÔNG tên — Tab tới\n * được nhưng trình đọc màn hình không biết đó là gì, cũng không biết phím nào dùng được.\n * `role=\"application\"` (không phải `group`) là CỐ Ý: vùng này sống nhờ phím mũi tên và\n * + / -, mà với `group` thì NVDA/JAWS ở chế độ duyệt nuốt mất phím mũi tên trước khi tới\n * handler; `application` bật chế độ focus. Bên trong không có nội dung đọc được nào bị\n * che đi — chỉ có ảnh đang cắt và khung vẽ. App ghi đè được cả ba qua `labels` hoặc\n * truyền thẳng `aria-label` / `aria-roledescription`.\n */\n role=\"application\"\n aria-roledescription={context.labels.roleDescription}\n aria-label={context.labels.label}\n aria-describedby={describedBy}\n data-slot=\"cropper\"\n tabIndex={0}\n {...rootImplProps}\n ref={composedRef}\n className={cn(\n \"absolute inset-0 flex cursor-move touch-none items-center justify-center overflow-hidden outline-none select-none\",\n /*\n * ⚠ Khác thượng nguồn: bản gốc `outline-none` mà KHÔNG có chỉ báo focus nào (WCAG 2.4.7).\n * Vòng focus vẽ trên `::after` phủ kín khung chứ không trên chính phần tử: ảnh và khung\n * cắt là con `absolute` nên được vẽ ĐÈ lên outline của cha, còn `::after` là con cuối\n * cùng nên nằm trên cùng. Cùng khuôn `outline-ring` với `Button`, thụt vào trong vì hai\n * lớp bọc ngoài đều `overflow-hidden`.\n */\n \"after:pointer-events-none after:absolute after:inset-0 focus-visible:after:-outline-offset-2 focus-visible:after:outline-2 focus-visible:after:outline-ring\",\n className\n )}\n onKeyUp={onKeyUp}\n onKeyDown={onKeyDown}\n onMouseDown={onMouseDown}\n onTouchStart={onTouchStart}\n />\n {/* `hidden` vẫn làm nguồn được cho `aria-describedby`, và không bị đọc lặp ở chế độ duyệt. */}\n <span id={descriptionId} hidden>\n {context.labels.instructions}\n </span>\n <span aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {zoomStatus}\n </span>\n </>\n );\n}\n\nconst cropperMediaVariants = cva(\"will-change-transform\", {\n variants: {\n objectFit: {\n contain: \"absolute inset-0 m-auto max-h-full max-w-full\",\n cover: \"h-auto w-full\",\n \"horizontal-cover\": \"h-auto w-full\",\n \"vertical-cover\": \"h-full w-auto\"\n }\n },\n defaultVariants: {\n objectFit: \"contain\"\n }\n});\n\ninterface UseMediaComputationProps<T extends HTMLImageElement | HTMLVideoElement> {\n mediaRef: React.RefObject<T | null>;\n context: CropperContextValue;\n store: Store;\n rotation: number;\n getNaturalDimensions: (media: T) => Size;\n}\n\nfunction useMediaComputation<T extends HTMLImageElement | HTMLVideoElement>({\n mediaRef,\n context,\n store,\n rotation,\n getNaturalDimensions\n}: UseMediaComputationProps<T>) {\n const computeSizes = React.useCallback(() => {\n const media = mediaRef.current;\n const content = context.rootRef?.current;\n if (!media || !content) return;\n\n const contentRect = content.getBoundingClientRect();\n const containerAspect = contentRect.width / contentRect.height;\n const { width: naturalWidth, height: naturalHeight } = getNaturalDimensions(media);\n const isScaledDown = media.offsetWidth < naturalWidth || media.offsetHeight < naturalHeight;\n const mediaAspect = naturalWidth / naturalHeight;\n\n let renderedMediaSize: Size;\n\n if (isScaledDown) {\n const objectFitCallbacks = {\n contain: () =>\n containerAspect > mediaAspect\n ? {\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }\n : {\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n },\n \"horizontal-cover\": () => ({\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n }),\n \"vertical-cover\": () => ({\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }),\n cover: () =>\n containerAspect < mediaAspect\n ? {\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n }\n : {\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }\n } as const;\n\n const callback = objectFitCallbacks[context.objectFit];\n renderedMediaSize = callback\n ? callback()\n : containerAspect > mediaAspect\n ? {\n width: contentRect.height * mediaAspect,\n height: contentRect.height\n }\n : {\n width: contentRect.width,\n height: contentRect.width / mediaAspect\n };\n } else {\n renderedMediaSize = {\n width: media.offsetWidth,\n height: media.offsetHeight\n };\n }\n\n const mediaSize: MediaSize = {\n ...renderedMediaSize,\n naturalWidth,\n naturalHeight\n };\n\n store.setState(\"mediaSize\", mediaSize);\n\n const cropSize = getCropSize(\n mediaSize.width,\n mediaSize.height,\n contentRect.width,\n contentRect.height,\n context.aspectRatio,\n rotation\n );\n\n store.setState(\"cropSize\", cropSize);\n\n requestAnimationFrame(() => {\n const currentState = store.getState();\n if (currentState.cropSize && currentState.mediaSize) {\n const newPosition = onPositionClamp(\n currentState.crop,\n currentState.mediaSize,\n currentState.cropSize,\n currentState.zoom,\n currentState.rotation\n );\n\n if (\n Math.abs(newPosition.x - currentState.crop.x) > 0.001 ||\n Math.abs(newPosition.y - currentState.crop.y) > 0.001\n ) {\n store.setState(\"crop\", newPosition);\n }\n }\n });\n\n return { mediaSize, cropSize };\n }, [mediaRef, context.aspectRatio, context.rootRef, context.objectFit, store, rotation, getNaturalDimensions]);\n\n return { computeSizes };\n}\n\ninterface CropperImageProps extends React.ComponentProps<\"img\">, VariantProps<typeof cropperMediaVariants> {\n asChild?: boolean;\n snapPixels?: boolean;\n}\n\n/** Ảnh cần cắt. Nhớ truyền `alt` — ảnh ở đây mang nội dung, không phải trang trí. */\nfunction CropperImage(props: CropperImageProps) {\n const { className, style, asChild, ref, onLoad, objectFit, snapPixels = false, ...imageProps } = props;\n\n const context = useCropperContext(IMAGE_NAME);\n const store = useStoreContext(IMAGE_NAME);\n const crop = useStore((state) => state.crop);\n const zoom = useStore((state) => state.zoom);\n const rotation = useStore((state) => state.rotation);\n const dpr = useDevicePixelRatio();\n\n const imageRef = React.useRef<HTMLImageElement>(null);\n const composedRef = useComposedRefs(ref, imageRef);\n\n const getNaturalDimensions = React.useCallback(\n (image: HTMLImageElement) => ({\n width: image.naturalWidth,\n height: image.naturalHeight\n }),\n []\n );\n\n const { computeSizes } = useMediaComputation({\n mediaRef: imageRef,\n context,\n store,\n rotation,\n getNaturalDimensions\n });\n\n const onMediaLoad = React.useCallback(() => {\n const image = imageRef.current;\n if (!image) return;\n\n computeSizes();\n\n onLoad?.(new Event(\"load\") as unknown as React.SyntheticEvent<HTMLImageElement>);\n }, [computeSizes, onLoad]);\n\n React.useEffect(() => {\n const image = imageRef.current;\n if (image?.complete && image.naturalWidth > 0) {\n onMediaLoad();\n }\n }, [onMediaLoad]);\n\n React.useEffect(() => {\n const content = context.rootRef?.current;\n if (!content) return;\n\n if (typeof ResizeObserver !== \"undefined\") {\n let isFirstResize = true;\n const resizeObserver = new ResizeObserver(() => {\n if (isFirstResize) {\n isFirstResize = false;\n return;\n }\n\n const callback = () => {\n const image = imageRef.current;\n if (image?.complete && image.naturalWidth > 0) {\n computeSizes();\n }\n };\n\n if (\"requestIdleCallback\" in window) {\n requestIdleCallback(callback);\n } else {\n setTimeout(callback, 16);\n }\n });\n\n resizeObserver.observe(content);\n\n return () => {\n resizeObserver.disconnect();\n };\n } else {\n const onWindowResize = () => {\n const image = imageRef.current;\n if (image?.complete && image.naturalWidth > 0) {\n computeSizes();\n }\n };\n\n window.addEventListener(\"resize\", onWindowResize);\n return () => {\n window.removeEventListener(\"resize\", onWindowResize);\n };\n }\n }, [context.rootRef, computeSizes]);\n\n const ImagePrimitive = asChild ? Slot : \"img\";\n\n return (\n <ImagePrimitive\n data-slot=\"cropper-image\"\n {...imageProps}\n ref={composedRef}\n className={cn(\n cropperMediaVariants({\n objectFit: objectFit ?? context.objectFit,\n className\n })\n )}\n style={{\n transform: snapPixels\n ? `translate(${snapToDevicePixel(crop.x, dpr)}px, ${snapToDevicePixel(crop.y, dpr)}px) rotate(${rotation}deg) scale(${zoom})`\n : `translate(${crop.x}px, ${crop.y}px) rotate(${rotation}deg) scale(${zoom})`,\n ...style\n }}\n onLoad={onMediaLoad}\n />\n );\n}\n\ninterface CropperVideoProps extends React.ComponentProps<\"video\">, VariantProps<typeof cropperMediaVariants> {\n asChild?: boolean;\n snapPixels?: boolean;\n}\n\nfunction CropperVideo(props: CropperVideoProps) {\n const { className, style, asChild, ref, onLoadedMetadata, objectFit, snapPixels = false, ...videoProps } = props;\n\n const context = useCropperContext(VIDEO_NAME);\n const store = useStoreContext(VIDEO_NAME);\n const crop = useStore((state) => state.crop);\n const zoom = useStore((state) => state.zoom);\n const rotation = useStore((state) => state.rotation);\n const dpr = useDevicePixelRatio();\n\n const videoRef = React.useRef<HTMLVideoElement>(null);\n const composedRef = useComposedRefs(ref, videoRef);\n\n const getNaturalDimensions = React.useCallback(\n (video: HTMLVideoElement) => ({\n width: video.videoWidth,\n height: video.videoHeight\n }),\n []\n );\n\n const { computeSizes } = useMediaComputation({\n mediaRef: videoRef,\n context,\n store,\n rotation,\n getNaturalDimensions\n });\n\n const onMediaLoad = React.useCallback(() => {\n const video = videoRef.current;\n if (!video) return;\n\n computeSizes();\n\n onLoadedMetadata?.(new Event(\"loadedmetadata\") as unknown as React.SyntheticEvent<HTMLVideoElement>);\n }, [computeSizes, onLoadedMetadata]);\n\n React.useEffect(() => {\n const content = context.rootRef?.current;\n if (!content) return;\n\n if (typeof ResizeObserver !== \"undefined\") {\n let isFirstResize = true;\n const resizeObserver = new ResizeObserver(() => {\n if (isFirstResize) {\n isFirstResize = false;\n return;\n }\n\n const callback = () => {\n const video = videoRef.current;\n if (video && video.videoWidth > 0 && video.videoHeight > 0) {\n computeSizes();\n }\n };\n\n if (\"requestIdleCallback\" in window) {\n requestIdleCallback(callback);\n } else {\n setTimeout(callback, 16);\n }\n });\n\n resizeObserver.observe(content);\n\n return () => {\n resizeObserver.disconnect();\n };\n } else {\n const onWindowResize = () => {\n const video = videoRef.current;\n if (video && video.videoWidth > 0 && video.videoHeight > 0) {\n computeSizes();\n }\n };\n\n window.addEventListener(\"resize\", onWindowResize);\n return () => {\n window.removeEventListener(\"resize\", onWindowResize);\n };\n }\n }, [context.rootRef, computeSizes]);\n\n const VideoPrimitive = asChild ? Slot : \"video\";\n\n return (\n <VideoPrimitive\n data-slot=\"cropper-video\"\n autoPlay\n playsInline\n loop\n muted\n controls={false}\n {...videoProps}\n ref={composedRef}\n className={cn(\n cropperMediaVariants({\n objectFit: objectFit ?? context.objectFit,\n className\n })\n )}\n style={{\n transform: snapPixels\n ? `translate(${snapToDevicePixel(crop.x, dpr)}px, ${snapToDevicePixel(crop.y, dpr)}px) rotate(${rotation}deg) scale(${zoom})`\n : `translate(${crop.x}px, ${crop.y}px) rotate(${rotation}deg) scale(${zoom})`,\n ...style\n }}\n onLoadedMetadata={onMediaLoad}\n />\n );\n}\n\n/*\n * ⚠ Khác thượng nguồn — màu. Khung cắt nằm trên ẢNH, không trên nền trang, nên cặp màu ở đây\n * không đổi theo theme (ảnh là ảnh ở cả sáng lẫn tối):\n * · vùng ngoài khung tối đi bằng MÀU LỚP PHỦ của `DialogOverlay` (`ink/60`, `ink/80` ở tối),\n * vẽ bằng bóng 9999em như bản gốc — bản gốc viết thẳng `rgba(0,0,0,0.5)`. Đây là một tấm\n * phủ, KHÔNG phải bóng đổ độ cao, nên không đi qua thang `shadow-card`/`shadow-overlay`;\n * màu vẫn là token nên đổi theo `--ink` của app.\n * · khung là `paper` (bản gốc `white/90`): màu đi cặp với lớp phủ mực, sáng ở MỌI theme và mọi\n * bảng màu. Ca tệ nhất — điểm ảnh TRẮNG nằm dưới lớp phủ: 4,65:1 (ink/60) · 9,60:1 (ink/80),\n * ≥ 3:1 cho thành phần phi văn bản. `--background`/`--foreground` KHÔNG dùng được: chúng đảo\n * theo theme trong khi lớp phủ thì luôn tối.\n * · lưới 1/3 (`paper/50`) là đường gióng bố cục thuần trang trí, nằm trên phần ảnh KHÔNG phủ.\n */\nconst cropperAreaVariants = cva(\n \"absolute top-1/2 left-1/2 box-border -translate-x-1/2 -translate-y-1/2 overflow-hidden border border-[2.5px] border-paper shadow-[0_0_0_9999em] shadow-ink/60 dark:shadow-ink/80\",\n {\n variants: {\n shape: {\n rectangle: \"\",\n circle: \"rounded-full\"\n },\n withGrid: {\n true: \"before:absolute before:top-0 before:right-1/3 before:bottom-0 before:left-1/3 before:box-border before:border before:border-t-0 before:border-b-0 before:border-paper/50 before:content-[''] after:absolute after:top-1/3 after:right-0 after:bottom-1/3 after:left-0 after:box-border after:border after:border-r-0 after:border-l-0 after:border-paper/50 after:content-['']\",\n false: \"\"\n }\n },\n defaultVariants: {\n shape: \"rectangle\",\n withGrid: false\n }\n }\n);\n\ninterface CropperAreaProps extends DivProps, VariantProps<typeof cropperAreaVariants> {\n snapPixels?: boolean;\n}\n\nfunction CropperArea(props: CropperAreaProps) {\n const { className, style, asChild, ref, snapPixels = false, shape, withGrid, ...areaProps } = props;\n\n const context = useCropperContext(AREA_NAME);\n const cropSize = useStore((state) => state.cropSize);\n\n if (!cropSize) return null;\n\n const AreaPrimitive = asChild ? Slot : \"div\";\n\n return (\n <AreaPrimitive\n data-slot=\"cropper-area\"\n {...areaProps}\n ref={ref}\n className={cn(\n cropperAreaVariants({\n shape: shape ?? context.shape,\n withGrid: withGrid ?? context.withGrid,\n className\n })\n )}\n style={{\n width: snapPixels ? Math.round(cropSize.width) : cropSize.width,\n height: snapPixels ? Math.round(cropSize.height) : cropSize.height,\n ...style\n }}\n />\n );\n}\n\nexport {\n type Area as CropperAreaData,\n Cropper,\n CropperArea,\n type CropperAreaProps,\n CropperImage,\n type CropperImageProps,\n type CropperProps,\n CropperVideo,\n type CropperVideoProps,\n type MediaSize as CropperMediaSize,\n type ObjectFit as CropperObjectFit,\n type Point as CropperPoint,\n type Shape as CropperShape,\n type Size as CropperSize,\n useStore as useCropper\n};\n"],"mappings":"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","names":[]}
|
|
@@ -30,10 +30,10 @@ type DialogContentProps = React.ComponentProps<typeof DialogPrimitive.Content> &
|
|
|
30
30
|
showCloseButton?: boolean;
|
|
31
31
|
/** Cỡ hộp thoại theo breakpoint sm trở lên. Mặc định "md". */
|
|
32
32
|
size?: DialogSize;
|
|
33
|
-
/** Nhãn cho trình đọc màn hình của nút đóng. Mặc định
|
|
33
|
+
/** Nhãn cho trình đọc màn hình của nút đóng. Mặc định: khoá `closeLabel` của namespace `dialog`. */
|
|
34
34
|
closeLabel?: string;
|
|
35
35
|
};
|
|
36
|
-
declare function DialogContent({ className, children, showCloseButton, size, closeLabel, ...props }: DialogContentProps): React.JSX.Element;
|
|
36
|
+
declare function DialogContent({ className, children, showCloseButton, size, closeLabel: closeLabelProp, ...props }: DialogContentProps): React.JSX.Element;
|
|
37
37
|
type DialogBodyProps = React.ComponentProps<"div">;
|
|
38
38
|
/**
|
|
39
39
|
* Vùng nội dung CUỘN của hộp thoại, giữa header và footer.
|