@ahrowe/ui 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/common/accordion/accordion.mjs +2 -0
- package/dist/esm/common/accordion/accordion.mjs.map +1 -0
- package/dist/esm/common/accordion/accordion.module.mjs +2 -0
- package/dist/esm/common/accordion/accordion.module.mjs.map +1 -0
- package/dist/esm/common/accordion/accordion.plain.module.mjs +2 -0
- package/dist/esm/common/accordion/accordion.plain.module.mjs.map +1 -0
- package/dist/esm/common/accordion/accordion.primary.module.mjs +2 -0
- package/dist/esm/common/accordion/accordion.primary.module.mjs.map +1 -0
- package/dist/esm/common/accordion/accordion.types.mjs +2 -0
- package/dist/esm/common/accordion/accordion.types.mjs.map +1 -0
- package/dist/esm/common/actionButtons/actionButtons.mjs +2 -0
- package/dist/esm/common/actionButtons/actionButtons.mjs.map +1 -0
- package/dist/esm/common/actionButtons/actionButtons.module.mjs +2 -0
- package/dist/esm/common/actionButtons/actionButtons.module.mjs.map +1 -0
- package/dist/esm/common/actionIcon/actionIcon.mjs +2 -0
- package/dist/esm/common/actionIcon/actionIcon.mjs.map +1 -0
- package/dist/esm/common/actionIcon/actionIcon.module.mjs +2 -0
- package/dist/esm/common/actionIcon/actionIcon.module.mjs.map +1 -0
- package/dist/esm/common/avatar/avatar.mjs +2 -0
- package/dist/esm/common/avatar/avatar.mjs.map +1 -0
- package/dist/esm/common/avatar/avatar.module.mjs +2 -0
- package/dist/esm/common/avatar/avatar.module.mjs.map +1 -0
- package/dist/esm/common/avatar/avatarGroup.mjs +2 -0
- package/dist/esm/common/avatar/avatarGroup.mjs.map +1 -0
- package/dist/esm/common/badge/badge.mjs +2 -0
- package/dist/esm/common/badge/badge.mjs.map +1 -0
- package/dist/esm/common/badge/badge.module.mjs +2 -0
- package/dist/esm/common/badge/badge.module.mjs.map +1 -0
- package/dist/esm/common/badge/badge.types.mjs +2 -0
- package/dist/esm/common/badge/badge.types.mjs.map +1 -0
- package/dist/esm/common/bodyEnd/bodyEnd.mjs +2 -0
- package/dist/esm/common/bodyEnd/bodyEnd.mjs.map +1 -0
- package/dist/esm/common/button/button.mjs +2 -0
- package/dist/esm/common/button/button.mjs.map +1 -0
- package/dist/esm/common/button/button.module.mjs +2 -0
- package/dist/esm/common/button/button.module.mjs.map +1 -0
- package/dist/esm/common/button/button.types.mjs +2 -0
- package/dist/esm/common/button/button.types.mjs.map +1 -0
- package/dist/esm/common/card/Card.mjs +2 -0
- package/dist/esm/common/card/Card.mjs.map +1 -0
- package/dist/esm/common/card/CardActions.mjs +2 -0
- package/dist/esm/common/card/CardActions.mjs.map +1 -0
- package/dist/esm/common/card/CardContent.mjs +2 -0
- package/dist/esm/common/card/CardContent.mjs.map +1 -0
- package/dist/esm/common/card/CardHeader.mjs +2 -0
- package/dist/esm/common/card/CardHeader.mjs.map +1 -0
- package/dist/esm/common/card/CardMedia.mjs +2 -0
- package/dist/esm/common/card/CardMedia.mjs.map +1 -0
- package/dist/esm/common/card/card.module.mjs +2 -0
- package/dist/esm/common/card/card.module.mjs.map +1 -0
- package/dist/esm/common/card/card.types.mjs +2 -0
- package/dist/esm/common/card/card.types.mjs.map +1 -0
- package/dist/esm/common/checkbox/checkbox.mjs +2 -0
- package/dist/esm/common/checkbox/checkbox.mjs.map +1 -0
- package/dist/esm/common/checkbox/checkbox.module.mjs +2 -0
- package/dist/esm/common/checkbox/checkbox.module.mjs.map +1 -0
- package/dist/esm/common/chip/chip.mjs +2 -0
- package/dist/esm/common/chip/chip.mjs.map +1 -0
- package/dist/esm/common/chip/chip.module.mjs +2 -0
- package/dist/esm/common/chip/chip.module.mjs.map +1 -0
- package/dist/esm/common/chip/chip.types.mjs +2 -0
- package/dist/esm/common/chip/chip.types.mjs.map +1 -0
- package/dist/esm/common/chip/chipContainer.mjs +2 -0
- package/dist/esm/common/chip/chipContainer.mjs.map +1 -0
- package/dist/esm/common/colorPicker/colorPicker.mjs +2 -0
- package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -0
- package/dist/esm/common/colorPicker/colorPicker.module.mjs +2 -0
- package/dist/esm/common/colorPicker/colorPicker.module.mjs.map +1 -0
- package/dist/esm/common/confirmModal/confirmModal.mjs +2 -0
- package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -0
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +2 -0
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -0
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs +2 -0
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs.map +1 -0
- package/dist/esm/common/datePicker/dateFunctions.mjs +2 -0
- package/dist/esm/common/datePicker/dateFunctions.mjs.map +1 -0
- package/dist/esm/common/datePicker/datePicker.mjs +2 -0
- package/dist/esm/common/datePicker/datePicker.mjs.map +1 -0
- package/dist/esm/common/datePicker/datePicker.module.mjs +2 -0
- package/dist/esm/common/datePicker/datePicker.module.mjs.map +1 -0
- package/dist/esm/common/drawer/drawer.mjs +2 -0
- package/dist/esm/common/drawer/drawer.mjs.map +1 -0
- package/dist/esm/common/drawer/drawer.module.mjs +2 -0
- package/dist/esm/common/drawer/drawer.module.mjs.map +1 -0
- package/dist/esm/common/dropZone/dropZone.mjs +2 -0
- package/dist/esm/common/dropZone/dropZone.mjs.map +1 -0
- package/dist/esm/common/dropZone/dropZone.module.mjs +2 -0
- package/dist/esm/common/dropZone/dropZone.module.mjs.map +1 -0
- package/dist/esm/common/dropZone/dropZone.types.mjs +2 -0
- package/dist/esm/common/dropZone/dropZone.types.mjs.map +1 -0
- package/dist/esm/common/dropdown/dropdown.mjs +2 -0
- package/dist/esm/common/dropdown/dropdown.mjs.map +1 -0
- package/dist/esm/common/dropdown/dropdown.module.mjs +2 -0
- package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -0
- package/dist/esm/common/emptyState/emptyState.mjs +2 -0
- package/dist/esm/common/emptyState/emptyState.mjs.map +1 -0
- package/dist/esm/common/emptyState/emptyState.module.mjs +2 -0
- package/dist/esm/common/emptyState/emptyState.module.mjs.map +1 -0
- package/dist/esm/common/fab/components/fabBase/fabBase.mjs +2 -0
- package/dist/esm/common/fab/components/fabBase/fabBase.mjs.map +1 -0
- package/dist/esm/common/fab/components/fabBase/fabBase.module.mjs +2 -0
- package/dist/esm/common/fab/components/fabBase/fabBase.module.mjs.map +1 -0
- package/dist/esm/common/fab/fab.mjs +2 -0
- package/dist/esm/common/fab/fab.mjs.map +1 -0
- package/dist/esm/common/fab/fab.module.mjs +2 -0
- package/dist/esm/common/fab/fab.module.mjs.map +1 -0
- package/dist/esm/common/floatingMenu/floatingMenu.mjs +2 -0
- package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +1 -0
- package/dist/esm/common/floatingMenu/floatingMenu.module.mjs +2 -0
- package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +1 -0
- package/dist/esm/common/floatingMenu/floatingMenu.types.mjs +2 -0
- package/dist/esm/common/floatingMenu/floatingMenu.types.mjs.map +1 -0
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs +2 -0
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +1 -0
- package/dist/esm/common/iconPicker/iconPicker.mjs +2 -0
- package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -0
- package/dist/esm/common/iconPicker/iconPicker.module.mjs +2 -0
- package/dist/esm/common/iconPicker/iconPicker.module.mjs.map +1 -0
- package/dist/esm/common/idleManager/idleManager.mjs +2 -0
- package/dist/esm/common/idleManager/idleManager.mjs.map +1 -0
- package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +2 -0
- package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +1 -0
- package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs +2 -0
- package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs.map +1 -0
- package/dist/esm/common/input/input.mjs +2 -0
- package/dist/esm/common/input/input.mjs.map +1 -0
- package/dist/esm/common/input/input.module.mjs +2 -0
- package/dist/esm/common/input/input.module.mjs.map +1 -0
- package/dist/esm/common/input/input.types.mjs +2 -0
- package/dist/esm/common/input/input.types.mjs.map +1 -0
- package/dist/esm/common/inputDropdown/inputDropdown.mjs +2 -0
- package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -0
- package/dist/esm/common/inputDropdown/inputDropdown.module.mjs +2 -0
- package/dist/esm/common/inputDropdown/inputDropdown.module.mjs.map +1 -0
- package/dist/esm/common/interactableDiv/index.mjs +2 -0
- package/dist/esm/common/interactableDiv/index.mjs.map +1 -0
- package/dist/esm/common/interactableDiv/interactableDiv.mjs +2 -0
- package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -0
- package/dist/esm/common/interactableDiv/interactableDiv.module.mjs +2 -0
- package/dist/esm/common/interactableDiv/interactableDiv.module.mjs.map +1 -0
- package/dist/esm/common/kanbanBoard/KanbanBoard.mjs +2 -0
- package/dist/esm/common/kanbanBoard/KanbanBoard.mjs.map +1 -0
- package/dist/esm/common/kanbanBoard/KanbanColumn.mjs +2 -0
- package/dist/esm/common/kanbanBoard/KanbanColumn.mjs.map +1 -0
- package/dist/esm/common/kanbanBoard/KanbanItem.mjs +2 -0
- package/dist/esm/common/kanbanBoard/KanbanItem.mjs.map +1 -0
- package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs +2 -0
- package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs.map +1 -0
- package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.mjs +2 -0
- package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.mjs.map +1 -0
- package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs +2 -0
- package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs.map +1 -0
- package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs +2 -0
- package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs.map +1 -0
- package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs +2 -0
- package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs.map +1 -0
- package/dist/esm/common/klipyPicker/klipyPicker.mjs +2 -0
- package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -0
- package/dist/esm/common/klipyPicker/klipyPicker.module.mjs +2 -0
- package/dist/esm/common/klipyPicker/klipyPicker.module.mjs.map +1 -0
- package/dist/esm/common/loading/iconLoading/iconLoading.mjs +2 -0
- package/dist/esm/common/loading/iconLoading/iconLoading.mjs.map +1 -0
- package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs +2 -0
- package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs.map +1 -0
- package/dist/esm/common/loading/iconLoading/index.mjs +2 -0
- package/dist/esm/common/loading/iconLoading/index.mjs.map +1 -0
- package/dist/esm/common/loading/spinnerLoading/index.mjs +2 -0
- package/dist/esm/common/loading/spinnerLoading/index.mjs.map +1 -0
- package/dist/esm/common/loading/spinnerLoading/spinnerLoading.mjs +2 -0
- package/dist/esm/common/loading/spinnerLoading/spinnerLoading.mjs.map +1 -0
- package/dist/esm/common/loading/spinnerLoading/spinnerLoading.module.mjs +2 -0
- package/dist/esm/common/loading/spinnerLoading/spinnerLoading.module.mjs.map +1 -0
- package/dist/esm/common/modal/modal.mjs +2 -0
- package/dist/esm/common/modal/modal.mjs.map +1 -0
- package/dist/esm/common/modal/modal.module.mjs +2 -0
- package/dist/esm/common/modal/modal.module.mjs.map +1 -0
- package/dist/esm/common/numberInput/index.mjs +2 -0
- package/dist/esm/common/numberInput/index.mjs.map +1 -0
- package/dist/esm/common/numberInput/numberInput.mjs +2 -0
- package/dist/esm/common/numberInput/numberInput.mjs.map +1 -0
- package/dist/esm/common/numberInput/numberInput.module.mjs +2 -0
- package/dist/esm/common/numberInput/numberInput.module.mjs.map +1 -0
- package/dist/esm/common/optionPicker/optionPicker.mjs +2 -0
- package/dist/esm/common/optionPicker/optionPicker.mjs.map +1 -0
- package/dist/esm/common/optionPicker/optionPicker.module.mjs +2 -0
- package/dist/esm/common/optionPicker/optionPicker.module.mjs.map +1 -0
- package/dist/esm/common/overscroll/overscroll.mjs +2 -0
- package/dist/esm/common/overscroll/overscroll.mjs.map +1 -0
- package/dist/esm/common/overscroll/overscroll.module.mjs +2 -0
- package/dist/esm/common/overscroll/overscroll.module.mjs.map +1 -0
- package/dist/esm/common/progressBar/progressBar.mjs +2 -0
- package/dist/esm/common/progressBar/progressBar.mjs.map +1 -0
- package/dist/esm/common/progressBar/progressBar.module.mjs +2 -0
- package/dist/esm/common/progressBar/progressBar.module.mjs.map +1 -0
- package/dist/esm/common/ripple/ripple.mjs +2 -0
- package/dist/esm/common/ripple/ripple.mjs.map +1 -0
- package/dist/esm/common/ripple/ripple.module.mjs +2 -0
- package/dist/esm/common/ripple/ripple.module.mjs.map +1 -0
- package/dist/esm/common/roomDrawer/roomDrawer.mjs +2 -0
- package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -0
- package/dist/esm/common/roomDrawer/roomDrawer.module.mjs +2 -0
- package/dist/esm/common/roomDrawer/roomDrawer.module.mjs.map +1 -0
- package/dist/esm/common/roomDrawer/roomDrawer.utils.mjs +6 -0
- package/dist/esm/common/roomDrawer/roomDrawer.utils.mjs.map +1 -0
- package/dist/esm/common/roomViewer/roomViewer.mjs +2 -0
- package/dist/esm/common/roomViewer/roomViewer.mjs.map +1 -0
- package/dist/esm/common/roomViewer/roomViewer.module.mjs +2 -0
- package/dist/esm/common/roomViewer/roomViewer.module.mjs.map +1 -0
- package/dist/esm/common/scrollbarProvider/index.mjs +2 -0
- package/dist/esm/common/scrollbarProvider/index.mjs.map +1 -0
- package/dist/esm/common/scrollbarProvider/scrollbarProvider.mjs +2 -0
- package/dist/esm/common/scrollbarProvider/scrollbarProvider.mjs.map +1 -0
- package/dist/esm/common/scrollbarProvider/scrollbarProvider.module.mjs +2 -0
- package/dist/esm/common/scrollbarProvider/scrollbarProvider.module.mjs.map +1 -0
- package/dist/esm/common/searchInput/searchInput.mjs +2 -0
- package/dist/esm/common/searchInput/searchInput.mjs.map +1 -0
- package/dist/esm/common/searchInput/searchInput.module.mjs +2 -0
- package/dist/esm/common/searchInput/searchInput.module.mjs.map +1 -0
- package/dist/esm/common/skeleton/skeleton.mjs +2 -0
- package/dist/esm/common/skeleton/skeleton.mjs.map +1 -0
- package/dist/esm/common/skeleton/skeleton.module.mjs +2 -0
- package/dist/esm/common/skeleton/skeleton.module.mjs.map +1 -0
- package/dist/esm/common/skeleton/skeleton.types.mjs +2 -0
- package/dist/esm/common/skeleton/skeleton.types.mjs.map +1 -0
- package/dist/esm/common/stepper/stepper.mjs +2 -0
- package/dist/esm/common/stepper/stepper.mjs.map +1 -0
- package/dist/esm/common/stepper/stepper.module.mjs +2 -0
- package/dist/esm/common/stepper/stepper.module.mjs.map +1 -0
- package/dist/esm/common/sticky/sticky.mjs +2 -0
- package/dist/esm/common/sticky/sticky.mjs.map +1 -0
- package/dist/esm/common/sticky/sticky.module.mjs +2 -0
- package/dist/esm/common/sticky/sticky.module.mjs.map +1 -0
- package/dist/esm/common/switch/switch.mjs +2 -0
- package/dist/esm/common/switch/switch.mjs.map +1 -0
- package/dist/esm/common/switch/switch.module.mjs +2 -0
- package/dist/esm/common/switch/switch.module.mjs.map +1 -0
- package/dist/esm/common/tabHeader/tabHeader.mjs +2 -0
- package/dist/esm/common/tabHeader/tabHeader.mjs.map +1 -0
- package/dist/esm/common/tabHeader/tabHeader.module.mjs +2 -0
- package/dist/esm/common/tabHeader/tabHeader.module.mjs.map +1 -0
- package/dist/esm/common/textarea/textarea.mjs +2 -0
- package/dist/esm/common/textarea/textarea.mjs.map +1 -0
- package/dist/esm/common/themeProvider/defaultTheme.mjs +2 -0
- package/dist/esm/common/themeProvider/defaultTheme.mjs.map +1 -0
- package/dist/esm/common/themeProvider/theme.module.mjs +2 -0
- package/dist/esm/common/themeProvider/theme.module.mjs.map +1 -0
- package/dist/esm/common/themeProvider/themeProvider.mjs +2 -0
- package/dist/esm/common/themeProvider/themeProvider.mjs.map +1 -0
- package/dist/esm/common/themeProvider/useTheme.mjs +2 -0
- package/dist/esm/common/themeProvider/useTheme.mjs.map +1 -0
- package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs +2 -0
- package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs.map +1 -0
- package/dist/esm/common/timeInput/components/clockDial/clockDial.module.mjs +2 -0
- package/dist/esm/common/timeInput/components/clockDial/clockDial.module.mjs.map +1 -0
- package/dist/esm/common/timeInput/timeFunctions.mjs +2 -0
- package/dist/esm/common/timeInput/timeFunctions.mjs.map +1 -0
- package/dist/esm/common/timeInput/timeInput.mjs +2 -0
- package/dist/esm/common/timeInput/timeInput.mjs.map +1 -0
- package/dist/esm/common/timeInput/timeInput.module.mjs +2 -0
- package/dist/esm/common/timeInput/timeInput.module.mjs.map +1 -0
- package/dist/esm/common/toast/toast.mjs +2 -0
- package/dist/esm/common/toast/toast.mjs.map +1 -0
- package/dist/esm/common/toast/toast.module.mjs +2 -0
- package/dist/esm/common/toast/toast.module.mjs.map +1 -0
- package/dist/esm/common/toast/toastProvider.mjs +2 -0
- package/dist/esm/common/toast/toastProvider.mjs.map +1 -0
- package/dist/esm/common/toast/toastService.mjs +2 -0
- package/dist/esm/common/toast/toastService.mjs.map +1 -0
- package/dist/esm/common/tooltip/tooltip.mjs +2 -0
- package/dist/esm/common/tooltip/tooltip.mjs.map +1 -0
- package/dist/esm/common/tooltip/tooltip.module.mjs +2 -0
- package/dist/esm/common/tooltip/tooltip.module.mjs.map +1 -0
- package/dist/esm/common/virtualList/useColumns.mjs +2 -0
- package/dist/esm/common/virtualList/useColumns.mjs.map +1 -0
- package/dist/esm/common/virtualList/useRowDrag.mjs +2 -0
- package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -0
- package/dist/esm/common/virtualList/useSelection.mjs +2 -0
- package/dist/esm/common/virtualList/useSelection.mjs.map +1 -0
- package/dist/esm/common/virtualList/useVirtualWindow.mjs +2 -0
- package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -0
- package/dist/esm/common/virtualList/virtualList.mjs +2 -0
- package/dist/esm/common/virtualList/virtualList.mjs.map +1 -0
- package/dist/esm/common/virtualList/virtualList.module.mjs +2 -0
- package/dist/esm/common/virtualList/virtualList.module.mjs.map +1 -0
- package/dist/esm/common/virtualList/virtualList.utils.mjs +2 -0
- package/dist/esm/common/virtualList/virtualList.utils.mjs.map +1 -0
- package/dist/esm/common/virtualList/virtualRow.mjs +2 -0
- package/dist/esm/common/virtualList/virtualRow.mjs.map +1 -0
- package/dist/esm/common/wizard/wizard.mjs +2 -0
- package/dist/esm/common/wizard/wizard.mjs.map +1 -0
- package/dist/esm/common/wizard/wizard.module.mjs +2 -0
- package/dist/esm/common/wizard/wizard.module.mjs.map +1 -0
- package/dist/esm/hooks/useWindowSize.mjs +2 -0
- package/dist/esm/hooks/useWindowSize.mjs.map +1 -0
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/services/formValidation/FormValidatorGroupForm.mjs +2 -0
- package/dist/esm/services/formValidation/FormValidatorGroupForm.mjs.map +1 -0
- package/dist/esm/services/formValidation/FormValidatorGroupWithForm.mjs +2 -0
- package/dist/esm/services/formValidation/FormValidatorGroupWithForm.mjs.map +1 -0
- package/dist/esm/services/formValidation/formValidator.mjs +2 -0
- package/dist/esm/services/formValidation/formValidator.mjs.map +1 -0
- package/dist/esm/services/formValidation/formValidatorGroup.mjs +2 -0
- package/dist/esm/services/formValidation/formValidatorGroup.mjs.map +1 -0
- package/dist/esm/services/formValidation/useFormValidator.mjs +2 -0
- package/dist/esm/services/formValidation/useFormValidator.mjs.map +1 -0
- package/dist/esm/services/formValidation/useFormValidatorGroup.mjs +2 -0
- package/dist/esm/services/formValidation/useFormValidatorGroup.mjs.map +1 -0
- package/dist/esm/services/formValidation/validatableComponent.mjs +2 -0
- package/dist/esm/services/formValidation/validatableComponent.mjs.map +1 -0
- package/dist/esm/services/formValidation/validators.mjs +2 -0
- package/dist/esm/services/formValidation/validators.mjs.map +1 -0
- package/dist/esm/services/klipy.mjs +2 -0
- package/dist/esm/services/klipy.mjs.map +1 -0
- package/dist/esm/services/localization.mjs +2 -0
- package/dist/esm/services/localization.mjs.map +1 -0
- package/dist/esm/services/regexp.mjs +2 -0
- package/dist/esm/services/regexp.mjs.map +1 -0
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/package/common/dropdown/dropdown.d.ts +1 -1
- package/dist/types/package/common/dropdown/dropdown.types.d.ts +0 -1
- package/dist/types/package/common/floatingMenu/useFloatingPosition.d.ts +25 -0
- package/docs/Card.md +1 -1
- package/docs/Dropdown.md +2 -1
- package/docs/InputDropdown.md +2 -0
- package/docs/Tooltip.md +2 -0
- package/docs/VirtualList.md +1 -1
- package/package.json +4 -3
- package/dist/index.mjs +0 -6791
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeProvider.mjs","names":[],"sources":["../../../../package/common/themeProvider/themeProvider.tsx"],"sourcesContent":["import React, { Component } from 'react';\n\nimport type { Theme } from './theme.types';\nimport { defaultTheme } from './defaultTheme';\nimport styles from './theme.module.pcss';\n\ninterface Props {\n children: React.ReactNode;\n themes?: Theme[];\n currentThemeId?: string;\n}\n\ninterface State {\n resolvedVariables: Record<string, string>;\n colorFadeActive: boolean;\n currentThemeColor: string | null;\n}\n\nclass ThemeProvider extends Component<Props, State> {\n state: State = {\n resolvedVariables: {},\n colorFadeActive: false,\n currentThemeColor: null,\n };\n\n private colorFadeTimeout: ReturnType<typeof setTimeout> | null = null;\n private wrapperRef = React.createRef<HTMLDivElement>();\n private themeColorMeta: HTMLMetaElement | null = null;\n private createdThemeColorMeta = false;\n\n componentDidMount() {\n this.applyTheme(this.props.currentThemeId);\n this.syncThemeColorMeta(this.state.currentThemeColor ?? '');\n }\n\n componentDidUpdate(prevProps: Props, prevState: State) {\n if (prevState.currentThemeColor !== this.state.currentThemeColor) {\n this.syncThemeColorMeta(this.state.currentThemeColor ?? '');\n }\n if (\n prevProps.currentThemeId !== this.props.currentThemeId ||\n prevProps.themes !== this.props.themes\n ) {\n this.applyTheme(this.props.currentThemeId);\n }\n }\n\n componentWillUnmount() {\n if (this.colorFadeTimeout) clearTimeout(this.colorFadeTimeout);\n // Only remove the meta tag if we created it; leave a host-app tag intact.\n if (this.createdThemeColorMeta) this.themeColorMeta?.remove();\n }\n\n /**\n * Replaces the former react-helmet usage: keep a single\n * <meta name=\"theme-color\"> in sync with the active theme's primary colour.\n * Reuses a tag the host app already declares; otherwise creates its own\n * (and removes it again on unmount).\n */\n private syncThemeColorMeta(color: string) {\n if (typeof document === 'undefined') return;\n\n if (!this.themeColorMeta) {\n const existing = document.head.querySelector<HTMLMetaElement>(\n 'meta[name=\"theme-color\"]',\n );\n if (existing) {\n this.themeColorMeta = existing;\n } else {\n const meta = document.createElement('meta');\n meta.setAttribute('name', 'theme-color');\n document.head.appendChild(meta);\n this.themeColorMeta = meta;\n this.createdThemeColorMeta = true;\n }\n }\n\n this.themeColorMeta.setAttribute('content', color);\n }\n\n /**\n * Resolves the full variable set for a given theme ID by walking up the\n * baseThemeId chain. Returns variables ordered from deepest ancestor to\n * the requested theme so callers can merge in order (later entries win).\n */\n private resolveChain(id: string): Record<string, string>[] {\n const themes = this.props.themes ?? [defaultTheme];\n const theme = themes.find((t) => t.id === id);\n if (!theme) return [];\n\n const parentVars = theme.baseThemeId ? this.resolveChain(theme.baseThemeId) : [];\n\n return [...parentVars, theme.variables as Record<string, string>];\n }\n\n private applyTheme = (currentThemeId: string | undefined) => {\n const themes = this.props.themes ?? [defaultTheme];\n\n // The root theme is the first theme without a baseThemeId.\n // It is always applied as the variable foundation.\n const rootTheme = themes.find((t) => !t.baseThemeId) ?? themes[0];\n const rootVars: Record<string, string> = rootTheme\n ? (rootTheme.variables as Record<string, string>)\n : {};\n\n // Resolve the selected theme's full inheritance chain.\n const selectedTheme = themes.find((t) => t.id === currentThemeId);\n const chainVars = selectedTheme ? this.resolveChain(selectedTheme.id) : [];\n\n // Merge: root foundation → ancestor chain → selected theme (each step overrides)\n const resolvedVariables = Object.assign({}, rootVars, ...chainVars);\n\n this.setState({ resolvedVariables, colorFadeActive: true });\n\n if (this.colorFadeTimeout) clearTimeout(this.colorFadeTimeout);\n this.colorFadeTimeout = setTimeout(() => {\n this.setState({ colorFadeActive: false });\n this.colorFadeTimeout = null;\n }, 500);\n\n // Read --primary-color after the new style is painted for the theme-color meta tag.\n setTimeout(() => {\n if (this.wrapperRef.current) {\n this.setState({\n currentThemeColor: getComputedStyle(this.wrapperRef.current)\n .getPropertyValue('--primary-color')\n .trim(),\n });\n }\n }, 1);\n };\n\n render() {\n const { children } = this.props;\n const { resolvedVariables, colorFadeActive } = this.state;\n\n return (\n <div\n ref={this.wrapperRef}\n id=\"themeProvider\"\n className={colorFadeActive ? styles.colorFade : undefined}\n style={resolvedVariables as React.CSSProperties}\n >\n {children}\n </div>\n );\n }\n}\n\nexport default ThemeProvider;\n"],"mappings":"iKAkBA,IAAM,EAAN,cAA4B,CAAwB,0CACnC,CACb,kBAAmB,CAAC,EACpB,gBAAiB,GACjB,kBAAmB,IACrB,wBAEiE,qBAC5C,EAAM,UAA0B,sBACJ,gCACjB,mBAmEV,GAAuC,CAC3D,IAAM,EAAS,KAAK,MAAM,QAAU,CAAC,CAAY,EAI3C,EAAY,EAAO,KAAM,GAAM,CAAC,EAAE,WAAW,GAAK,EAAO,GACzD,EAAmC,EACpC,EAAU,UACX,CAAC,EAGC,EAAgB,EAAO,KAAM,GAAM,EAAE,KAAO,CAAc,EAC1D,EAAY,EAAgB,KAAK,aAAa,EAAc,EAAE,EAAI,CAAC,EAGnE,EAAoB,OAAO,OAAO,CAAC,EAAG,EAAU,GAAG,CAAS,EAElE,KAAK,SAAS,CAAE,oBAAmB,gBAAiB,EAAK,CAAC,EAEtD,KAAK,kBAAkB,aAAa,KAAK,gBAAgB,EAC7D,KAAK,iBAAmB,eAAiB,CACvC,KAAK,SAAS,CAAE,gBAAiB,EAAM,CAAC,EACxC,KAAK,iBAAmB,IAC1B,EAAG,GAAG,EAGN,eAAiB,CACX,KAAK,WAAW,SAClB,KAAK,SAAS,CACZ,kBAAmB,iBAAiB,KAAK,WAAW,OAAO,EACxD,iBAAiB,iBAAiB,EAClC,KAAK,CACV,CAAC,CAEL,EAAG,CAAC,CACN,EApGA,mBAAoB,CAClB,KAAK,WAAW,KAAK,MAAM,cAAc,EACzC,KAAK,mBAAmB,KAAK,MAAM,mBAAqB,EAAE,CAC5D,CAEA,mBAAmB,EAAkB,EAAkB,CACjD,EAAU,oBAAsB,KAAK,MAAM,mBAC7C,KAAK,mBAAmB,KAAK,MAAM,mBAAqB,EAAE,GAG1D,EAAU,iBAAmB,KAAK,MAAM,gBACxC,EAAU,SAAW,KAAK,MAAM,SAEhC,KAAK,WAAW,KAAK,MAAM,cAAc,CAE7C,CAEA,sBAAuB,CACjB,KAAK,kBAAkB,aAAa,KAAK,gBAAgB,EAEzD,KAAK,uBAAuB,KAAK,gBAAgB,OAAO,CAC9D,CAQA,mBAA2B,EAAe,CACpC,YAAO,SAAa,KAExB,IAAI,CAAC,KAAK,eAAgB,CACxB,IAAM,EAAW,SAAS,KAAK,cAC7B,0BACF,EACA,GAAI,EACF,KAAK,eAAiB,MACjB,CACL,IAAM,EAAO,SAAS,cAAc,MAAM,EAC1C,EAAK,aAAa,OAAQ,aAAa,EACvC,SAAS,KAAK,YAAY,CAAI,EAC9B,KAAK,eAAiB,EACtB,KAAK,sBAAwB,EAC/B,CACF,CAEA,KAAK,eAAe,aAAa,UAAW,CAAK,CAFjD,CAGF,CAOA,aAAqB,EAAsC,CAEzD,IAAM,GADS,KAAK,MAAM,QAAU,CAAC,CAAY,GAC5B,KAAM,GAAM,EAAE,KAAO,CAAE,EAK5C,OAJK,EAIE,CAAC,GAFW,EAAM,YAAc,KAAK,aAAa,EAAM,WAAW,EAAI,CAAC,EAExD,EAAM,SAAmC,EAJ7C,CAAC,CAKtB,CAuCA,QAAS,CACP,GAAM,CAAE,YAAa,KAAK,MACpB,CAAE,oBAAmB,mBAAoB,KAAK,MAEpD,OACE,EAAC,MAAD,CACE,IAAK,KAAK,WACV,GAAG,gBACH,UAAW,EAAkB,EAAO,UAAY,IAAA,GAChD,MAAO,EAEN,UACE,CAAA,CAET,CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTheme.mjs","names":[],"sources":["../../../../package/common/themeProvider/useTheme.ts"],"sourcesContent":["import { useState } from \"react\";\n\nexport function useTheme(defaultThemeId: string = 'default') {\n const [currentThemeId, setThemeId] = useState<string>(localStorage.getItem('theme') || defaultThemeId);\n\n const setCurrentThemeId = (themeId: string) => {\n setThemeId(themeId);\n localStorage.setItem('theme', themeId);\n };\n\n return { currentThemeId, setCurrentThemeId };\n}"],"mappings":"iCAEA,SAAgB,EAAS,EAAyB,UAAW,CAC3D,GAAM,CAAC,EAAgB,GAAc,EAAiB,aAAa,QAAQ,OAAO,GAAK,CAAc,EAOrG,MAAO,CAAE,iBAAgB,kBALE,GAAoB,CAC7C,EAAW,CAAO,EAClB,aAAa,QAAQ,QAAS,CAAO,CACvC,CAE2C,CAC7C"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{clampHour as e,pointerAngle as t,pointerRadius as n,polarPoint as r,snapMinute as i}from"../../timeFunctions.mjs";import a from"./clockDial.module.mjs";import{useRef as o}from"react";import s from"classnames";import{jsx as c,jsxs as l}from"react/jsx-runtime";var u=50,d=40,f=25.5,p=65.5/2,m=30,h=6,g=e=>(e+11)%12+1;function _(e,t){if(e===`minutes`)return Array.from({length:12},(e,t)=>{let n=t*5;return{label:String(n).padStart(2,`0`),slot:t,value:n,ring:`outer`}});if(!t)return Array.from({length:12},(e,t)=>{let n=t===0?12:t;return{label:String(n),slot:t,value:n,ring:`outer`}});let n=Array.from({length:12},(e,t)=>{let n=t===0?12:t;return{label:String(n),slot:t,value:n,ring:`outer`}}),r=Array.from({length:12},(e,t)=>{let n=t===0?0:t+12;return{label:String(n).padStart(2,`0`),slot:t,value:n,ring:`inner`}});return[...n,...r]}function v({time:v,mode:y,use24Hour:b,minuteStep:x,onChange:S,onCommit:C,classNames:w,styles:T}){let E=o(null),D=o(!1),O=_(y,b),k=v.hours>=12,A=g(v.hours),j=y===`minutes`?{slot:v.minutes,radius:d}:b?v.hours===0?{slot:0,radius:f}:v.hours<=12?{slot:v.hours%12,radius:d}:{slot:(v.hours-12)%12,radius:f}:{slot:A%12,radius:d},M=r(u,u,j.radius,j.slot,y===`minutes`?h:m),N=e=>y===`minutes`?i(v.minutes,x)===e.value||v.minutes===e.value:b?v.hours===e.value:A===e.value,P=(r,a)=>{let o=E.current?.getBoundingClientRect();if(!o)return v;let s=r-(o.left+o.width/2),c=a-(o.top+o.height/2),l=t(s,c);if(y===`minutes`){let e=i(Math.round(l/h),x);return{hours:v.hours,minutes:e}}let d=Math.round(l/m)%12;if(!b){let t=d===0?12:d;return{hours:e(k?t%12+12:t%12),minutes:v.minutes}}return{hours:e(n(s,c)/(o.width/2)*u<p?d===0?0:d+12:d===0?12:d),minutes:v.minutes}};return l(`div`,{ref:E,className:s(a.clockFace,w?.clockFace),style:T?.clockFace,onPointerDown:e=>{D.current=!0,e.currentTarget.setPointerCapture?.(e.pointerId),S(P(e.clientX,e.clientY))},onPointerMove:e=>{D.current&&S(P(e.clientX,e.clientY))},onPointerUp:e=>{D.current&&(D.current=!1,C(P(e.clientX,e.clientY)))},role:`slider`,"aria-label":y===`minutes`?`Minutes`:`Hours`,"aria-valuetext":y===`minutes`?`${v.minutes} minutes`:`${v.hours} hours`,children:[l(`svg`,{className:a.clockHand,viewBox:`0 0 100 100`,"aria-hidden":!0,children:[c(`circle`,{cx:u,cy:u,r:1.8,className:a.clockHandCenter}),c(`line`,{x1:u,y1:u,x2:M.x,y2:M.y,className:a.clockHandLine}),c(`circle`,{cx:M.x,cy:M.y,r:7,className:s(a.clockHandKnob,w?.clockHand),style:T?.clockHand})]}),O.map(e=>{let t=r(u,u,e.ring===`inner`?f:d,e.slot,m),n=N(e);return c(`div`,{className:s(a.clockNumber,e.ring===`inner`&&a.clockNumberInner,n&&a.clockNumberSelected,w?.clockNumber),style:{left:`${t.x}%`,top:`${t.y}%`,...T?.clockNumber},children:e.label},`${e.ring}-${e.value}`)})]})}export{v as default};
|
|
2
|
+
//# sourceMappingURL=clockDial.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clockDial.mjs","names":[],"sources":["../../../../../../package/common/timeInput/components/clockDial/clockDial.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport cx from 'classnames';\nimport {\n type TimeValue,\n clampHour,\n snapMinute,\n polarPoint,\n pointerAngle,\n pointerRadius,\n} from '../../timeFunctions';\nimport type { ClockDialProps, DialNumber } from './clockDial.types';\n\nimport styles from './clockDial.module.pcss';\n\n// viewBox units (0–100). The face scales with its CSS box; geometry stays in this space.\nconst CENTER = 50;\nconst OUTER_RADIUS = 40;\nconst INNER_RADIUS = 25.5;\nconst RING_THRESHOLD = (OUTER_RADIUS + INNER_RADIUS) / 2;\n\nconst HOUR_STEP_DEG = 30;\nconst MINUTE_STEP_DEG = 6;\n\nconst to12 = (hour: number): number => ((hour + 11) % 12) + 1;\n\n/** Build the labelled numbers for the current mode/format. */\nfunction buildNumbers(mode: 'hours' | 'minutes', use24Hour: boolean): DialNumber[] {\n if (mode === 'minutes') {\n return Array.from({ length: 12 }, (_, slot) => {\n const value = slot * 5;\n return { label: String(value).padStart(2, '0'), slot, value, ring: 'outer' as const };\n });\n }\n\n if (!use24Hour) {\n return Array.from({ length: 12 }, (_, slot) => {\n const value = slot === 0 ? 12 : slot; // displayed hour (1–12)\n return { label: String(value), slot, value, ring: 'outer' as const };\n });\n }\n\n // 24-hour double ring: outer 1–12, inner 00/13–23.\n const outer = Array.from({ length: 12 }, (_, slot) => {\n const value = slot === 0 ? 12 : slot;\n return { label: String(value), slot, value, ring: 'outer' as const };\n });\n const inner = Array.from({ length: 12 }, (_, slot) => {\n const value = slot === 0 ? 0 : slot + 12;\n return { label: String(value).padStart(2, '0'), slot, value, ring: 'inner' as const };\n });\n return [...outer, ...inner];\n}\n\nexport default function ClockDial({\n time,\n mode,\n use24Hour,\n minuteStep,\n onChange,\n onCommit,\n classNames,\n styles: slotStyles,\n}: ClockDialProps) {\n const faceRef = useRef<HTMLDivElement>(null);\n const draggingRef = useRef(false);\n\n const numbers = buildNumbers(mode, use24Hour);\n\n // Resolve the active value and the hand geometry for the current time.\n const isPm = time.hours >= 12;\n const selectedHour12 = to12(time.hours);\n\n const hand = (() => {\n if (mode === 'minutes') {\n // 6° per minute → angle = minutes * MINUTE_STEP_DEG.\n return { slot: time.minutes, radius: OUTER_RADIUS };\n }\n if (!use24Hour) {\n return { slot: selectedHour12 % 12, radius: OUTER_RADIUS };\n }\n if (time.hours === 0) return { slot: 0, radius: INNER_RADIUS };\n if (time.hours <= 12) return { slot: time.hours % 12, radius: OUTER_RADIUS };\n return { slot: (time.hours - 12) % 12, radius: INNER_RADIUS };\n })();\n\n const knob = polarPoint(CENTER, CENTER, hand.radius, hand.slot, mode === 'minutes' ? MINUTE_STEP_DEG : HOUR_STEP_DEG);\n\n const isSelected = (n: DialNumber): boolean =>\n mode === 'minutes'\n ? snapMinute(time.minutes, minuteStep) === n.value || time.minutes === n.value\n : use24Hour\n ? time.hours === n.value\n : selectedHour12 === n.value;\n\n const valueFromPointer = (clientX: number, clientY: number): TimeValue => {\n const rect = faceRef.current?.getBoundingClientRect();\n if (!rect) return time;\n const dx = clientX - (rect.left + rect.width / 2);\n const dy = clientY - (rect.top + rect.height / 2);\n const angle = pointerAngle(dx, dy);\n\n if (mode === 'minutes') {\n const minutes = snapMinute(Math.round(angle / MINUTE_STEP_DEG), minuteStep);\n return { hours: time.hours, minutes };\n }\n\n const slot = Math.round(angle / HOUR_STEP_DEG) % 12;\n if (!use24Hour) {\n const display = slot === 0 ? 12 : slot;\n const hours = isPm ? (display % 12) + 12 : display % 12;\n return { hours: clampHour(hours), minutes: time.minutes };\n }\n\n // 24h: inner vs outer ring decided by pointer distance from centre.\n const radiusFrac = (pointerRadius(dx, dy) / (rect.width / 2)) * CENTER;\n const inner = radiusFrac < RING_THRESHOLD;\n const hours = inner ? (slot === 0 ? 0 : slot + 12) : slot === 0 ? 12 : slot;\n return { hours: clampHour(hours), minutes: time.minutes };\n };\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n draggingRef.current = true;\n // setPointerCapture keeps move/up events flowing to the face even when the\n // pointer started on (or drags over) a number. Guarded for jsdom.\n (e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId);\n onChange(valueFromPointer(e.clientX, e.clientY));\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current) return;\n onChange(valueFromPointer(e.clientX, e.clientY));\n };\n\n const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current) return;\n draggingRef.current = false;\n onCommit(valueFromPointer(e.clientX, e.clientY));\n };\n\n return (\n <div\n ref={faceRef}\n className={cx(styles.clockFace, classNames?.clockFace)}\n style={slotStyles?.clockFace}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n role=\"slider\"\n aria-label={mode === 'minutes' ? 'Minutes' : 'Hours'}\n aria-valuetext={mode === 'minutes' ? `${time.minutes} minutes` : `${time.hours} hours`}\n >\n <svg className={styles.clockHand} viewBox=\"0 0 100 100\" aria-hidden>\n <circle cx={CENTER} cy={CENTER} r={1.8} className={styles.clockHandCenter} />\n <line x1={CENTER} y1={CENTER} x2={knob.x} y2={knob.y} className={styles.clockHandLine} />\n <circle\n cx={knob.x}\n cy={knob.y}\n r={7}\n className={cx(styles.clockHandKnob, classNames?.clockHand)}\n style={slotStyles?.clockHand as React.CSSProperties}\n />\n </svg>\n\n {numbers.map((n) => {\n const p = polarPoint(CENTER, CENTER, n.ring === 'inner' ? INNER_RADIUS : OUTER_RADIUS, n.slot, HOUR_STEP_DEG);\n const selected = isSelected(n);\n // Purely visual — the face owns all pointer handling so click and drag\n // behave identically whether the pointer lands on a number or between two.\n return (\n <div\n key={`${n.ring}-${n.value}`}\n className={cx(\n styles.clockNumber,\n n.ring === 'inner' && styles.clockNumberInner,\n selected && styles.clockNumberSelected,\n classNames?.clockNumber,\n )}\n style={{ left: `${p.x}%`, top: `${p.y}%`, ...slotStyles?.clockNumber }}\n >\n {n.label}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={clockFace:`clockFace_LbXIa`,clockHand:`clockHand_E9nTw`,"clockHand-line":`clockHand-line_iOipC`,clockHandLine:`clockHand-line_iOipC`,"clockHand-center":`clockHand-center_VElxx`,clockHandCenter:`clockHand-center_VElxx`,"clockHand-knob":`clockHand-knob_Mb2Fx`,clockHandKnob:`clockHand-knob_Mb2Fx`,clockNumber:`clockNumber_qHDO8`,"clockNumber-inner":`clockNumber-inner_x2XR1`,clockNumberInner:`clockNumber-inner_x2XR1`,"clockNumber-selected":`clockNumber-selected_rPVlV`,clockNumberSelected:`clockNumber-selected_rPVlV`};export{e as default};
|
|
2
|
+
//# sourceMappingURL=clockDial.module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clockDial.module.mjs","names":[],"sources":["../../../../../../package/common/timeInput/components/clockDial/clockDial.module.pcss"],"sourcesContent":[".clockFace {\n position: relative;\n width: var(--clock-size, 256px);\n height: var(--clock-size, 256px);\n margin: 4px auto;\n border-radius: 50%;\n background: var(--background-accent-light, var(--background-accent));\n touch-action: none;\n user-select: none;\n cursor: pointer;\n}\n\n.clockHand {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n overflow: visible;\n\n &-line {\n stroke: var(--primary-color);\n stroke-width: 0.7;\n }\n\n &-center {\n fill: var(--primary-color);\n }\n\n &-knob {\n fill: var(--primary-color);\n }\n}\n\n.clockNumber {\n position: absolute;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n color: var(--text-color);\n font-size: 15px;\n font-weight: 500;\n line-height: 1;\n /* Visual only — the face handles all pointer interaction. */\n pointer-events: none;\n z-index: 1;\n\n &-inner {\n font-size: 12px;\n color: var(--text-dark);\n }\n\n &-selected {\n color: var(--text-on-primary);\n font-weight: 600;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=e=>(Math.trunc(e)%24+24)%24,t=e=>(Math.trunc(e)%60+60)%60;function n(e){if(!e)return null;let t=e.match(/^(\d{1,2}):(\d{1,2})$/);if(!t)return null;let n=Number(t[1]),r=Number(t[2]);return n>23||r>59?null:{hours:n,minutes:r}}function r(n){return n?`${String(e(n.hours)).padStart(2,`0`)}:${String(t(n.minutes)).padStart(2,`0`)}`:``}function i(e,n){return t(!n||n<=1?e:Math.round(t(e)/n)*n)}var a=e=>e.hours*60+e.minutes;function o(e,t,r){let i=a(e),o=n(t),s=n(r);return o&&(i=Math.max(i,a(o))),s&&(i=Math.min(i,a(s))),{hours:Math.floor(i/60),minutes:i%60}}function s(e,t,n,r,i){let a=r*i*Math.PI/180;return{x:e+n*Math.sin(a),y:t-n*Math.cos(a)}}function c(e,t){return(Math.atan2(e,-t)*180/Math.PI+360)%360}var l=(e,t)=>Math.sqrt(e*e+t*t);export{e as clampHour,o as clampToRange,r as formatTime,n as parseTimeString,c as pointerAngle,l as pointerRadius,s as polarPoint,i as snapMinute};
|
|
2
|
+
//# sourceMappingURL=timeFunctions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeFunctions.mjs","names":[],"sources":["../../../../package/common/timeInput/timeFunctions.ts"],"sourcesContent":["export interface TimeValue {\n hours: number; // 0–23\n minutes: number; // 0–59\n}\n\nexport const clampHour = (h: number): number => ((Math.trunc(h) % 24) + 24) % 24;\nexport const clampMinute = (m: number): number => ((Math.trunc(m) % 60) + 60) % 60;\n\n/** Parse a \"HH:MM\" (24-hour) string. Returns null for anything that isn't a valid time. */\nexport function parseTimeString(value: string | null | undefined): TimeValue | null {\n if (!value) return null;\n const match = value.match(/^(\\d{1,2}):(\\d{1,2})$/);\n if (!match) return null;\n const hours = Number(match[1]);\n const minutes = Number(match[2]);\n if (hours > 23 || minutes > 59) return null;\n return { hours, minutes };\n}\n\n/** Format a TimeValue as a zero-padded \"HH:MM\" string. */\nexport function formatTime(time: TimeValue | null | undefined): string {\n if (!time) return '';\n const hh = String(clampHour(time.hours)).padStart(2, '0');\n const mm = String(clampMinute(time.minutes)).padStart(2, '0');\n return `${hh}:${mm}`;\n}\n\n/** Snap a minute value to the nearest multiple of `step` (step <= 1 is a no-op). */\nexport function snapMinute(minute: number, step: number): number {\n if (!step || step <= 1) return clampMinute(minute);\n return clampMinute(Math.round(clampMinute(minute) / step) * step);\n}\n\nexport const timeToMinutes = (time: TimeValue): number => time.hours * 60 + time.minutes;\n\n/** Clamp a time into [min, max] (both \"HH:MM\" strings, either optional). */\nexport function clampToRange(time: TimeValue, min?: string | null, max?: string | null): TimeValue {\n let total = timeToMinutes(time);\n const minVal = parseTimeString(min);\n const maxVal = parseTimeString(max);\n if (minVal) total = Math.max(total, timeToMinutes(minVal));\n if (maxVal) total = Math.min(total, timeToMinutes(maxVal));\n return { hours: Math.floor(total / 60), minutes: total % 60 };\n}\n\nexport function isWithinRange(time: TimeValue, min?: string | null, max?: string | null): boolean {\n const total = timeToMinutes(time);\n const minVal = parseTimeString(min);\n const maxVal = parseTimeString(max);\n if (minVal && total < timeToMinutes(minVal)) return false;\n if (maxVal && total > timeToMinutes(maxVal)) return false;\n return true;\n}\n\n/**\n * Auto-correct a masked \"HH:MM\" value as the user types: clamp the hour segment to 23\n * and the minute segment to 59 so the field can never hold an impossible time.\n */\nexport function correctTimeMaskValue(value: string): string {\n const digits = value.replace(/[^\\d]/g, '');\n if (!digits) return value;\n\n let hourDigits = digits.slice(0, 2);\n const minuteDigits = digits.slice(2, 4);\n\n // First hour digit > 2 → it can only be a single-digit hour (e.g. \"9\" → \"09\").\n if (hourDigits.length === 1 && Number(hourDigits) > 2) {\n hourDigits = `0${hourDigits}`;\n }\n if (hourDigits.length === 2 && Number(hourDigits) > 23) hourDigits = '23';\n\n let result = hourDigits;\n if (minuteDigits.length > 0 || /:/.test(value)) result += ':';\n if (minuteDigits.length > 0) {\n const clamped = minuteDigits.length === 2 && Number(minuteDigits) > 59 ? '59' : minuteDigits;\n result += clamped;\n }\n return result;\n}\n\n// ── Clock-dial geometry ─────────────────────────────────────────────────────\n\nexport interface DialPoint {\n x: number;\n y: number;\n}\n\n/**\n * Cartesian coordinates for a point on the dial. `slot` is the step index from the\n * top of the clock, going clockwise; `stepDegrees` is the angle between steps\n * (30° for hours, 6° for minutes). Returns coordinates relative to (cx, cy).\n */\nexport function polarPoint(cx: number, cy: number, radius: number, slot: number, stepDegrees: number): DialPoint {\n const theta = (slot * stepDegrees * Math.PI) / 180;\n return {\n x: cx + radius * Math.sin(theta),\n y: cy - radius * Math.cos(theta),\n };\n}\n\n/** Rotation (deg) of a hand pointing at `slot`. A 3-o'clock-default hand points up at slot 0. */\nexport const handAngle = (slot: number, stepDegrees: number): number => slot * stepDegrees - 90;\n\n/** Angle (0–360, clockwise from top) of a pointer at (dx, dy) relative to the dial centre. */\nexport function pointerAngle(dx: number, dy: number): number {\n const deg = (Math.atan2(dx, -dy) * 180) / Math.PI;\n return (deg + 360) % 360;\n}\n\nexport const pointerRadius = (dx: number, dy: number): number => Math.sqrt(dx * dx + dy * dy);\n"],"mappings":"AAKA,IAAa,EAAa,IAAwB,KAAK,MAAM,CAAC,EAAI,GAAM,IAAM,GACjE,EAAe,IAAwB,KAAK,MAAM,CAAC,EAAI,GAAM,IAAM,GAGhF,SAAgB,EAAgB,EAAoD,CAClF,GAAI,CAAC,EAAO,OAAO,KACnB,IAAM,EAAQ,EAAM,MAAM,uBAAuB,EACjD,GAAI,CAAC,EAAO,OAAO,KACnB,IAAM,EAAQ,OAAO,EAAM,EAAE,EACvB,EAAU,OAAO,EAAM,EAAE,EAE/B,OADI,EAAQ,IAAM,EAAU,GAAW,KAChC,CAAE,QAAO,SAAQ,CAC1B,CAGA,SAAgB,EAAW,EAA4C,CAIrE,OAHK,EAGE,GAFI,OAAO,EAAU,EAAK,KAAK,CAAC,EAAE,SAAS,EAAG,GAE3C,EAAG,GADF,OAAO,EAAY,EAAK,OAAO,CAAC,EAAE,SAAS,EAAG,GACzC,IAHE,EAIpB,CAGA,SAAgB,EAAW,EAAgB,EAAsB,CAE/D,OAD+B,EAA3B,CAAC,GAAQ,GAAQ,EAAsB,EACxB,KAAK,MAAM,EAAY,CAAM,EAAI,CAAI,EAAI,CADX,CAEnD,CAEA,IAAa,EAAiB,GAA4B,EAAK,MAAQ,GAAK,EAAK,QAGjF,SAAgB,EAAa,EAAiB,EAAqB,EAAgC,CACjG,IAAI,EAAQ,EAAc,CAAI,EACxB,EAAS,EAAgB,CAAG,EAC5B,EAAS,EAAgB,CAAG,EAGlC,OAFI,IAAQ,EAAQ,KAAK,IAAI,EAAO,EAAc,CAAM,CAAC,GACrD,IAAQ,EAAQ,KAAK,IAAI,EAAO,EAAc,CAAM,CAAC,GAClD,CAAE,MAAO,KAAK,MAAM,EAAQ,EAAE,EAAG,QAAS,EAAQ,EAAG,CAC9D,CAiDA,SAAgB,EAAW,EAAY,EAAY,EAAgB,EAAc,EAAgC,CAC/G,IAAM,EAAS,EAAO,EAAc,KAAK,GAAM,IAC/C,MAAO,CACL,EAAG,EAAK,EAAS,KAAK,IAAI,CAAK,EAC/B,EAAG,EAAK,EAAS,KAAK,IAAI,CAAK,CACjC,CACF,CAMA,SAAgB,EAAa,EAAY,EAAoB,CAE3D,OADa,KAAK,MAAM,EAAI,CAAC,CAAE,EAAI,IAAO,KAAK,GACjC,KAAO,GACvB,CAEA,IAAa,GAAiB,EAAY,IAAuB,KAAK,KAAK,EAAK,EAAK,EAAK,CAAE"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ButtonStyleType as e}from"../button/button.types.mjs";import t from"../button/button.mjs";import{Align as n}from"../floatingMenu/floatingMenu.types.mjs";import r from"../floatingMenu/floatingMenu.mjs";import i from"../tooltip/tooltip.mjs";import a from"../input/input.mjs";import ee from"../modal/modal.mjs";import{clampHour as te,clampToRange as o,formatTime as s,parseTimeString as c,snapMinute as l}from"./timeFunctions.mjs";import ne from"./components/clockDial/clockDial.mjs";import u from"./timeInput.module.mjs";import{useEffect as re,useRef as ie,useState as d}from"react";import f from"classnames";import{FontAwesomeIcon as ae}from"@fortawesome/react-fontawesome";import{faClock as oe}from"@fortawesome/free-solid-svg-icons";import{jsx as p,jsxs as m}from"react/jsx-runtime";import h from"@mona-health/react-input-mask";function g({value:g,selected:se,onChange:ce=()=>null,onSelect:_=()=>null,formValidator:v=null,isInline:y=!1,isModal:b=!1,noInput:le=!1,noHeader:ue=!1,showClearButton:x=!1,showNowButton:S=!1,minuteStep:C=1,use24Hour:w=!0,minTime:T=null,maxTime:E=null,label:D=``,isValid:de=!0,errorMessage:O=``,isRequired:k=!1,disabled:A=!1,className:fe=``,style:pe,classNames:j,styles:M,...me}){let N=()=>v?v.value||``:g??se??``,[P,F]=d(N),[I,L]=d(!1),[R,z]=d(`hours`),[he,B]=d(!1),[ge,V]=d(!1),[,_e]=d(0),H=N(),[ve,ye]=d(H),U=ie(v);!v&&ve!==H&&(ye(H),F(H)),re(()=>{if(U.current=v,!v)return;let e=()=>{F(v.value||``),_e(e=>e+1)};return v.registerOnUpdateListener(e),()=>v.removeOnUpdateListener(e)},[v]);let be=()=>v?v.touched&&v.hasError():!de||!!O,xe=()=>!!(k||v?.validators.find(e=>e.validatorId===`required`)),W=e=>{let t=e?s(e):null;v&&v.set(t),ce?.(t)},G=e=>{F(e?s(e):``),W(e)},K=c(P),q=K??{hours:12,minutes:0},J=e=>{G(o({hours:e.hours,minutes:l(e.minutes,C)},T,E))},Se=e=>{let t=o({hours:e.hours,minutes:l(e.minutes,C)},T,E);if(G(t),R===`hours`){z(`minutes`);return}_?.(s(t)),y||L(!1)},Y=()=>{A||(z(`hours`),L(!0))},Ce=({previousState:e,nextState:t})=>{if(!e||t.value===e.value)return t;let n=t.value,r=n.slice(0,2);/^\d\d$/.test(r)&&Number(r)>23&&(n=`23${n.slice(2)}`);let i=n.slice(3,5);return/^\d\d$/.test(i)&&Number(i)>59&&(n=`${n.slice(0,3)}59`),n===t.value?t:{...t,value:n}},we=e=>{F(e);let t=c(e);t&&W(t)},Te=()=>{U.current&&(U.current.touched=!0),B(!1),W(c(P))},X=e=>{e!==q.hours>=12&&G({hours:te(q.hours+(e?12:-12)),minutes:q.minutes})},Z=be(),Ee=K?String(w?K.hours:(K.hours+11)%12+1).padStart(2,`0`):`--`,De=K?String(K.minutes).padStart(2,`0`):`--`,Oe=ue?null:m(`div`,{className:f(u.timeInputClockHeader,j?.clockHeader),style:M?.clockHeader,children:[p(`button`,{type:`button`,className:f(u.timeInputHeaderSegment,R===`hours`&&u.timeInputHeaderSegmentActive,j?.headerSegment),style:M?.headerSegment,onClick:()=>z(`hours`),children:Ee}),p(`span`,{className:u.timeInputHeaderColon,children:`:`}),p(`button`,{type:`button`,className:f(u.timeInputHeaderSegment,R===`minutes`&&u.timeInputHeaderSegmentActive,j?.headerSegment),style:M?.headerSegment,onClick:()=>z(`minutes`),children:De}),!w&&m(`div`,{className:f(u.timeInputMeridiem,j?.meridiem),style:M?.meridiem,children:[p(`button`,{type:`button`,className:f(q.hours<12&&u.timeInputMeridiemActive),onClick:()=>X(!1),children:`AM`}),p(`button`,{type:`button`,className:f(q.hours>=12&&u.timeInputMeridiemActive),onClick:()=>X(!0),children:`PM`})]})]}),ke=x||S?m(`div`,{className:f(u.timeInputFooter,j?.footer),style:M?.footer,children:[S&&p(t,{styleType:e.Default,onClick:()=>{let e=new Date;J({hours:e.getHours(),minutes:e.getMinutes()})},children:`Now`}),x&&p(t,{styleType:e.Default,onClick:()=>{G(null),_?.(null)},children:`Clear`})]}):null,Q=m(`div`,{className:f(u.timeInputClock,j?.clock),style:M?.clock,children:[Oe,p(ne,{time:q,mode:R,use24Hour:w,minuteStep:C,onChange:J,onCommit:Se,classNames:j,styles:M}),ke]}),$=le?null:p(a,{label:`${D}${xe()?` *`:``}`,value:P,icon:p(ae,{icon:oe}),onIconClick:Y,onClick:Y,readOnly:b,disabled:A,isValid:!Z,customInput:p(h,{mask:`99:99`,maskPlaceholder:`_`,beforeMaskedStateChange:Ce}),onChange:e=>we(e),onBlur:Te,onFocus:()=>B(!0),onMouseEnter:()=>V(!0),onMouseLeave:()=>V(!1)}),Ae=y?Q:b?p(ee,{hideHeader:!0,isOpen:I,onClose:()=>L(!1),children:Q}):p(r,{isOpen:I,onOpenChange:L,content:Q,align:n.Left,dontCloseOnChildClick:!0,children:$});return m(`div`,{className:f(u.timeInput,j?.root,fe),style:{...M?.root,...pe},...me,children:[(b||y)&&$,Ae,p(i,{variant:`error`,message:v?v.getCurrentErrorMessage()??``:O||``,isVisible:Z&&(he||ge)})]})}export{g as default};
|
|
2
|
+
//# sourceMappingURL=timeInput.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeInput.mjs","names":[],"sources":["../../../../package/common/timeInput/timeInput.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport InputMask, { type BeforeMaskedStateChangeStates, type InputState } from '@mona-health/react-input-mask';\nimport { faClock } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport Input from '../input';\nimport Modal from '../modal';\nimport FloatingMenu from '../floatingMenu';\nimport Button from '../button';\nimport { ButtonStyleType } from '../button/button.types';\nimport Tooltip from '../tooltip';\nimport ClockDial from './components/clockDial';\nimport { Align } from '../floatingMenu/floatingMenu.types';\nimport {\n type TimeValue,\n parseTimeString,\n formatTime,\n snapMinute,\n clampToRange,\n clampHour,\n} from './timeFunctions';\nimport type { TimeInputProps } from './timeInput.types';\n\nimport styles from './timeInput.module.pcss';\n\ntype ClockMode = 'hours' | 'minutes';\n\nexport default function TimeInput({\n value,\n selected,\n onChange = () => null,\n onSelect = () => null,\n formValidator = null,\n isInline = false,\n isModal = false,\n noInput = false,\n noHeader = false,\n showClearButton = false,\n showNowButton = false,\n minuteStep = 1,\n use24Hour = true,\n minTime = null,\n maxTime = null,\n label = '',\n isValid = true,\n errorMessage = '',\n isRequired = false,\n disabled = false,\n className = '',\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: TimeInputProps) {\n const getExternalString = (): string => {\n if (formValidator) return (formValidator.value as string) || '';\n return value ?? selected ?? '';\n };\n\n const [currentTimeString, setCurrentTimeString] = useState(getExternalString);\n const [isPickerOpen, setIsPickerOpen] = useState(false);\n const [mode, setMode] = useState<ClockMode>('hours');\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [, forceUpdate] = useState(0);\n\n const externalString = getExternalString();\n const [prevExternal, setPrevExternal] = useState(externalString);\n const fvRef = useRef(formValidator);\n\n // Sync when the controlled value changes externally.\n if (!formValidator && prevExternal !== externalString) {\n setPrevExternal(externalString);\n setCurrentTimeString(externalString);\n }\n\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => {\n setCurrentTimeString((formValidator.value as string) || '');\n forceUpdate((n) => n + 1);\n };\n formValidator.registerOnUpdateListener(listener);\n return () => formValidator.removeOnUpdateListener(listener);\n }, [formValidator]);\n\n const hasError = (): boolean =>\n formValidator ? formValidator.touched && formValidator.hasError() : !isValid || !!errorMessage;\n\n const computedIsRequired = (): boolean =>\n !!(isRequired || formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required'));\n\n /** Push a value out to formValidator/onChange without touching the input string. */\n const emit = (time: TimeValue | null) => {\n const str = time ? formatTime(time) : null;\n if (formValidator) formValidator.set(str);\n onChange?.(str);\n };\n\n const applyTime = (time: TimeValue | null) => {\n setCurrentTimeString(time ? formatTime(time) : '');\n emit(time);\n };\n\n const parsed = parseTimeString(currentTimeString);\n const dialTime: TimeValue = parsed ?? { hours: 12, minutes: 0 };\n\n const handleDialChange = (time: TimeValue) => {\n const snapped = { hours: time.hours, minutes: snapMinute(time.minutes, minuteStep) };\n applyTime(clampToRange(snapped, minTime, maxTime));\n };\n\n const handleDialCommit = (time: TimeValue) => {\n const snapped = { hours: time.hours, minutes: snapMinute(time.minutes, minuteStep) };\n const next = clampToRange(snapped, minTime, maxTime);\n applyTime(next);\n if (mode === 'hours') {\n setMode('minutes');\n return;\n }\n onSelect?.(formatTime(next));\n if (!isInline) setIsPickerOpen(false);\n };\n\n const openPicker = () => {\n if (disabled) return;\n setMode('hours');\n setIsPickerOpen(true);\n };\n\n const beforeMaskedStateChange = ({ previousState, nextState }: BeforeMaskedStateChangeStates): InputState => {\n if (!previousState || nextState.value === previousState.value) return nextState;\n let v = nextState.value;\n const hourStr = v.slice(0, 2);\n if (/^\\d\\d$/.test(hourStr) && Number(hourStr) > 23) v = `23${v.slice(2)}`;\n const minStr = v.slice(3, 5);\n if (/^\\d\\d$/.test(minStr) && Number(minStr) > 59) v = `${v.slice(0, 3)}59`;\n return v === nextState.value ? nextState : { ...nextState, value: v };\n };\n\n const handleInputChange = (v: string) => {\n setCurrentTimeString(v);\n const t = parseTimeString(v);\n if (t) emit(t);\n };\n\n const handleBlur = () => {\n if (fvRef.current) fvRef.current.touched = true;\n setIsFocused(false);\n emit(parseTimeString(currentTimeString));\n };\n\n const setMeridiem = (pm: boolean) => {\n const isPm = dialTime.hours >= 12;\n if (pm === isPm) return;\n applyTime({ hours: clampHour(dialTime.hours + (pm ? 12 : -12)), minutes: dialTime.minutes });\n };\n\n const hasErr = hasError();\n const displayHours = parsed ? String(use24Hour ? parsed.hours : ((parsed.hours + 11) % 12) + 1).padStart(2, '0') : '--';\n const displayMinutes = parsed ? String(parsed.minutes).padStart(2, '0') : '--';\n\n const header = noHeader ? null : (\n <div className={cx(styles.timeInputClockHeader, classNames?.clockHeader)} style={slotStyles?.clockHeader}>\n <button\n type=\"button\"\n className={cx(styles.timeInputHeaderSegment, mode === 'hours' && styles.timeInputHeaderSegmentActive, classNames?.headerSegment)}\n style={slotStyles?.headerSegment}\n onClick={() => setMode('hours')}\n >\n {displayHours}\n </button>\n <span className={styles.timeInputHeaderColon}>:</span>\n <button\n type=\"button\"\n className={cx(styles.timeInputHeaderSegment, mode === 'minutes' && styles.timeInputHeaderSegmentActive, classNames?.headerSegment)}\n style={slotStyles?.headerSegment}\n onClick={() => setMode('minutes')}\n >\n {displayMinutes}\n </button>\n {!use24Hour && (\n <div className={cx(styles.timeInputMeridiem, classNames?.meridiem)} style={slotStyles?.meridiem}>\n <button type=\"button\" className={cx(dialTime.hours < 12 && styles.timeInputMeridiemActive)} onClick={() => setMeridiem(false)}>AM</button>\n <button type=\"button\" className={cx(dialTime.hours >= 12 && styles.timeInputMeridiemActive)} onClick={() => setMeridiem(true)}>PM</button>\n </div>\n )}\n </div>\n );\n\n const footer =\n showClearButton || showNowButton ? (\n <div className={cx(styles.timeInputFooter, classNames?.footer)} style={slotStyles?.footer}>\n {showNowButton && (\n <Button\n styleType={ButtonStyleType.Default}\n onClick={() => {\n const now = new Date();\n handleDialChange({ hours: now.getHours(), minutes: now.getMinutes() });\n }}\n >\n Now\n </Button>\n )}\n {showClearButton && (\n <Button styleType={ButtonStyleType.Default} onClick={() => { applyTime(null); onSelect?.(null); }}>\n Clear\n </Button>\n )}\n </div>\n ) : null;\n\n const pickerContent = (\n <div className={cx(styles.timeInputClock, classNames?.clock)} style={slotStyles?.clock}>\n {header}\n <ClockDial\n time={dialTime}\n mode={mode}\n use24Hour={use24Hour}\n minuteStep={minuteStep}\n onChange={handleDialChange}\n onCommit={handleDialCommit}\n classNames={classNames}\n styles={slotStyles}\n />\n {footer}\n </div>\n );\n\n const input = noInput ? null : (\n <Input\n label={`${label}${computedIsRequired() ? ' *' : ''}`}\n value={currentTimeString}\n icon={<FontAwesomeIcon icon={faClock} />}\n onIconClick={openPicker}\n onClick={openPicker}\n readOnly={isModal}\n disabled={disabled}\n isValid={!hasErr}\n customInput={<InputMask mask=\"99:99\" maskPlaceholder=\"_\" beforeMaskedStateChange={beforeMaskedStateChange} />}\n onChange={(v) => handleInputChange(v as string)}\n onBlur={handleBlur}\n onFocus={() => setIsFocused(true)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n />\n );\n\n const picker = (() => {\n if (isInline) return pickerContent;\n if (isModal) {\n return (\n <Modal hideHeader isOpen={isPickerOpen} onClose={() => setIsPickerOpen(false)}>\n {pickerContent}\n </Modal>\n );\n }\n return (\n <FloatingMenu\n isOpen={isPickerOpen}\n onOpenChange={setIsPickerOpen}\n content={pickerContent}\n align={Align.Left}\n dontCloseOnChildClick\n >\n {input}\n </FloatingMenu>\n );\n })();\n\n return (\n <div className={cx(styles.timeInput, classNames?.root, className)} style={{ ...slotStyles?.root, ...style }} {...rest}>\n {(isModal || isInline) && input}\n {picker}\n <Tooltip\n variant=\"error\"\n message={formValidator ? formValidator.getCurrentErrorMessage() ?? '' : errorMessage || ''}\n isVisible={hasErr && (isFocused || isHovered)}\n />\n </div>\n );\n}\n"],"mappings":"o0BA2BA,SAAwB,EAAU,CAChC,QACA,YACA,gBAAiB,KACjB,eAAiB,KACjB,gBAAgB,KAChB,WAAW,GACX,UAAU,GACV,WAAU,GACV,YAAW,GACX,kBAAkB,GAClB,gBAAgB,GAChB,aAAa,EACb,YAAY,GACZ,UAAU,KACV,UAAU,KACV,QAAQ,GACR,WAAU,GACV,eAAe,GACf,aAAa,GACb,WAAW,GACX,aAAY,GACZ,SACA,aACA,OAAQ,EACR,GAAG,IACc,CACjB,IAAM,MACA,EAAuB,EAAc,OAAoB,GACtD,GAAS,IAAY,GAGxB,CAAC,EAAmB,GAAwB,EAAS,CAAiB,EACtE,CAAC,EAAc,GAAmB,EAAS,EAAK,EAChD,CAAC,EAAM,GAAW,EAAoB,OAAO,EAC7C,CAAC,GAAW,GAAgB,EAAS,EAAK,EAC1C,CAAC,GAAW,GAAgB,EAAS,EAAK,EAC1C,EAAG,IAAe,EAAS,CAAC,EAE5B,EAAiB,EAAkB,EACnC,CAAC,GAAc,IAAmB,EAAS,CAAc,EACzD,EAAQ,GAAO,CAAa,EAG9B,CAAC,GAAiB,KAAiB,IACrC,GAAgB,CAAc,EAC9B,EAAqB,CAAc,GAGrC,OAAgB,CAEd,GADA,EAAM,QAAU,EACZ,CAAC,EAAe,OACpB,IAAM,MAAiB,CACrB,EAAsB,EAAc,OAAoB,EAAE,EAC1D,GAAa,GAAM,EAAI,CAAC,CAC1B,EAEA,OADA,EAAc,yBAAyB,CAAQ,MAClC,EAAc,uBAAuB,CAAQ,CAC5D,EAAG,CAAC,CAAa,CAAC,EAElB,IAAM,OACJ,EAAgB,EAAc,SAAW,EAAc,SAAS,EAAI,CAAC,IAAW,CAAC,CAAC,EAE9E,OACJ,CAAC,EAAE,GAAc,GAAe,WAAW,KAAM,GAAO,EAA+B,cAAgB,UAAU,GAG7G,EAAQ,GAA2B,CACvC,IAAM,EAAM,EAAO,EAAW,CAAI,EAAI,KAClC,GAAe,EAAc,IAAI,CAAG,EACxC,KAAW,CAAG,CAChB,EAEM,EAAa,GAA2B,CAC5C,EAAqB,EAAO,EAAW,CAAI,EAAI,EAAE,EACjD,EAAK,CAAI,CACX,EAEM,EAAS,EAAgB,CAAiB,EAC1C,EAAsB,GAAU,CAAE,MAAO,GAAI,QAAS,CAAE,EAExD,EAAoB,GAAoB,CAE5C,EAAU,EAAa,CADL,MAAO,EAAK,MAAO,QAAS,EAAW,EAAK,QAAS,CAAU,CAC1D,EAAS,EAAS,CAAO,CAAC,CACnD,EAEM,GAAoB,GAAoB,CAE5C,IAAM,EAAO,EAAa,CADR,MAAO,EAAK,MAAO,QAAS,EAAW,EAAK,QAAS,CAAU,CACvD,EAAS,EAAS,CAAO,EAEnD,GADA,EAAU,CAAI,EACV,IAAS,QAAS,CACpB,EAAQ,SAAS,EACjB,MACF,CACA,IAAW,EAAW,CAAI,CAAC,EACtB,GAAU,EAAgB,EAAK,CACtC,EAEM,MAAmB,CACnB,IACJ,EAAQ,OAAO,EACf,EAAgB,EAAI,EACtB,EAEM,IAA2B,CAAE,gBAAe,eAA2D,CAC3G,GAAI,CAAC,GAAiB,EAAU,QAAU,EAAc,MAAO,OAAO,EACtE,IAAI,EAAI,EAAU,MACZ,EAAU,EAAE,MAAM,EAAG,CAAC,EACxB,SAAS,KAAK,CAAO,GAAK,OAAO,CAAO,EAAI,KAAI,EAAI,KAAK,EAAE,MAAM,CAAC,KACtE,IAAM,EAAS,EAAE,MAAM,EAAG,CAAC,EAE3B,MADI,SAAS,KAAK,CAAM,GAAK,OAAO,CAAM,EAAI,KAAI,EAAI,GAAG,EAAE,MAAM,EAAG,CAAC,EAAE,KAChE,IAAM,EAAU,MAAQ,EAAY,CAAE,GAAG,EAAW,MAAO,CAAE,CACtE,EAEM,GAAqB,GAAc,CACvC,EAAqB,CAAC,EACtB,IAAM,EAAI,EAAgB,CAAC,EACvB,GAAG,EAAK,CAAC,CACf,EAEM,OAAmB,CACnB,EAAM,UAAS,EAAM,QAAQ,QAAU,IAC3C,EAAa,EAAK,EAClB,EAAK,EAAgB,CAAiB,CAAC,CACzC,EAEM,EAAe,GAAgB,CAE/B,IADS,EAAS,OAAS,IAE/B,EAAU,CAAE,MAAO,GAAU,EAAS,OAAS,EAAK,GAAK,IAAI,EAAG,QAAS,EAAS,OAAQ,CAAC,CAC7F,EAEM,EAAS,GAAS,EAClB,GAAe,EAAS,OAAO,EAAY,EAAO,OAAU,EAAO,MAAQ,IAAM,GAAM,CAAC,EAAE,SAAS,EAAG,GAAG,EAAI,KAC7G,GAAiB,EAAS,OAAO,EAAO,OAAO,EAAE,SAAS,EAAG,GAAG,EAAI,KAEpE,GAAS,GAAW,KACxB,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,qBAAsB,GAAY,WAAW,EAAG,MAAO,GAAY,qBAA7F,CACE,EAAC,SAAD,CACE,KAAK,SACL,UAAW,EAAG,EAAO,uBAAwB,IAAS,SAAW,EAAO,6BAA8B,GAAY,aAAa,EAC/H,MAAO,GAAY,cACnB,YAAe,EAAQ,OAAO,WAE7B,EACK,CAAA,EACR,EAAC,OAAD,CAAM,UAAW,EAAO,8BAAsB,GAAO,CAAA,EACrD,EAAC,SAAD,CACE,KAAK,SACL,UAAW,EAAG,EAAO,uBAAwB,IAAS,WAAa,EAAO,6BAA8B,GAAY,aAAa,EACjI,MAAO,GAAY,cACnB,YAAe,EAAQ,SAAS,WAE/B,EACK,CAAA,EACP,CAAC,GACA,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,kBAAmB,GAAY,QAAQ,EAAG,MAAO,GAAY,kBAAvF,CACE,EAAC,SAAD,CAAQ,KAAK,SAAS,UAAW,EAAG,EAAS,MAAQ,IAAM,EAAO,uBAAuB,EAAG,YAAe,EAAY,EAAK,WAAG,IAAU,CAAA,EACzI,EAAC,SAAD,CAAQ,KAAK,SAAS,UAAW,EAAG,EAAS,OAAS,IAAM,EAAO,uBAAuB,EAAG,YAAe,EAAY,EAAI,WAAG,IAAU,CAAA,CACtI,GAEJ,IAGD,GACJ,GAAmB,EACjB,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,gBAAiB,GAAY,MAAM,EAAG,MAAO,GAAY,gBAAnF,CACG,GACC,EAAC,EAAD,CACE,UAAW,EAAgB,QAC3B,YAAe,CACb,IAAM,EAAM,IAAI,KAChB,EAAiB,CAAE,MAAO,EAAI,SAAS,EAAG,QAAS,EAAI,WAAW,CAAE,CAAC,CACvE,WACD,KAEO,CAAA,EAET,GACC,EAAC,EAAD,CAAQ,UAAW,EAAgB,QAAS,YAAe,CAAE,EAAU,IAAI,EAAG,IAAW,IAAI,CAAG,WAAG,OAE3F,CAAA,CAEP,IACH,KAEA,EACJ,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,eAAgB,GAAY,KAAK,EAAG,MAAO,GAAY,eAAjF,CACG,GACD,EAAC,GAAD,CACE,KAAM,EACA,OACK,YACC,aACZ,SAAU,EACV,SAAU,GACE,aACZ,OAAQ,CACT,CAAA,EACA,EACE,IAGD,EAAQ,GAAU,KACtB,EAAC,EAAD,CACE,MAAO,GAAG,IAAQ,GAAmB,EAAI,KAAO,KAChD,MAAO,EACP,KAAM,EAAC,GAAD,CAAiB,KAAM,EAAU,CAAA,EACvC,YAAa,EACb,QAAS,EACT,SAAU,EACA,WACV,QAAS,CAAC,EACV,YAAa,EAAC,EAAD,CAAW,KAAK,QAAQ,gBAAgB,IAA6B,0BAA0B,CAAA,EAC5G,SAAW,GAAM,GAAkB,CAAW,EAC9C,OAAQ,GACR,YAAe,EAAa,EAAI,EAChC,iBAAoB,EAAa,EAAI,EACrC,iBAAoB,EAAa,EAAK,CACvC,CAAA,EAGG,GACA,EAAiB,EACjB,EAEA,EAAC,GAAD,CAAO,WAAA,GAAW,OAAQ,EAAc,YAAe,EAAgB,EAAK,WACzE,CACI,CAAA,EAIT,EAAC,EAAD,CACE,OAAQ,EACR,aAAc,EACd,QAAS,EACT,MAAO,EAAM,KACb,sBAAA,YAEC,CACW,CAAA,EAIlB,OACE,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,UAAW,GAAY,KAAM,EAAS,EAAG,MAAO,CAAE,GAAG,GAAY,KAAM,GAAG,EAAM,EAAG,GAAI,YAAjH,EACI,GAAW,IAAa,EACzB,GACD,EAAC,EAAD,CACE,QAAQ,QACR,QAAS,EAAgB,EAAc,uBAAuB,GAAK,GAAK,GAAgB,GACxF,UAAW,IAAW,IAAa,GACpC,CAAA,CACE,GAET"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={timeInput:`timeInput_EbsZN`,"timeInput-clock":`timeInput-clock_D1-dk`,timeInputClock:`timeInput-clock_D1-dk`,"timeInput-clockHeader":`timeInput-clockHeader_bsYNW`,timeInputClockHeader:`timeInput-clockHeader_bsYNW`,"timeInput-headerSegment":`timeInput-headerSegment_Oiu7e`,timeInputHeaderSegment:`timeInput-headerSegment_Oiu7e`,"timeInput-headerSegment-active":`timeInput-headerSegment-active_-Funz`,timeInputHeaderSegmentActive:`timeInput-headerSegment-active_-Funz`,"timeInput-headerColon":`timeInput-headerColon_LwyQH`,timeInputHeaderColon:`timeInput-headerColon_LwyQH`,"timeInput-meridiem":`timeInput-meridiem_tk9km`,timeInputMeridiem:`timeInput-meridiem_tk9km`,"timeInput-meridiem-active":`timeInput-meridiem-active_40uHm`,timeInputMeridiemActive:`timeInput-meridiem-active_40uHm`,"timeInput-footer":`timeInput-footer_NCXsB`,timeInputFooter:`timeInput-footer_NCXsB`};export{e as default};
|
|
2
|
+
//# sourceMappingURL=timeInput.module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeInput.module.mjs","names":[],"sources":["../../../../package/common/timeInput/timeInput.module.pcss"],"sourcesContent":[".timeInput {\n position: relative;\n width: 100%;\n flex: 1;\n min-width: 105px;\n\n &-clock {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n min-width: 280px;\n }\n\n &-clockHeader {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n margin-bottom: 4px;\n }\n\n &-headerSegment {\n border: none;\n background: var(--background-accent);\n color: var(--text-dark);\n font-size: 32px;\n font-weight: 600;\n line-height: 1;\n padding: 6px 10px;\n border-radius: var(--default-border-radius);\n cursor: pointer;\n\n &-active {\n background: var(--primary-color);\n color: var(--text-on-primary);\n }\n }\n\n &-headerColon {\n font-size: 32px;\n font-weight: 600;\n color: var(--text-dark);\n }\n\n &-meridiem {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-left: 8px;\n\n & button {\n border: 1px solid var(--border-color);\n background: var(--background-accent);\n color: var(--text-dark);\n font-size: 12px;\n font-weight: 600;\n padding: 3px 8px;\n cursor: pointer;\n\n &:first-child { border-radius: var(--default-border-radius) var(--default-border-radius) 0 0; }\n &:last-child { border-radius: 0 0 var(--default-border-radius) var(--default-border-radius); }\n }\n\n &-active {\n background: var(--primary-color) !important;\n color: var(--text-on-primary) !important;\n }\n }\n\n &-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 4px;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"../actionIcon/actionIcon.mjs";import t from"./toast.module.mjs";import{useEffect as n,useRef as r,useState as i}from"react";import a from"classnames";import{FontAwesomeIcon as o}from"@fortawesome/react-fontawesome";import{faBell as s,faCircleCheck as c,faCircleInfo as l,faCircleXmark as u,faTriangleExclamation as d,faXmark as f}from"@fortawesome/free-solid-svg-icons";import{jsx as p,jsxs as m}from"react/jsx-runtime";var h={info:l,success:c,error:u,warn:d,default:s};function g({item:s,isBottom:c,onDismiss:l}){let{id:u,content:d,options:g,dismissing:_}=s,{duration:v,showRemainingTime:y,showCloseButton:b,pauseOnHover:x,type:S,classNames:C,styles:w}=g,[T,E]=i(!1),[D,O]=i(!1),k=x&&(T||D),A=r(v);return n(()=>{if(v===0||k)return;let e=Date.now(),t=setTimeout(()=>l(u),A.current);return()=>{clearTimeout(t),A.current-=Date.now()-e}},[u,v,l,k]),m(`div`,{className:a(t.toast,c?t.toastBottom:null,t[`toast-${S}`],_&&t.toastDismissing,k&&t.toastPaused,C?.root),style:w?.root,onMouseEnter:x?()=>E(!0):void 0,onMouseLeave:x?()=>E(!1):void 0,onFocus:x?()=>O(!0):void 0,onBlur:x?()=>O(!1):void 0,children:[p(o,{icon:h[S],className:a(t.toastIcon,C?.icon),style:w?.icon}),p(`div`,{className:a(t.toastContent,C?.content),style:w?.content,children:d}),b&&p(e,{icon:f,onClick:()=>l(u),className:a(t.toastCloseButton,C?.closeButton),style:w?.closeButton,"aria-label":`Close`}),y&&v>0&&p(`div`,{className:a(t.toastProgressBar,C?.progressBar),style:{"--toast-duration":`${v}ms`,...w?.progressBar}})]})}export{g as default};
|
|
2
|
+
//# sourceMappingURL=toast.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast.mjs","names":[],"sources":["../../../../package/common/toast/toast.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faCircleInfo,\n faCircleCheck,\n faCircleXmark,\n faTriangleExclamation,\n faBell,\n faXmark,\n} from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './toast.module.pcss';\nimport type { ToastItem } from './toast.types';\nimport ActionIcon from '../actionIcon';\n\ninterface ToastProps {\n item: ToastItem;\n isBottom: boolean;\n onDismiss: (id: string) => void;\n}\n\nconst typeIcons = {\n info: faCircleInfo,\n success: faCircleCheck,\n error: faCircleXmark,\n warn: faTriangleExclamation,\n default: faBell,\n};\n\nfunction Toast({ item, isBottom, onDismiss }: ToastProps) {\n const { id, content, options, dismissing } = item;\n const { duration, showRemainingTime, showCloseButton, pauseOnHover, type, classNames, styles: slotStyles } = options;\n\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n const paused = pauseOnHover && (hovered || focused);\n\n // Remaining time is carried across pause/resume cycles so the timer continues\n // where it left off instead of restarting on every hover.\n const remainingRef = useRef(duration);\n\n useEffect(() => {\n if (duration === 0 || paused) return;\n const start = Date.now();\n const timer = setTimeout(() => onDismiss(id), remainingRef.current);\n return () => {\n clearTimeout(timer);\n remainingRef.current -= Date.now() - start;\n };\n }, [id, duration, onDismiss, paused]);\n\n return (\n <div\n className={cx(\n styles.toast,\n isBottom ? styles.toastBottom : null,\n styles[`toast-${type}`],\n dismissing && styles.toastDismissing,\n paused && styles.toastPaused,\n classNames?.root,\n )}\n style={slotStyles?.root}\n onMouseEnter={pauseOnHover ? () => setHovered(true) : undefined}\n onMouseLeave={pauseOnHover ? () => setHovered(false) : undefined}\n onFocus={pauseOnHover ? () => setFocused(true) : undefined}\n onBlur={pauseOnHover ? () => setFocused(false) : undefined}\n >\n <FontAwesomeIcon\n icon={typeIcons[type]}\n className={cx(styles.toastIcon, classNames?.icon)}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n\n <div className={cx(styles.toastContent, classNames?.content)} style={slotStyles?.content}>\n {content}\n </div>\n\n {showCloseButton && (\n <ActionIcon\n icon={faXmark}\n onClick={() => onDismiss(id)}\n className={cx(styles.toastCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n aria-label=\"Close\"\n />\n )}\n\n {showRemainingTime && duration > 0 && (\n <div\n className={cx(styles.toastProgressBar, classNames?.progressBar)}\n style={{ '--toast-duration': `${duration}ms`, ...slotStyles?.progressBar } as React.CSSProperties}\n />\n )}\n </div>\n );\n}\n\nexport default Toast;\n"],"mappings":"kbAsBA,IAAM,EAAY,CAChB,KAAM,EACN,QAAS,EACT,MAAO,EACP,KAAM,EACN,QAAS,CACX,EAEA,SAAS,EAAM,CAAE,OAAM,WAAU,aAAyB,CACxD,GAAM,CAAE,KAAI,UAAS,UAAS,cAAe,EACvC,CAAE,WAAU,oBAAmB,kBAAiB,eAAc,OAAM,aAAY,OAAQ,GAAe,EAEvG,CAAC,EAAS,GAAc,EAAS,EAAK,EACtC,CAAC,EAAS,GAAc,EAAS,EAAK,EACtC,EAAS,IAAiB,GAAW,GAIrC,EAAe,EAAO,CAAQ,EAYpC,OAVA,MAAgB,CACd,GAAI,IAAa,GAAK,EAAQ,OAC9B,IAAM,EAAQ,KAAK,IAAI,EACjB,EAAQ,eAAiB,EAAU,CAAE,EAAG,EAAa,OAAO,EAClE,UAAa,CACX,aAAa,CAAK,EAClB,EAAa,SAAW,KAAK,IAAI,EAAI,CACvC,CACF,EAAG,CAAC,EAAI,EAAU,EAAW,CAAM,CAAC,EAGlC,EAAC,MAAD,CACE,UAAW,EACT,EAAO,MACP,EAAW,EAAO,YAAc,KAChC,EAAO,SAAS,KAChB,GAAc,EAAO,gBACrB,GAAU,EAAO,YACjB,GAAY,IACd,EACA,MAAO,GAAY,KACnB,aAAc,MAAqB,EAAW,EAAI,EAAI,IAAA,GACtD,aAAc,MAAqB,EAAW,EAAK,EAAI,IAAA,GACvD,QAAS,MAAqB,EAAW,EAAI,EAAI,IAAA,GACjD,OAAQ,MAAqB,EAAW,EAAK,EAAI,IAAA,YAbnD,CAeE,EAAC,EAAD,CACE,KAAM,EAAU,GAChB,UAAW,EAAG,EAAO,UAAW,GAAY,IAAI,EAChD,MAAO,GAAY,IACpB,CAAA,EAED,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,aAAc,GAAY,OAAO,EAAG,MAAO,GAAY,iBAC9E,CACE,CAAA,EAEJ,GACC,EAAC,EAAD,CACE,KAAM,EACN,YAAe,EAAU,CAAE,EAC3B,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,GAAY,YACnB,aAAW,OACZ,CAAA,EAGF,GAAqB,EAAW,GAC/B,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,CAAE,mBAAoB,GAAG,EAAS,IAAK,GAAG,GAAY,WAAY,CAC1E,CAAA,CAEA,GAET"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={container:`container_krdsW`,"container-top-left":`container-top-left_zfDTO`,containerTopLeft:`container-top-left_zfDTO`,"container-top-center":`container-top-center_CUIGc`,containerTopCenter:`container-top-center_CUIGc`,"container-top-right":`container-top-right_sB0KU`,containerTopRight:`container-top-right_sB0KU`,"container-bottom-left":`container-bottom-left_toJdF`,containerBottomLeft:`container-bottom-left_toJdF`,"container-bottom-center":`container-bottom-center_Bkf9m`,containerBottomCenter:`container-bottom-center_Bkf9m`,"container-bottom-right":`container-bottom-right_oRSMc`,containerBottomRight:`container-bottom-right_oRSMc`,toast:`toast_qBi4o`,toastSlideDown:`toastSlideDown_4lKWq`,"toast-bottom":`toast-bottom_X8ZIe`,toastBottom:`toast-bottom_X8ZIe`,toastSlideUp:`toastSlideUp_SGR5X`,"toast-dismissing":`toast-dismissing_xKmB-`,toastDismissing:`toast-dismissing_xKmB-`,toastFadeOut:`toastFadeOut_cvHYp`,"toast-paused":`toast-paused_NPmT4`,toastPaused:`toast-paused_NPmT4`,toastProgressBar:`toastProgressBar_6vBs6`,"toast-info":`toast-info_RlLli`,toastInfo:`toast-info_RlLli`,toastIcon:`toastIcon_xU1nA`,"toast-success":`toast-success_I1g1B`,toastSuccess:`toast-success_I1g1B`,"toast-error":`toast-error_MloFO`,toastError:`toast-error_MloFO`,"toast-warn":`toast-warn_pP6HB`,toastWarn:`toast-warn_pP6HB`,"toast-default":`toast-default_RTt2L`,toastDefault:`toast-default_RTt2L`,toastContent:`toastContent_gvyIv`,toastCloseButton:`toastCloseButton_n-YST`,toastShrink:`toastShrink_h89HS`};export{e as default};
|
|
2
|
+
//# sourceMappingURL=toast.module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast.module.mjs","names":[],"sources":["../../../../package/common/toast/toast.module.pcss"],"sourcesContent":[".container {\n position: fixed;\n z-index: 9999;\n display: flex;\n flex-direction: column;\n gap: 8px;\n pointer-events: none;\n padding: 16px;\n box-sizing: border-box;\n\n &-top-left {\n top: 0;\n left: 0;\n align-items: flex-start;\n }\n\n &-top-center {\n top: 0;\n left: 50%;\n transform: translateX(-50%);\n align-items: center;\n }\n\n &-top-right {\n top: 0;\n right: 0;\n align-items: flex-end;\n }\n\n &-bottom-left {\n bottom: 0;\n left: 0;\n align-items: flex-start;\n flex-direction: column-reverse;\n }\n\n &-bottom-center {\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n align-items: center;\n flex-direction: column-reverse;\n }\n\n &-bottom-right {\n bottom: 0;\n right: 0;\n align-items: flex-end;\n flex-direction: column-reverse;\n }\n}\n\n.toast {\n pointer-events: all;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 12px 14px;\n border-radius: var(--default-border-radius);\n background: var(--background-modal);\n color: var(--text-color);\n font-family: var(--default-font);\n box-shadow: var(--card-shadow);\n min-width: 240px;\n max-width: 380px;\n box-sizing: border-box;\n position: relative;\n overflow: hidden;\n animation: toastSlideDown 0.25s ease forwards;\n\n &-bottom {\n animation: toastSlideUp 0.25s ease forwards;\n }\n\n &-dismissing {\n animation: toastFadeOut 0.2s ease forwards;\n }\n\n &-paused .toastProgressBar {\n animation-play-state: paused;\n }\n\n &-info {\n border-left: 3px solid var(--info-color, #3b82f6);\n\n .toastIcon {\n color: var(--info-color, #3b82f6);\n }\n }\n\n &-success {\n border-left: 3px solid var(--success-color);\n\n .toastIcon {\n color: var(--success-color);\n }\n }\n\n &-error {\n border-left: 3px solid var(--error-color, #ef4444);\n\n .toastIcon {\n color: var(--error-color, #ef4444);\n }\n }\n\n &-warn {\n border-left: 3px solid var(--warn-color);\n\n .toastIcon {\n color: var(--warn-color);\n }\n }\n\n &-default {\n border-left: 3px solid var(--primary-color);\n\n .toastIcon {\n color: var(--primary-color);\n }\n }\n}\n\n.toastIcon {\n flex-shrink: 0;\n margin-top: 1px;\n font-size: 15px;\n}\n\n.toastContent {\n flex: 1;\n font-size: 14px;\n line-height: 1.4;\n}\n\n.toastCloseButton {\n flex-shrink: 0;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--text-dark);\n font-size: 13px;\n opacity: 0.6;\n transition: opacity 0.15s;\n margin-top: 1px;\n\n &:hover {\n opacity: 1;\n }\n}\n\n.toastProgressBar {\n position: absolute;\n bottom: 0;\n left: 0;\n height: 3px;\n width: 100%;\n background: currentColor;\n opacity: 0.35;\n transform-origin: left;\n animation: toastShrink var(--toast-duration) linear forwards;\n}\n\n@keyframes toastSlideDown {\n from {\n opacity: 0;\n transform: translateY(-12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes toastSlideUp {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes toastFadeOut {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.92);\n }\n}\n\n@keyframes toastShrink {\n from {\n transform: scaleX(1);\n }\n to {\n transform: scaleX(0);\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"../bodyEnd/bodyEnd.mjs";import t from"./toast.module.mjs";import n from"./toast.mjs";import{_registerToastHandler as r,_unregisterToastHandler as i}from"./toastService.mjs";import{useCallback as a,useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{Fragment as u,jsx as d,jsxs as f}from"react/jsx-runtime";var p={position:`top-right`,duration:4e3,showRemainingTime:!0,showCloseButton:!0,allowStacking:!0,pauseOnHover:!0},m=220;function h(e){return t[`container-${e}`]}function g({children:g,position:_=p.position,duration:v=p.duration,showRemainingTime:y=p.showRemainingTime,showCloseButton:b=p.showCloseButton,allowStacking:x=p.allowStacking,pauseOnHover:S=p.pauseOnHover}){let[C,w]=c([]),T=s(0),E=a(e=>{w(t=>t.map(t=>t.id===e?{...t,dismissing:!0}:t)),setTimeout(()=>{w(t=>t.filter(t=>t.id!==e))},m)},[]),D=a((e,t)=>{let n={position:t?.position??_,duration:t?.duration??v,showRemainingTime:t?.showRemainingTime??y,showCloseButton:t?.showCloseButton??b,pauseOnHover:t?.pauseOnHover??S,type:t?.type??`default`,classNames:t?.classNames,styles:t?.styles};T.current+=1;let r={id:`toast-${T.current}`,content:e,options:n,dismissing:!1};w(e=>!x&&e.length>0?(setTimeout(()=>{w([r])},m),e.map(e=>({...e,dismissing:!0}))):[...e,r])},[_,v,y,b,x,S]);o(()=>(r(D),()=>i()),[D]);let O=C.reduce((e,t)=>{let n=t.options.position;return e[n]||(e[n]=[]),e[n].push(t),e},{});return f(u,{children:[g,d(e,{children:Object.entries(O).map(([e,r])=>d(`div`,{className:l(t.container,h(e)),children:r.map(t=>d(n,{item:t,isBottom:e.startsWith(`bottom`),onDismiss:E},t.id))},e))})]})}export{g as default};
|
|
2
|
+
//# sourceMappingURL=toastProvider.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toastProvider.mjs","names":[],"sources":["../../../../package/common/toast/toastProvider.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './toast.module.pcss';\nimport Toast from './toast';\nimport { _registerToastHandler, _unregisterToastHandler } from './toastService';\nimport type { ToastContextConfig, ToastItem, ToastOptions, ResolvedToastOptions, ToastPosition } from './toast.types';\nimport type { ReactNode } from 'react';\n\nconst DEFAULTS: Required<ToastContextConfig> = {\n position: 'top-right',\n duration: 4000,\n showRemainingTime: true,\n showCloseButton: true,\n allowStacking: true,\n pauseOnHover: true,\n};\n\nconst DISMISS_ANIMATION_MS = 220;\n\nfunction positionToClass(position: ToastPosition): string {\n return styles[`container-${position}`];\n}\n\ninterface ToastProviderProps extends ToastContextConfig {\n children: ReactNode;\n}\n\nfunction ToastProvider({\n children,\n position = DEFAULTS.position,\n duration = DEFAULTS.duration,\n showRemainingTime = DEFAULTS.showRemainingTime,\n showCloseButton = DEFAULTS.showCloseButton,\n allowStacking = DEFAULTS.allowStacking,\n pauseOnHover = DEFAULTS.pauseOnHover,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastItem[]>([]);\n const counterRef = useRef(0);\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) =>\n prev.map((t) => (t.id === id ? { ...t, dismissing: true } : t)),\n );\n setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, DISMISS_ANIMATION_MS);\n }, []);\n\n const addToast = useCallback(\n (content: ReactNode, options?: ToastOptions) => {\n const resolved: ResolvedToastOptions = {\n position: options?.position ?? position,\n duration: options?.duration ?? duration,\n showRemainingTime: options?.showRemainingTime ?? showRemainingTime,\n showCloseButton: options?.showCloseButton ?? showCloseButton,\n pauseOnHover: options?.pauseOnHover ?? pauseOnHover,\n type: options?.type ?? 'default',\n classNames: options?.classNames,\n styles: options?.styles,\n };\n\n counterRef.current += 1;\n const id = `toast-${counterRef.current}`;\n const newToast: ToastItem = { id, content, options: resolved, dismissing: false };\n\n setToasts((prev) => {\n if (!allowStacking && prev.length > 0) {\n // Mark all existing as dismissing, then replace\n setTimeout(() => {\n setToasts([newToast]);\n }, DISMISS_ANIMATION_MS);\n return prev.map((t) => ({ ...t, dismissing: true }));\n }\n return [...prev, newToast];\n });\n },\n [position, duration, showRemainingTime, showCloseButton, allowStacking, pauseOnHover],\n );\n\n useEffect(() => {\n _registerToastHandler(addToast);\n return () => _unregisterToastHandler();\n }, [addToast]);\n\n // Group toasts by position so per-toast position overrides work correctly\n const byPosition = toasts.reduce<Record<string, ToastItem[]>>((acc, t) => {\n const pos = t.options.position;\n if (!acc[pos]) acc[pos] = [];\n acc[pos].push(t);\n return acc;\n }, {});\n\n return (\n <>\n {children}\n <BodyEnd>\n {Object.entries(byPosition).map(([pos, items]) => (\n <div\n key={pos}\n className={cx(styles.container, positionToClass(pos as typeof position))}\n >\n {items.map((item) => (\n <Toast\n key={item.id}\n item={item}\n isBottom={pos.startsWith('bottom')}\n onDismiss={dismiss}\n />\n ))}\n </div>\n ))}\n </BodyEnd>\n </>\n );\n}\n\nexport default ToastProvider;\nexport type { ToastProviderProps };\n"],"mappings":"kWAUA,IAAM,EAAyC,CAC7C,SAAU,YACV,SAAU,IACV,kBAAmB,GACnB,gBAAiB,GACjB,cAAe,GACf,aAAc,EAChB,EAEM,EAAuB,IAE7B,SAAS,EAAgB,EAAiC,CACxD,OAAO,EAAO,aAAa,IAC7B,CAMA,SAAS,EAAc,CACrB,WACA,WAAW,EAAS,SACpB,WAAW,EAAS,SACpB,oBAAoB,EAAS,kBAC7B,kBAAkB,EAAS,gBAC3B,gBAAgB,EAAS,cACzB,eAAe,EAAS,cACH,CACrB,GAAM,CAAC,EAAQ,GAAa,EAAsB,CAAC,CAAC,EAC9C,EAAa,EAAO,CAAC,EAErB,EAAU,EAAa,GAAe,CAC1C,EAAW,GACT,EAAK,IAAK,GAAO,EAAE,KAAO,EAAK,CAAE,GAAG,EAAG,WAAY,EAAK,EAAI,CAAE,CAChE,EACA,eAAiB,CACf,EAAW,GAAS,EAAK,OAAQ,GAAM,EAAE,KAAO,CAAE,CAAC,CACrD,EAAG,CAAoB,CACzB,EAAG,CAAC,CAAC,EAEC,EAAW,GACd,EAAoB,IAA2B,CAC9C,IAAM,EAAiC,CACrC,SAAU,GAAS,UAAY,EAC/B,SAAU,GAAS,UAAY,EAC/B,kBAAmB,GAAS,mBAAqB,EACjD,gBAAiB,GAAS,iBAAmB,EAC7C,aAAc,GAAS,cAAgB,EACvC,KAAM,GAAS,MAAQ,UACvB,WAAY,GAAS,WACrB,OAAQ,GAAS,MACnB,EAEA,EAAW,SAAW,EAEtB,IAAM,EAAsB,CAAE,GAAA,SADV,EAAW,UACG,UAAS,QAAS,EAAU,WAAY,EAAM,EAEhF,EAAW,GACL,CAAC,GAAiB,EAAK,OAAS,GAElC,eAAiB,CACf,EAAU,CAAC,CAAQ,CAAC,CACtB,EAAG,CAAoB,EAChB,EAAK,IAAK,IAAO,CAAE,GAAG,EAAG,WAAY,EAAK,EAAE,GAE9C,CAAC,GAAG,EAAM,CAAQ,CAC1B,CACH,EACA,CAAC,EAAU,EAAU,EAAmB,EAAiB,EAAe,CAAY,CACtF,EAEA,OACE,EAAsB,CAAQ,MACjB,EAAwB,GACpC,CAAC,CAAQ,CAAC,EAGb,IAAM,EAAa,EAAO,QAAqC,EAAK,IAAM,CACxE,IAAM,EAAM,EAAE,QAAQ,SAGtB,OAFK,EAAI,KAAM,EAAI,GAAO,CAAC,GAC3B,EAAI,GAAK,KAAK,CAAC,EACR,CACT,EAAG,CAAC,CAAC,EAEL,OACE,EAAA,EAAA,CAAA,SAAA,CACG,EACD,EAAC,EAAD,CAAA,SACG,OAAO,QAAQ,CAAU,EAAE,KAAK,CAAC,EAAK,KACrC,EAAC,MAAD,CAEE,UAAW,EAAG,EAAO,UAAW,EAAgB,CAAsB,CAAC,WAEtE,EAAM,IAAK,GACV,EAAC,EAAD,CAEQ,OACN,SAAU,EAAI,WAAW,QAAQ,EACjC,UAAW,CACZ,EAJM,EAAK,EAIX,CACF,CACE,EAXE,CAWF,CACN,CACM,CAAA,CACT,CAAA,CAAA,CAEN"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=null;function t(t){e=t}function n(){e=null}function r(t,n){if(!e){console.error(`[Toast] No ToastProvider found. Wrap your app with <ToastProvider>.`);return}e(t,n)}export{t as _registerToastHandler,n as _unregisterToastHandler,r as showToast};
|
|
2
|
+
//# sourceMappingURL=toastService.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toastService.mjs","names":[],"sources":["../../../../package/common/toast/toastService.ts"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { ToastOptions } from './toast.types';\n\ntype ShowToastFn = (content: ReactNode, options?: ToastOptions) => void;\n\nlet _handler: ShowToastFn | null = null;\n\nexport function _registerToastHandler(fn: ShowToastFn): void {\n _handler = fn;\n}\n\nexport function _unregisterToastHandler(): void {\n _handler = null;\n}\n\nexport function showToast(content: ReactNode, options?: ToastOptions): void {\n if (!_handler) {\n console.error('[Toast] No ToastProvider found. Wrap your app with <ToastProvider>.');\n return;\n }\n _handler(content, options);\n}\n"],"mappings":"AAKA,IAAI,EAA+B,KAEnC,SAAgB,EAAsB,EAAuB,CAC3D,EAAW,CACb,CAEA,SAAgB,GAAgC,CAC9C,EAAW,IACb,CAEA,SAAgB,EAAU,EAAoB,EAA8B,CAC1E,GAAI,CAAC,EAAU,CACb,QAAQ,MAAM,qEAAqE,EACnF,MACF,CACA,EAAS,EAAS,CAAO,CAC3B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"../bodyEnd/bodyEnd.mjs";import{useFloatingPosition as t}from"../floatingMenu/useFloatingPosition.mjs";import n from"./tooltip.module.mjs";import{useLayoutEffect as r,useRef as i,useState as a}from"react";import o from"classnames";import{Fragment as s,jsx as c,jsxs as l}from"react/jsx-runtime";function u({variant:u,message:d=``,isVisible:f=!0,tooltipPosition:p,onClick:m}){let[h,g]=a(!1),_=i(null),v=i(null),y=i(null),b=i(null),x=i(null),[S,C]=a(10),w=u===`details`?h:f;r(()=>{y.current=u===`details`?v.current:_.current?.parentElement??null}),r(()=>{if(w){let e=y.current?.getBoundingClientRect();C(e?.width??10)}},[w]),t({isOpen:w,triggerRef:y,anchorRef:b,panelRef:x,flipClassName:n.tooltipAnchorFlip,placement:`top`});let T=w&&c(e,{children:c(`div`,{ref:b,className:n.tooltipAnchor,style:{width:`${S}px`,"--tooltip-trigger-width":`${S}px`},children:c(`div`,{ref:x,className:o(u===`error`?n.tooltipError:n.tooltipBubble,p),onClick:m,children:d})})});return u===`details`?l(`div`,{ref:v,className:n.tooltipDetails,children:[c(`span`,{className:n.tooltipDetailsIcon,onMouseEnter:()=>g(!0),onMouseLeave:()=>g(!1),children:`?`}),T]}):u===`info`||u===`error`?l(s,{children:[c(`span`,{ref:_,style:{display:`none`}}),T]}):null}export{u as default};
|
|
2
|
+
//# sourceMappingURL=tooltip.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip.mjs","names":[],"sources":["../../../../package/common/tooltip/tooltip.tsx"],"sourcesContent":["import React, { useLayoutEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\nimport { useFloatingPosition } from '../floatingMenu/useFloatingPosition';\nimport styles from './tooltip.module.pcss';\nimport type { TooltipProps } from './tooltip.types';\n\nexport default function Tooltip({\n variant,\n message = '',\n isVisible = true,\n tooltipPosition,\n onClick,\n}: TooltipProps) {\n const [detailsHovered, setDetailsHovered] = useState(false);\n\n const sentinelRef = useRef<HTMLSpanElement>(null);\n const detailsRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n const shown = variant === 'details' ? detailsHovered : isVisible;\n\n useLayoutEffect(() => {\n triggerRef.current = variant === 'details' ? detailsRef.current : (sentinelRef.current?.parentElement ?? null);\n });\n\n useLayoutEffect(() => {\n if (shown) {\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n }\n }, [shown]);\n\n useFloatingPosition({\n isOpen: shown,\n triggerRef,\n anchorRef,\n panelRef,\n flipClassName: styles.tooltipAnchorFlip,\n placement: 'top',\n });\n\n const bubble = shown && (\n <BodyEnd>\n <div\n ref={anchorRef}\n className={styles.tooltipAnchor}\n style={{ width: `${triggerWidth}px`, '--tooltip-trigger-width': `${triggerWidth}px` } as React.CSSProperties}\n >\n <div\n ref={panelRef}\n className={cx(variant === 'error' ? styles.tooltipError : styles.tooltipBubble, tooltipPosition)}\n onClick={onClick}\n >\n {message}\n </div>\n </div>\n </BodyEnd>\n );\n\n if (variant === 'details') {\n return (\n <div ref={detailsRef} className={styles.tooltipDetails}>\n <span\n className={styles.tooltipDetailsIcon}\n onMouseEnter={() => setDetailsHovered(true)}\n onMouseLeave={() => setDetailsHovered(false)}\n >\n ?\n </span>\n {bubble}\n </div>\n );\n }\n\n if (variant === 'info' || variant === 'error') {\n return (\n <>\n <span ref={sentinelRef} style={{ display: 'none' }} />\n {bubble}\n </>\n );\n }\n\n return null;\n}\n"],"mappings":"oTAOA,SAAwB,EAAQ,CAC9B,UACA,UAAU,GACV,YAAY,GACZ,kBACA,WACe,CACf,GAAM,CAAC,EAAgB,GAAqB,EAAS,EAAK,EAEpD,EAAc,EAAwB,IAAI,EAC1C,EAAa,EAAuB,IAAI,EACxC,EAAa,EAA2B,IAAI,EAC5C,EAAY,EAAuB,IAAI,EACvC,EAAW,EAAuB,IAAI,EACtC,CAAC,EAAc,GAAmB,EAAS,EAAE,EAE7C,EAAQ,IAAY,UAAY,EAAiB,EAEvD,MAAsB,CACpB,EAAW,QAAU,IAAY,UAAY,EAAW,QAAW,EAAY,SAAS,eAAiB,IAC3G,CAAC,EAED,MAAsB,CACpB,GAAI,EAAO,CACT,IAAM,EAAO,EAAW,SAAS,sBAAsB,EACvD,EAAgB,GAAM,OAAS,EAAE,CACnC,CACF,EAAG,CAAC,CAAK,CAAC,EAEV,EAAoB,CAClB,OAAQ,EACR,aACA,YACA,WACA,cAAe,EAAO,kBACtB,UAAW,KACb,CAAC,EAED,IAAM,EAAS,GACb,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EAAO,cAClB,MAAO,CAAE,MAAO,GAAG,EAAa,IAAK,0BAA2B,GAAG,EAAa,GAAI,WAEpF,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EAAG,IAAY,QAAU,EAAO,aAAe,EAAO,cAAe,CAAe,EACtF,mBAER,CACE,CAAA,CACF,CAAA,CACE,CAAA,EA2BX,OAxBI,IAAY,UAEZ,EAAC,MAAD,CAAK,IAAK,EAAY,UAAW,EAAO,wBAAxC,CACE,EAAC,OAAD,CACE,UAAW,EAAO,mBAClB,iBAAoB,EAAkB,EAAI,EAC1C,iBAAoB,EAAkB,EAAK,WAC5C,GAEK,CAAA,EACL,CACE,IAIL,IAAY,QAAU,IAAY,QAElC,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,OAAD,CAAM,IAAK,EAAa,MAAO,CAAE,QAAS,MAAO,CAAI,CAAA,EACpD,CACD,CAAA,CAAA,EAIC,IACT"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={tooltipAnchor:`tooltipAnchor_Ew7Xk`,tooltipBubble:`tooltipBubble_uyev0`,"tooltip-anchor-flip":`tooltip-anchor-flip_qlJyz`,tooltipAnchorFlip:`tooltip-anchor-flip_qlJyz`,tooltipDetails:`tooltipDetails_R7N16`,"tooltipDetails-icon":`tooltipDetails-icon_rsjns`,tooltipDetailsIcon:`tooltipDetails-icon_rsjns`,tooltipError:`tooltipError_gUBut`};export{e as default};
|
|
2
|
+
//# sourceMappingURL=tooltip.module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip.module.mjs","names":[],"sources":["../../../../package/common/tooltip/tooltip.module.pcss"],"sourcesContent":["\n.tooltipAnchor {\n position: fixed;\n z-index: 10;\n}\n\n.tooltipBubble {\n position: absolute;\n bottom: 0;\n margin-bottom: 6px;\n left: 0;\n border-radius: 3px;\n width: max-content;\n max-width: 200px;\n font-size: 12px;\n background-color: #454953;\n padding: 6px 9px;\n color: white;\n pointer-events: none;\n\n .tooltip-anchor-flip & {\n bottom: auto;\n top: 0;\n margin-bottom: 0;\n margin-top: 6px;\n }\n\n &:after {\n content: '';\n position: absolute;\n top: 100%;\n left: calc(var(--tooltip-trigger-width, 10px) / 2 - 5px);\n border-width: 5px;\n border-style: solid;\n border-color: #454953 transparent transparent transparent;\n }\n\n .tooltip-anchor-flip &:after {\n top: auto;\n bottom: 100%;\n border-color: transparent transparent #454953 transparent;\n }\n}\n\n.tooltipDetails {\n position: relative;\n display: inline-flex;\n align-items: center;\n\n &-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n font-size: 11px;\n font-weight: 700;\n background-color: #454953;\n color: white;\n cursor: default;\n user-select: none;\n }\n}\n\n.tooltipError {\n position: absolute;\n bottom: 0;\n margin-bottom: 6px;\n right: 0;\n width: max-content;\n border-radius: 3px;\n background-color: var(--error-lighter);\n color: var(--red);\n font-size: 10px;\n padding: 6px 9px;\n\n .tooltip-anchor-flip & {\n bottom: auto;\n top: 0;\n margin-bottom: 0;\n margin-top: 6px;\n }\n\n &:after {\n content: '';\n position: absolute;\n top: 100%;\n right: 12px;\n border-width: 5px;\n border-style: solid;\n border-color: var(--error-border-color) transparent transparent transparent;\n }\n\n .tooltip-anchor-flip &:after {\n top: auto;\n bottom: 100%;\n border-color: transparent transparent var(--error-border-color) transparent;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{COLUMN_STORAGE_PREFIX as e,buildColumnTemplate as t,isColumnInitiallyVisible as n,loadPersistedColumns as r}from"./virtualList.utils.mjs";import{useCallback as i,useEffect as a,useLayoutEffect as o,useRef as s,useState as c}from"react";function l({columns:l,items:u,multiSelect:d,visibleColumnKeys:f,onVisibleColumnsChange:p,persistColumnsKey:m,showColumnToggle:h,rootRef:g,startIndex:_,endIndex:v,containerHeight:y,containerWidth:b}){let x=f!==void 0,[S,C]=c(!1),w=s(null),[T,E]=c({}),[D,O]=c(()=>{let e=r(m);return new Set((l??[]).filter(t=>n(t,e)).map(e=>e.key))}),k=s(new Set((l??[]).map(e=>e.key)));a(()=>{if(x)return;let e=l??[],t=new Set(e.map(e=>e.key)),i=k.current,a=t.size===i.size;if(a){for(let e of t)if(!i.has(e)){a=!1;break}}if(a)return;k.current=t;let o=r(m);O(t=>{let r=new Set;for(let a of e)i.has(a.key)?t.has(a.key)&&r.add(a.key):n(a,o)&&r.add(a.key);return r})},[l,x,m]),a(()=>{if(x||!m||typeof window>`u`)return;let t=l??[];if(!(t.length===0||D.size===0))try{window.localStorage.setItem(e+m,JSON.stringify({visible:[...D],known:t.map(e=>e.key)}))}catch{}},[D,l,x,m]);let A=x?new Set(f):D;a(()=>{if(!S)return;function e(e){w.current&&!w.current.contains(e.target)&&C(!1)}return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[S]);let j=!!l?.length,M=j?l.filter(e=>A.has(e.key)):[],N=j?l.filter(e=>!e.defaultHidden&&!A.has(e.key)).length:0,P=j?`${d&&j?`40px `:``}${t(M,T)}`:void 0,F=h!==!1&&j,I=M.filter(e=>e.width.type===`fit`),L=I.length>0,R=I.map(e=>e.key).join(`|`),[z,B]=c({key:R,items:u});(z.key!==R||z.items!==u)&&(B({key:R,items:u}),Object.keys(T).length>0&&E({}));let V=i(()=>{let e=g.current;if(!e)return;let t=new Map;e.querySelectorAll(`[data-fit-key]`).forEach(e=>{let n=e,r=n.getAttribute(`data-fit-key`);if(!r)return;let i=n.scrollWidth>n.clientWidth,a=n.scrollWidth;if(i||n.firstElementChild){let e=getComputedStyle(n),t=parseFloat(e.paddingLeft)||0,r=parseFloat(e.paddingRight)||0;if(i&&(a+=r),n.firstElementChild&&!i&&n.scrollWidth<=t+r+1){let e=1/0,i=-1/0;if(n.querySelectorAll(`*`).forEach(t=>{let n=t.getBoundingClientRect();n.left<e&&(e=n.left),n.right>i&&(i=n.right)}),i>e){let n=Math.ceil(i-e)+t+r;n>a&&(a=n)}}}a>(t.get(r)??0)&&t.set(r,a)}),t.size!==0&&E(n=>{let r=!1,i={...n};for(let[a,o]of t){if(o<=0)continue;let t=Math.min(Math.ceil(o),e.clientWidth);t>(n[a]??0)&&(i[a]=t,r=!0)}return r?i:n})},[g]),[H]=c(()=>typeof ResizeObserver>`u`?null:new ResizeObserver(()=>V())),U=s(new Set);a(()=>()=>{H?.disconnect(),U.current.clear()},[H]),o(()=>{if(!L)return;let e=g.current;if(!e||(V(),!H))return;let t=new Set(e.querySelectorAll(`[data-fit-key]`)),n=U.current;for(let e of n)t.has(e)||(H.unobserve(e),n.delete(e));for(let e of t)n.has(e)||(H.observe(e),n.add(e))},[L,R,T,_,v,y,b,u,V,H]),a(()=>{if(!L)return;let e=0,t=requestAnimationFrame(()=>{V(),e=requestAnimationFrame(()=>V())});return()=>{cancelAnimationFrame(t),cancelAnimationFrame(e)}},[L,R,u,V]);let W=i(()=>E({}),[]);function G(e){let t=new Set(A);if(t.has(e)){if(t.size<=1)return;t.delete(e)}else t.add(e);let n=[...t];x||O(t),p?.(n)}return{hasColumns:j,visibleColumns:M,columnTemplate:P,shouldShowToggle:F,effectiveVisible:A,manuallyHiddenCount:N,toggleOpen:S,setToggleOpen:C,toggleRef:w,handleToggleColumn:G,recalculateColumns:W}}export{l as useColumns};
|
|
2
|
+
//# sourceMappingURL=useColumns.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useColumns.mjs","names":[],"sources":["../../../../package/common/virtualList/useColumns.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';\n\nimport {\n buildColumnTemplate,\n loadPersistedColumns,\n isColumnInitiallyVisible,\n COLUMN_STORAGE_PREFIX,\n type PersistedColumns,\n} from './virtualList.utils';\nimport type { VirtualListColumn } from './virtualList.types';\n\ninterface UseColumnsArgs<T> {\n columns?: VirtualListColumn<T>[];\n items: T[];\n multiSelect: boolean;\n visibleColumnKeys?: string[];\n onVisibleColumnsChange?: (keys: string[]) => void;\n persistColumnsKey?: string;\n showColumnToggle?: boolean;\n rootRef: React.RefObject<HTMLDivElement | null>;\n /** Visible-window bounds — re-measure `fit` columns as new cells scroll in. */\n startIndex: number;\n endIndex: number;\n containerHeight: number;\n /** Re-measure `fit` columns when the container width settles (e.g. after a route transition). */\n containerWidth: number;\n}\n\ninterface UseColumnsResult<T> {\n hasColumns: boolean;\n visibleColumns: VirtualListColumn<T>[];\n columnTemplate: string | undefined;\n shouldShowToggle: boolean;\n effectiveVisible: Set<string>;\n /** How many default-visible columns the user has hidden (excludes defaultHidden). */\n manuallyHiddenCount: number;\n toggleOpen: boolean;\n setToggleOpen: React.Dispatch<React.SetStateAction<boolean>>;\n toggleRef: React.RefObject<HTMLDivElement | null>;\n handleToggleColumn: (key: string) => void;\n /** Imperative escape hatch: drop fit-column pins so they re-measure on the\n * next layout. For out-of-band content changes that don't flow through a new\n * `items` array or `columns` set (which reset automatically). */\n recalculateColumns: () => void;\n}\n\n/**\n * Table-mode column logic: visibility (controlled or uncontrolled, with\n * localStorage persistence and runtime reconciliation), the toggle popover, and\n * `fit`-column width measurement that pins one shared px track across the header\n * and every row grid so they stay aligned.\n */\nexport function useColumns<T>({\n columns,\n items,\n multiSelect,\n visibleColumnKeys,\n onVisibleColumnsChange,\n persistColumnsKey,\n showColumnToggle,\n rootRef,\n startIndex,\n endIndex,\n containerHeight,\n containerWidth,\n}: UseColumnsArgs<T>): UseColumnsResult<T> {\n const isControlled = visibleColumnKeys !== undefined;\n const [toggleOpen, setToggleOpen] = useState(false);\n const toggleRef = useRef<HTMLDivElement>(null);\n // Measured px widths for `fit` columns, keyed by column key. Pinning these\n // into the shared column template keeps the header and rows aligned (a raw\n // `fit-content` track resolves per-grid and drifts). See the effects below.\n const [fitWidths, setFitWidths] = useState<Record<string, number>>({});\n\n const [internalVisibleKeys, setInternalVisibleKeys] = useState<Set<string>>(() => {\n const persisted = loadPersistedColumns(persistColumnsKey);\n return new Set((columns ?? []).filter((c) => isColumnInitiallyVisible(c, persisted)).map((c) => c.key));\n });\n // The set of column keys the internal visibility state was last reconciled\n // against. The lazy initializer above only runs at mount, so without this a\n // list that mounts in list mode (no columns) and later switches to table mode\n // would keep an empty visible set and render no columns.\n const knownColumnKeysRef = useRef<Set<string>>(new Set((columns ?? []).map((c) => c.key)));\n\n // Re-derive internal visibility when the column set changes at runtime: new\n // columns get their saved/default visibility, removed columns drop out, and\n // existing columns keep whatever the user toggled them to. This is also what\n // applies persisted settings when a list switches from list mode to table\n // mode (columns absent at mount, supplied later).\n useEffect(() => {\n if (isControlled) return;\n const cols = columns ?? [];\n const currentKeys = new Set(cols.map((c) => c.key));\n const known = knownColumnKeysRef.current;\n let identical = currentKeys.size === known.size;\n if (identical) for (const k of currentKeys) if (!known.has(k)) { identical = false; break; }\n if (identical) return;\n knownColumnKeysRef.current = currentKeys;\n const persisted = loadPersistedColumns(persistColumnsKey);\n setInternalVisibleKeys((prev) => {\n const next = new Set<string>();\n for (const c of cols) {\n if (known.has(c.key)) {\n if (prev.has(c.key)) next.add(c.key); // preserve the current-session choice\n } else if (isColumnInitiallyVisible(c, persisted)) {\n next.add(c.key); // newly-added column: saved setting, else defaultHidden\n }\n }\n return next;\n });\n }, [columns, isControlled, persistColumnsKey]);\n\n // Persist visibility whenever it changes (uncontrolled mode only). Skip while\n // there are no columns, or the transient empty state during a list→table\n // switch before the reconcile effect above has filled in the visible set —\n // writing then would clobber the saved config with an empty set.\n useEffect(() => {\n if (isControlled || !persistColumnsKey || typeof window === 'undefined') return;\n const cols = columns ?? [];\n if (cols.length === 0 || internalVisibleKeys.size === 0) return;\n try {\n window.localStorage.setItem(\n COLUMN_STORAGE_PREFIX + persistColumnsKey,\n JSON.stringify({ visible: [...internalVisibleKeys], known: cols.map((c) => c.key) } satisfies PersistedColumns),\n );\n } catch {\n // Storage full or unavailable — non-fatal, just don't persist.\n }\n }, [internalVisibleKeys, columns, isControlled, persistColumnsKey]);\n\n const effectiveVisible: Set<string> = isControlled ? new Set(visibleColumnKeys) : internalVisibleKeys;\n\n useEffect(() => {\n if (!toggleOpen) return;\n function onMouseDown(e: MouseEvent) {\n if (toggleRef.current && !toggleRef.current.contains(e.target as Node)) {\n setToggleOpen(false);\n }\n }\n document.addEventListener('mousedown', onMouseDown);\n return () => document.removeEventListener('mousedown', onMouseDown);\n }, [toggleOpen]);\n\n const hasColumns = !!columns?.length;\n const visibleColumns = hasColumns ? columns!.filter((c) => effectiveVisible.has(c.key)) : [];\n // A column counts as \"manually hidden\" only if it's default-visible yet\n // currently hidden — a defaultHidden column being hidden is its default\n // state, not a user choice, so it never contributes to the chip.\n const manuallyHiddenCount = hasColumns\n ? columns!.filter((c) => !c.defaultHidden && !effectiveVisible.has(c.key)).length\n : 0;\n const selectPrefix = multiSelect && hasColumns ? '40px ' : '';\n const columnTemplate = hasColumns ? `${selectPrefix}${buildColumnTemplate(visibleColumns, fitWidths)}` : undefined;\n const shouldShowToggle = showColumnToggle !== false && hasColumns;\n\n // ── `fit` column width measurement ──────────────────────────────────────────\n const fitColumns = visibleColumns.filter((c) => c.width.type === 'fit');\n const hasFit = fitColumns.length > 0;\n const fitColKey = fitColumns.map((c) => c.key).join('|');\n\n // Drop the measured pins when the data or the fit-column set changes, so the\n // measure effect below re-reads the true intrinsic width on the next pass —\n // this is what lets a column shrink (during scroll the effect only grows it,\n // to avoid jitter). Resetting state during render is React's recommended\n // pattern for \"reset on prop change\" and avoids a cascading effect render.\n const [fitReset, setFitReset] = useState<{ key: string; items: T[] }>({ key: fitColKey, items });\n if (fitReset.key !== fitColKey || fitReset.items !== items) {\n setFitReset({ key: fitColKey, items });\n if (Object.keys(fitWidths).length > 0) setFitWidths({});\n }\n\n // Measure every fit cell currently in the DOM (header + visible rows), keyed\n // by its `data-fit-key`, and grow each column's pin to the widest. Reading the\n // key off the DOM (rather than closing over `fitColumns`) keeps this a stable\n // callback the ResizeObserver below can reuse. `scrollWidth` reports the true\n // content width even when the cell is pinned narrower than its content, so a\n // later pass always recovers a column first measured while it was still empty\n // (e.g. an actions cell whose buttons mount a tick after the row commits — its\n // empty width is just the padding, ~24px, which \"only grow\" can't undo).\n const measureFitWidths = useCallback(() => {\n const root = rootRef.current;\n if (!root) return;\n const maxByKey = new Map<string, number>();\n root.querySelectorAll('[data-fit-key]').forEach((node) => {\n const el = node as HTMLElement;\n const key = el.getAttribute('data-fit-key');\n if (!key) return;\n const overflowing = el.scrollWidth > el.clientWidth;\n let w = el.scrollWidth;\n // Only resolve computed padding when we actually need it — the overflow\n // fix-up, or the collapse check below — so the hot scroll path stays cheap\n // for plain in-flow cells.\n if (overflowing || el.firstElementChild) {\n const cs = getComputedStyle(el);\n const padLeft = parseFloat(cs.paddingLeft) || 0;\n const padRight = parseFloat(cs.paddingRight) || 0;\n // scrollWidth includes the left padding but drops the right padding when\n // the content overflows — add it back.\n if (overflowing) w += padRight;\n // Collapsed-content case (FontAwesome icons etc.): element children are\n // present, yet scrollWidth is only the cell's padding because their boxes\n // overflow via `overflow: visible` and carry no intrinsic width, so they\n // don't count toward scrollWidth (and, when right-aligned, overflow to the\n // *left* into negative offsets). ONLY then walk the descendants for their\n // true span — once a real width pins, the cell is no longer collapsed, so\n // this stops running on every scroll frame.\n if (el.firstElementChild && !overflowing && el.scrollWidth <= padLeft + padRight + 1) {\n let minLeft = Infinity;\n let maxRight = -Infinity;\n el.querySelectorAll('*').forEach((d) => {\n const r = d.getBoundingClientRect();\n if (r.left < minLeft) minLeft = r.left;\n if (r.right > maxRight) maxRight = r.right;\n });\n if (maxRight > minLeft) {\n const span = Math.ceil(maxRight - minLeft) + padLeft + padRight;\n if (span > w) w = span;\n }\n }\n }\n if (w > (maxByKey.get(key) ?? 0)) maxByKey.set(key, w);\n });\n if (maxByKey.size === 0) return;\n setFitWidths((prev) => {\n let changed = false;\n const next = { ...prev };\n for (const [key, max] of maxByKey) {\n if (max <= 0) continue;\n // Cap at the viewport width so one oversized cell can't blow out layout.\n const pinned = Math.min(Math.ceil(max), root.clientWidth);\n if (pinned > (prev[key] ?? 0)) { next[key] = pinned; changed = true; }\n }\n return changed ? next : prev;\n });\n }, [rootRef]);\n\n // One ResizeObserver shared across all fit cells. It re-measures whenever a\n // cell's box changes — crucially when content first appears after mount (which\n // changes the cell's height even while its width is pinned), so a too-early or\n // empty-cell measure self-corrects instead of sticking. Its initial callback\n // also fires once after layout settles, covering route transitions and other\n // post-mount layout shifts without depending on font/rAF timing.\n const [fitObserver] = useState<ResizeObserver | null>(() =>\n typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(() => measureFitWidths()),\n );\n const observedRef = useRef<Set<Element>>(new Set());\n useEffect(() => () => { fitObserver?.disconnect(); observedRef.current.clear(); }, [fitObserver]);\n\n // Measure synchronously (before paint, so a wider row scrolling in never shows\n // a clipped frame), then *diff* the observed set rather than re-observing every\n // cell. Re-observing fires a redundant ResizeObserver callback per node, and\n // `startIndex`/`endIndex` change every scroll frame — so observing only the\n // cells that entered (and dropping the ones that left) keeps stable, already\n // pinned cells from generating any observer traffic while scrolling. A newly\n // entered cell still fires exactly once, which is when we want to measure it.\n useLayoutEffect(() => {\n if (!hasFit) return;\n const root = rootRef.current;\n if (!root) return;\n measureFitWidths();\n if (!fitObserver) return;\n const current = new Set<Element>(root.querySelectorAll('[data-fit-key]'));\n const observed = observedRef.current;\n for (const el of observed) if (!current.has(el)) { fitObserver.unobserve(el); observed.delete(el); }\n for (const el of current) if (!observed.has(el)) { fitObserver.observe(el); observed.add(el); }\n }, [hasFit, fitColKey, fitWidths, startIndex, endIndex, containerHeight, containerWidth, items, measureFitWidths, fitObserver]);\n\n // Cheap insurance: re-measure on the next two frames after mount / data /\n // fit-column changes, in case the icons (or the injected FontAwesome sizing\n // CSS) resolve a frame after the first synchronous pass. Safe and scoped —\n // measureFitWidths only ever grows a pin, and this runs on mount / data change\n // (not every scroll frame), so it keeps the diff-observe perf win.\n useEffect(() => {\n if (!hasFit) return;\n let raf2 = 0;\n const raf1 = requestAnimationFrame(() => {\n measureFitWidths();\n raf2 = requestAnimationFrame(() => measureFitWidths());\n });\n return () => { cancelAnimationFrame(raf1); cancelAnimationFrame(raf2); };\n }, [hasFit, fitColKey, items, measureFitWidths]);\n\n // Force a fresh fit-column measure regardless of current pins. Always installs\n // a new empty object so the measure layout effect re-runs even when nothing\n // was pinned (e.g. content changed while the column was still fit-content).\n const recalculateColumns = useCallback(() => setFitWidths({}), []);\n\n function handleToggleColumn(key: string) {\n const next = new Set(effectiveVisible);\n if (next.has(key)) {\n if (next.size <= 1) return;\n next.delete(key);\n } else {\n next.add(key);\n }\n const nextArray = [...next];\n if (!isControlled) setInternalVisibleKeys(next);\n onVisibleColumnsChange?.(nextArray);\n }\n\n return {\n hasColumns,\n visibleColumns,\n columnTemplate,\n shouldShowToggle,\n effectiveVisible,\n manuallyHiddenCount,\n toggleOpen,\n setToggleOpen,\n toggleRef,\n handleToggleColumn,\n recalculateColumns,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"./virtualList.module.mjs";import{lastDescendantIndex as t,resolveReorderTarget as n,resolveTreeDropTarget as r}from"./virtualList.utils.mjs";import{useCallback as i,useEffect as a,useLayoutEffect as o,useRef as s,useState as c}from"react";function l({reorderable:l,treeReorder:u,onReorder:d,onTreeDrop:f,longPressDelay:p,dragHandle:m,treeIndentPx:ee,keys:h,depths:g,isGroupAt:_,rootRef:v,keysRef:y}){let b=s(null),[x,S]=c(null),[C,w]=c(null),T=s(null),E=s(d),D=s(f),O=s(u),k=s(g),A=s(_),j=s(!0),M=s(null),N=s(!1),P=s(null),F=s(0),I=s(0),L=s(null),R=s(!1),z=s(null),B=s(0),V=s(0),H=s(0),[U]=c(()=>typeof window<`u`&&typeof window.matchMedia==`function`?window.matchMedia(`(pointer: coarse)`).matches:!1);o(()=>{E.current=d,D.current=f,O.current=u,k.current=g,T.current=C,A.current=_});function W(e){j.current=!!e.target.closest(`[data-drag-handle]`)}function G(e,t){if(m&&!j.current){t.preventDefault();return}b.current=e,S(e),u&&w(null)}function K(e,n,i){let a=b.current;if(a==null)return null;let o=h.indexOf(a);if(o!==-1&&e>=o&&e<=t(o,g))return null;let s=r(n,i.top,i.height,_(e));return{key:h[e],position:s}}function q(e,t){t.preventDefault();let n=t.currentTarget.getBoundingClientRect(),r=K(e,t.clientY,n);w(e=>e?.key===r?.key&&e?.position===r?.position?e:r)}function te(){let e=b.current,t=T.current;e!=null&&t&&t.key!==e&&f?.(e,t)}function ne(e){e.preventDefault(),te(),w(null),b.current=null,S(null)}function re(){w(null),b.current=null,S(null)}function ie(e,t){t.preventDefault();let r=b.current;if(r==null)return;let i=h.indexOf(r),a=t.currentTarget.getBoundingClientRect(),o=n(i,e,t.clientY,a.top,a.height);o!=null&&d?.(i,o)}function ae(){b.current=null,S(null)}let J=i(e=>{let i=b.current,a=v.current;if(i==null||!a)return;let o=z.current?I.current-B.current+H.current/2:I.current,s=document.elementFromPoint(e,o),c=s&&a.contains(s)?s.closest(`[data-index]`):null;if(!c)return;let l=Number(c.dataset.index);if(Number.isNaN(l))return;let u=y.current.indexOf(i),d=c.getBoundingClientRect();if(O.current){let e=y.current,n=k.current;if(u!==-1&&l>=u&&l<=t(u,n)){w(null);return}let i=r(o,d.top,d.height,A.current(l)),a={key:e[l],position:i};w(e=>e?.key===a.key&&e?.position===a.position?e:a);return}let f=n(u,l,o,d.top,d.height);f!=null&&E.current?.(u,f)},[v,y]),Y=i(()=>{let e=z.current;e&&(e.style.transform=`translate(${V.current}px, ${I.current-B.current}px)`)},[]),X=i(()=>{let e=v.current;if(!e||!N.current){L.current=null;return}let t=e.getBoundingClientRect(),n=F.current,r=I.current,i=0;n>=t.left&&n<=t.right&&r>=t.top&&r<=t.bottom&&(r<t.top+48?i=-Math.min(18,Math.ceil((t.top+48-r)/3)):r>t.bottom-48&&(i=Math.min(18,Math.ceil((r-(t.bottom-48))/3)))),i!==0&&(e.scrollTop+=i,J(n)),L.current=requestAnimationFrame(X)},[J,v]),Z=i(()=>{if(M.current!=null&&(clearTimeout(M.current),M.current=null),window.removeEventListener(`touchmove`,Q),window.removeEventListener(`touchend`,Z),window.removeEventListener(`touchcancel`,Z),L.current!=null&&(cancelAnimationFrame(L.current),L.current=null),z.current&&=(z.current.remove(),null),document.body.style.touchAction=``,document.body.style.overscrollBehavior=``,N.current&&(R.current=!0,setTimeout(()=>{R.current=!1},350),O.current)){let e=b.current,t=T.current;e!=null&&t&&t.key!==e&&D.current?.(e,t)}w(null),N.current=!1,P.current=null,b.current=null,S(null)},[]),Q=i(e=>{let t=e.touches[0];if(t){if(F.current=t.clientX,I.current=t.clientY,!N.current){let e=P.current;e!=null&&Math.abs(t.clientY-e)>10&&M.current!=null&&(clearTimeout(M.current),M.current=null);return}e.cancelable&&e.preventDefault(),Y(),J(t.clientX)}},[J,Y]);function oe(e,t){if(!l&&!u||m&&!t.target.closest(`[data-drag-handle]`)||M.current!=null||N.current)return;let n=t.touches[0];n&&(P.current=n.clientY,F.current=n.clientX,I.current=n.clientY,window.addEventListener(`touchmove`,Q,{passive:!1}),window.addEventListener(`touchend`,Z),window.addEventListener(`touchcancel`,Z),M.current=window.setTimeout(()=>{M.current=null,N.current=!0,b.current=e,S(e),navigator.vibrate?.(10),document.body.style.touchAction=`none`,document.body.style.overscrollBehavior=`none`,se(e),L.current??=requestAnimationFrame(X)},p))}function se(t){let n=v.current;if(!n)return;let r=y.current.indexOf(t),i=n.querySelector(`[data-index="${r}"]`);if(!i)return;let a=i.getBoundingClientRect();B.current=I.current-a.top,V.current=a.left,H.current=a.height;let o=i.cloneNode(!0);o.removeAttribute(`data-index`),o.setAttribute(`data-drag-clone`,`true`),o.setAttribute(`aria-hidden`,`true`),o.classList.add(e.virtualListDragClone),Object.assign(o.style,{position:`fixed`,left:`0`,top:`0`,width:`${a.width}px`,height:`${a.height}px`,margin:`0`,opacity:`1`,pointerEvents:`none`,zIndex:`3`,background:`var(--background)`,boxShadow:`var(--card-shadow)`,borderRadius:`var(--default-border-radius)`}),n.appendChild(o),z.current=o,Y()}a(()=>Z,[Z]);let $=l||u;function ce(e,t){let n=u&&C?.key===t?C.position:void 0;return{reorderable:$&&!m,draggable:$&&!U||void 0,isDragging:$&&t===x,onMouseDown:$&&m?W:void 0,onDragStart:$?e=>G(t,e):void 0,onDragOver:u?t=>q(e,t):l?t=>ie(e,t):void 0,onDragEnd:u?re:l?ae:void 0,onDrop:u?ne:void 0,onTouchStart:$?e=>oe(t,e):void 0,dropPosition:n,dropIndentPx:n?(g[e]??0)*ee:void 0}}function le(){return R.current?(R.current=!1,!0):!1}return{draggingKey:x,dragEnabled:$,getRowDragProps:ce,consumeSuppressedClick:le}}export{l as useRowDrag};
|
|
2
|
+
//# sourceMappingURL=useRowDrag.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRowDrag.mjs","names":[],"sources":["../../../../package/common/virtualList/useRowDrag.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';\n\nimport styles from './virtualList.module.pcss';\nimport { resolveReorderTarget, resolveTreeDropTarget, lastDescendantIndex } from './virtualList.utils';\nimport type { TreeDropPosition, TreeDropTarget } from './virtualList.types';\n\ninterface UseRowDragArgs {\n reorderable: boolean;\n treeReorder: boolean;\n onReorder?: (fromIndex: number, toIndex: number) => void;\n onTreeDrop?: (dragKey: string | number, target: TreeDropTarget) => void;\n longPressDelay: number;\n dragHandle: boolean;\n treeIndentPx: number;\n /** Current flat ordering and depth tags (mouse handlers read these directly). */\n keys: (string | number)[];\n depths: number[];\n isGroupAt: (index: number) => boolean;\n rootRef: React.RefObject<HTMLDivElement | null>;\n /** Latest keys for async (touch / rAF) consumers — owned by useVirtualWindow. */\n keysRef: React.RefObject<(string | number)[]>;\n}\n\n/** The drag-related props the parent spreads onto a given row. */\nexport interface RowDragProps {\n reorderable: boolean;\n draggable: boolean | undefined;\n isDragging: boolean;\n onMouseDown: ((e: React.MouseEvent<HTMLDivElement>) => void) | undefined;\n onDragStart: ((e: React.DragEvent<HTMLDivElement>) => void) | undefined;\n onDragOver: ((e: React.DragEvent<HTMLDivElement>) => void) | undefined;\n onDragEnd: (() => void) | undefined;\n onDrop: ((e: React.DragEvent<HTMLDivElement>) => void) | undefined;\n onTouchStart: ((e: React.TouchEvent<HTMLDivElement>) => void) | undefined;\n dropPosition: TreeDropPosition | undefined;\n dropIndentPx: number | undefined;\n}\n\ninterface UseRowDragResult {\n /** True while a row is being dragged (for the root reordering style). */\n draggingKey: string | number | null;\n /** Whether either drag mode is active. */\n dragEnabled: boolean;\n /** Drag props for the row at `index` / `key`. */\n getRowDragProps: (index: number, key: string | number) => RowDragProps;\n /** Returns true (and resets) if the next click should be swallowed (post-drag). */\n consumeSuppressedClick: () => boolean;\n}\n\n/**\n * Row drag-and-drop for both modes:\n * - `reorderable` (flat): native HTML5 drag on desktop; rows move live via\n * `onReorder` with midpoint hysteresis.\n * - `treeReorder`: a drop indicator (before/after/inside) is shown during the\n * drag and `onTreeDrop` fires once on release; dropping onto the dragged\n * node's own subtree is forbidden.\n * Touch uses a long-press → lifted-clone → pointer-move path with edge\n * auto-scroll. `dragHandle` restricts initiation to `[data-drag-handle]`.\n */\nexport function useRowDrag({\n reorderable,\n treeReorder,\n onReorder,\n onTreeDrop,\n longPressDelay,\n dragHandle,\n treeIndentPx,\n keys,\n depths,\n isGroupAt,\n rootRef,\n keysRef,\n}: UseRowDragArgs): UseRowDragResult {\n // The dragged item is tracked by its stable key (indices shift after each\n // live reorder); the ref drives the logic, the state drives the row's style.\n const dragKeyRef = useRef<string | number | null>(null);\n const [draggingKey, setDraggingKey] = useState<string | number | null>(null);\n // Tree-reorder drop indicator. Unlike flat reorder (which moves rows live),\n // tree mode shows where the drop will land and commits once on release.\n const [dropTarget, setDropTarget] = useState<TreeDropTarget | null>(null);\n const dropTargetRef = useRef<TreeDropTarget | null>(null);\n const onReorderRef = useRef(onReorder);\n const onTreeDropRef = useRef(onTreeDrop);\n const treeModeRef = useRef(treeReorder);\n const depthsRef = useRef<number[]>(depths);\n const isGroupAtRef = useRef<(i: number) => boolean>(isGroupAt);\n // When `dragHandle` is on, a mousedown sets this to whether it landed on a\n // `[data-drag-handle]` element, gating whether the ensuing dragstart is honoured.\n const dragFromHandleRef = useRef(true);\n const longPressRef = useRef<number | null>(null);\n const touchActiveRef = useRef(false);\n const touchStartYRef = useRef<number | null>(null);\n const pointerXRef = useRef(0);\n const pointerYRef = useRef(0);\n const autoScrollRef = useRef<number | null>(null);\n const suppressNextClickRef = useRef(false);\n // Floating clone that follows the finger during a touch drag.\n const dragCloneRef = useRef<HTMLElement | null>(null);\n const grabOffsetYRef = useRef(0);\n const cloneLeftRef = useRef(0);\n const dragHeightRef = useRef(0);\n // The native `draggable` attribute (mouse DnD) makes a long-press start the\n // browser's own drag on touch devices, which hijacks our touch handlers. So\n // expose it only where the primary pointer is fine (mouse/trackpad); touch\n // devices use the touch handlers below instead.\n const [isCoarsePointer] = useState(() =>\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(pointer: coarse)').matches\n : false,\n );\n\n useLayoutEffect(() => {\n onReorderRef.current = onReorder;\n onTreeDropRef.current = onTreeDrop;\n treeModeRef.current = treeReorder;\n depthsRef.current = depths;\n dropTargetRef.current = dropTarget;\n isGroupAtRef.current = isGroupAt;\n });\n\n // ── Mouse / shared start ──────────────────────────────────────────────────\n\n // With `dragHandle`, remember on mousedown whether the press landed on a\n // handle, so the dragstart that follows can be ignored if it didn't.\n function handleRowMouseDown(e: React.MouseEvent<HTMLDivElement>) {\n dragFromHandleRef.current = !!(e.target as HTMLElement).closest('[data-drag-handle]');\n }\n\n function handleReorderStart(key: string | number, e: React.DragEvent<HTMLDivElement>) {\n if (dragHandle && !dragFromHandleRef.current) {\n e.preventDefault(); // not started from a handle — let the row stay put\n return;\n }\n dragKeyRef.current = key;\n setDraggingKey(key);\n if (treeReorder) setDropTarget(null);\n }\n\n // ── Tree mode ─────────────────────────────────────────────────────────────\n\n /** Resolve the tree drop target for the row at `overIndex` under pointer `y`. */\n function computeTreeDrop(overIndex: number, y: number, rect: DOMRect): TreeDropTarget | null {\n const dragKey = dragKeyRef.current;\n if (dragKey == null) return null;\n const fromIndex = keys.indexOf(dragKey);\n // Forbid dropping onto the dragged node or anything in its own subtree.\n if (fromIndex !== -1 && overIndex >= fromIndex && overIndex <= lastDescendantIndex(fromIndex, depths)) {\n return null;\n }\n const position = resolveTreeDropTarget(y, rect.top, rect.height, isGroupAt(overIndex));\n return { key: keys[overIndex], position };\n }\n\n function handleTreeDragOver(overIndex: number, e: React.DragEvent<HTMLDivElement>) {\n e.preventDefault(); // allow the drop\n const rect = e.currentTarget.getBoundingClientRect();\n const next = computeTreeDrop(overIndex, e.clientY, rect);\n setDropTarget((prev) =>\n prev?.key === next?.key && prev?.position === next?.position ? prev : next,\n );\n }\n\n function commitTreeDrop() {\n const dragKey = dragKeyRef.current;\n const target = dropTargetRef.current;\n if (dragKey != null && target && target.key !== dragKey) onTreeDrop?.(dragKey, target);\n }\n\n function handleTreeDrop(e: React.DragEvent<HTMLDivElement>) {\n e.preventDefault();\n commitTreeDrop();\n setDropTarget(null);\n dragKeyRef.current = null;\n setDraggingKey(null);\n }\n\n function handleTreeDragEnd() {\n // Fires after `drop` (or on its own when released off a valid target).\n setDropTarget(null);\n dragKeyRef.current = null;\n setDraggingKey(null);\n }\n\n // ── Flat mode ─────────────────────────────────────────────────────────────\n\n function handleReorderOver(overIndex: number, e: React.DragEvent<HTMLDivElement>) {\n e.preventDefault(); // allow the drop\n const dragKey = dragKeyRef.current;\n if (dragKey == null) return;\n const fromIndex = keys.indexOf(dragKey);\n // Midpoint hysteresis (see resolveReorderTarget): a move only happens once\n // the pointer crosses the centre of the row it's over. After a swap the\n // dragged row sits under the cursor, so moving again needs real pointer\n // travel — this stops the oscillation that made dragging feel jumpy.\n const rect = e.currentTarget.getBoundingClientRect();\n const target = resolveReorderTarget(fromIndex, overIndex, e.clientY, rect.top, rect.height);\n if (target != null) onReorder?.(fromIndex, target);\n }\n\n function handleReorderEnd() {\n dragKeyRef.current = null;\n setDraggingKey(null);\n }\n\n // ── Touch reordering (long-press to arm, then drag) ──────────────────────────\n // These handlers run from window listeners during a touch drag, so they read\n // mutable state from refs and are stable across renders.\n\n const reorderAtPoint = useCallback((x: number) => {\n const dragKey = dragKeyRef.current;\n const root = rootRef.current;\n if (dragKey == null || !root) return;\n // Reorder against the centre of the lifted clone, not the raw finger — the\n // finger sits below the clone's top by the grab offset, so using it would\n // make the top (and bottom) rows unreachable. The clone is what the user\n // aims with, so match it.\n const y = dragCloneRef.current\n ? pointerYRef.current - grabOffsetYRef.current + dragHeightRef.current / 2\n : pointerYRef.current;\n const el = document.elementFromPoint(x, y) as HTMLElement | null;\n const rowEl = el && root.contains(el) ? el.closest<HTMLElement>('[data-index]') : null;\n if (!rowEl) return;\n const overIndex = Number(rowEl.dataset.index);\n if (Number.isNaN(overIndex)) return;\n const fromIndex = keysRef.current.indexOf(dragKey);\n const rect = rowEl.getBoundingClientRect();\n if (treeModeRef.current) {\n // Tree mode: don't move live — just track where the drop will land.\n const ks = keysRef.current;\n const ds = depthsRef.current;\n if (fromIndex !== -1 && overIndex >= fromIndex && overIndex <= lastDescendantIndex(fromIndex, ds)) {\n setDropTarget(null);\n return;\n }\n const position = resolveTreeDropTarget(y, rect.top, rect.height, isGroupAtRef.current(overIndex));\n const next: TreeDropTarget = { key: ks[overIndex], position };\n setDropTarget((prev) => (prev?.key === next.key && prev?.position === next.position ? prev : next));\n return;\n }\n const target = resolveReorderTarget(fromIndex, overIndex, y, rect.top, rect.height);\n if (target != null) onReorderRef.current?.(fromIndex, target);\n }, [rootRef, keysRef]);\n\n // Keep the floating clone glued under the finger (same grab point).\n const positionDragClone = useCallback(() => {\n const clone = dragCloneRef.current;\n if (!clone) return;\n clone.style.transform = `translate(${cloneLeftRef.current}px, ${pointerYRef.current - grabOffsetYRef.current}px)`;\n }, []);\n\n // While the finger sits near a top/bottom edge (and within the list's width),\n // scroll the list and keep reordering against the rows now passing under it.\n const autoScrollTick = useCallback(() => {\n const root = rootRef.current;\n if (!root || !touchActiveRef.current) { autoScrollRef.current = null; return; }\n const rect = root.getBoundingClientRect();\n const x = pointerXRef.current;\n const y = pointerYRef.current;\n const EDGE = 48;\n let dy = 0;\n // Only auto-scroll while the finger is actually over the list — moving it\n // outside (any direction) stops the scroll instead of running away; pinning\n // the dragged row keeps touch events alive so it resumes when you come back.\n const inside = x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;\n if (inside) {\n if (y < rect.top + EDGE) dy = -Math.min(18, Math.ceil((rect.top + EDGE - y) / 3));\n else if (y > rect.bottom - EDGE) dy = Math.min(18, Math.ceil((y - (rect.bottom - EDGE)) / 3));\n }\n if (dy !== 0) {\n root.scrollTop += dy;\n reorderAtPoint(x);\n }\n autoScrollRef.current = requestAnimationFrame(autoScrollTick);\n }, [reorderAtPoint, rootRef]);\n\n const endTouchDrag = useCallback(() => {\n if (longPressRef.current != null) { clearTimeout(longPressRef.current); longPressRef.current = null; }\n window.removeEventListener('touchmove', handleTouchMove);\n window.removeEventListener('touchend', endTouchDrag);\n window.removeEventListener('touchcancel', endTouchDrag);\n if (autoScrollRef.current != null) { cancelAnimationFrame(autoScrollRef.current); autoScrollRef.current = null; }\n if (dragCloneRef.current) { dragCloneRef.current.remove(); dragCloneRef.current = null; }\n // Restore native scrolling that was locked for the duration of the drag.\n document.body.style.touchAction = '';\n document.body.style.overscrollBehavior = '';\n if (touchActiveRef.current) {\n // A real drag happened — swallow the click the browser fires afterwards\n // so it doesn't, e.g., toggle row selection.\n suppressNextClickRef.current = true;\n setTimeout(() => { suppressNextClickRef.current = false; }, 350);\n // Tree mode commits the pending drop on release (flat mode already moved\n // rows live during the drag, so there's nothing to commit here).\n if (treeModeRef.current) {\n const dk = dragKeyRef.current;\n const target = dropTargetRef.current;\n if (dk != null && target && target.key !== dk) onTreeDropRef.current?.(dk, target);\n }\n }\n setDropTarget(null);\n touchActiveRef.current = false;\n touchStartYRef.current = null;\n dragKeyRef.current = null;\n setDraggingKey(null);\n }, []);\n\n const handleTouchMove = useCallback((e: TouchEvent) => {\n const t = e.touches[0];\n if (!t) return;\n pointerXRef.current = t.clientX;\n pointerYRef.current = t.clientY;\n if (!touchActiveRef.current) {\n // Before the long-press fires: if the finger travels, the user means to\n // scroll, so disarm and let the browser handle it (we don't preventDefault).\n const sy = touchStartYRef.current;\n if (sy != null && Math.abs(t.clientY - sy) > 10 && longPressRef.current != null) {\n clearTimeout(longPressRef.current);\n longPressRef.current = null;\n }\n return;\n }\n // Non-passive listener: preventDefault cancels the native scroll for this\n // gesture — the only reliable way once touch-action has been latched at\n // touchstart. This is what makes the drag actually move on touch devices.\n if (e.cancelable) e.preventDefault();\n positionDragClone();\n reorderAtPoint(t.clientX);\n }, [reorderAtPoint, positionDragClone]);\n\n function handleRowTouchStart(key: string | number, e: React.TouchEvent<HTMLDivElement>) {\n if (!reorderable && !treeReorder) return;\n // With a drag handle, only a press that starts on it arms the drag, so the\n // rest of the row stays free for tapping/typing into inputs.\n if (dragHandle && !(e.target as HTMLElement).closest('[data-drag-handle]')) return;\n if (longPressRef.current != null || touchActiveRef.current) return; // ignore extra fingers\n const t = e.touches[0];\n if (!t) return;\n touchStartYRef.current = t.clientY;\n pointerXRef.current = t.clientX;\n pointerYRef.current = t.clientY;\n window.addEventListener('touchmove', handleTouchMove, { passive: false });\n window.addEventListener('touchend', endTouchDrag);\n window.addEventListener('touchcancel', endTouchDrag);\n longPressRef.current = window.setTimeout(() => {\n longPressRef.current = null;\n touchActiveRef.current = true;\n dragKeyRef.current = key;\n setDraggingKey(key);\n navigator.vibrate?.(10);\n // Lock native scrolling for the whole gesture — relying on per-move\n // preventDefault isn't enough once the finger leaves and re-enters the\n // list (the browser commits to a scroll and ignores it). We do all the\n // scrolling ourselves via autoScrollTick.\n document.body.style.touchAction = 'none';\n document.body.style.overscrollBehavior = 'none';\n createDragClone(key);\n if (autoScrollRef.current == null) autoScrollRef.current = requestAnimationFrame(autoScrollTick);\n }, longPressDelay);\n }\n\n // Build a floating copy of the picked-up row that tracks the finger, so the\n // drag has a visible \"lifted\" element (the original row stays dimmed in place\n // as a drop placeholder).\n function createDragClone(key: string | number) {\n const root = rootRef.current;\n if (!root) return;\n const idx = keysRef.current.indexOf(key);\n const src = root.querySelector<HTMLElement>(`[data-index=\"${idx}\"]`);\n if (!src) return;\n const r = src.getBoundingClientRect();\n grabOffsetYRef.current = pointerYRef.current - r.top;\n cloneLeftRef.current = r.left;\n dragHeightRef.current = r.height;\n const clone = src.cloneNode(true) as HTMLElement;\n clone.removeAttribute('data-index');\n clone.setAttribute('data-drag-clone', 'true');\n clone.setAttribute('aria-hidden', 'true');\n clone.classList.add(styles.virtualListDragClone);\n Object.assign(clone.style, {\n position: 'fixed',\n left: '0',\n top: '0',\n width: `${r.width}px`,\n height: `${r.height}px`,\n margin: '0',\n opacity: '1',\n pointerEvents: 'none',\n // Above the sticky header (z-index 2) and any focused row (z-index 1).\n zIndex: '3',\n background: 'var(--background)',\n boxShadow: 'var(--card-shadow)',\n borderRadius: 'var(--default-border-radius)',\n } as Partial<CSSStyleDeclaration>);\n // Appended inside the list so it inherits the active theme's CSS variables;\n // position:fixed keeps it in viewport coordinates regardless.\n root.appendChild(clone);\n dragCloneRef.current = clone;\n positionDragClone();\n }\n\n // Tear down any in-flight touch drag if the component unmounts mid-gesture.\n useEffect(() => endTouchDrag, [endTouchDrag]);\n\n // Either drag mode arms the same row gestures; the handlers above branch on\n // `treeReorder` for the differing target resolution / commit behaviour.\n const dragEnabled = reorderable || treeReorder;\n\n function getRowDragProps(index: number, key: string | number): RowDragProps {\n // The drop indicator only renders on the row currently targeted. `before`/\n // `after` lines indent to the target's depth so they sit under where the\n // dropped content will start; `inside` highlights the whole row instead.\n const rowDrop = treeReorder && dropTarget?.key === key ? dropTarget.position : undefined;\n return {\n // Drives the row-wide grab cursor. With `dragHandle`, only the handle\n // initiates a drag, so the cursor belongs on the handle (styled by the\n // consumer), not across the whole row.\n reorderable: dragEnabled && !dragHandle,\n draggable: (dragEnabled && !isCoarsePointer) || undefined,\n isDragging: dragEnabled && key === draggingKey,\n onMouseDown: dragEnabled && dragHandle ? handleRowMouseDown : undefined,\n onDragStart: dragEnabled ? (e) => handleReorderStart(key, e) : undefined,\n onDragOver:\n treeReorder ? (e) => handleTreeDragOver(index, e)\n : reorderable ? (e) => handleReorderOver(index, e)\n : undefined,\n onDragEnd: treeReorder ? handleTreeDragEnd : reorderable ? handleReorderEnd : undefined,\n onDrop: treeReorder ? handleTreeDrop : undefined,\n onTouchStart: dragEnabled ? (e) => handleRowTouchStart(key, e) : undefined,\n dropPosition: rowDrop,\n dropIndentPx: rowDrop ? (depths[index] ?? 0) * treeIndentPx : undefined,\n };\n }\n\n function consumeSuppressedClick(): boolean {\n if (suppressNextClickRef.current) { suppressNextClickRef.current = false; return true; }\n return false;\n }\n\n return { draggingKey, dragEnabled, getRowDragProps, consumeSuppressedClick };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useMemo as e,useState as t}from"react";function n({items:n,getKey:r,multiSelect:i,selectedKeys:a,onSelectionChange:o}){let s=a!==void 0,[c,l]=t(new Set),u=s?a:c;function d(e){s||l(e),o?.(e)}function f(e){let t=new Set(u);t.has(e)?t.delete(e):t.add(e),d(t)}function p(){let e=n.map((e,t)=>r(e,t));d(e.every(e=>u.has(e))?new Set:new Set(e))}let{allSelected:m,someSelected:h}=e(()=>{if(!i||n.length===0)return{allSelected:!1,someSelected:!1};let e=n.every((e,t)=>u.has(r(e,t)));return{allSelected:e,someSelected:!e&&n.some((e,t)=>u.has(r(e,t)))}},[i,n,u,r]);return{effectiveSelectedKeys:u,handleRowSelect:f,handleSelectAll:p,allSelected:m,someSelected:h}}export{n as useSelection};
|
|
2
|
+
//# sourceMappingURL=useSelection.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSelection.mjs","names":[],"sources":["../../../../package/common/virtualList/useSelection.ts"],"sourcesContent":["import { useState, useMemo } from 'react';\n\ninterface UseSelectionArgs<T> {\n items: T[];\n getKey: (item: T, index: number) => string | number;\n multiSelect: boolean;\n /** Controlled selected keys. When provided, internal state is ignored. */\n selectedKeys?: Set<string | number>;\n onSelectionChange?: (keys: Set<string | number>) => void;\n}\n\ninterface UseSelectionResult {\n effectiveSelectedKeys: Set<string | number>;\n /** Toggle one row's membership in the selection. */\n handleRowSelect: (key: string | number) => void;\n /** Select all rows, or clear if all are already selected. */\n handleSelectAll: () => void;\n allSelected: boolean;\n someSelected: boolean;\n}\n\n/**\n * Multi-row selection, controlled or uncontrolled. `allSelected`/`someSelected`\n * (for the header checkbox) are O(n) scans, so they're only computed when\n * `multiSelect` is on.\n */\nexport function useSelection<T>({\n items,\n getKey,\n multiSelect,\n selectedKeys,\n onSelectionChange,\n}: UseSelectionArgs<T>): UseSelectionResult {\n const isControlled = selectedKeys !== undefined;\n const [internalSelectedKeys, setInternalSelectedKeys] = useState<Set<string | number>>(new Set());\n const effectiveSelectedKeys = isControlled ? selectedKeys! : internalSelectedKeys;\n\n function applySelection(next: Set<string | number>) {\n if (!isControlled) setInternalSelectedKeys(next);\n onSelectionChange?.(next);\n }\n\n function handleRowSelect(key: string | number) {\n const next = new Set(effectiveSelectedKeys);\n if (next.has(key)) next.delete(key); else next.add(key);\n applySelection(next);\n }\n\n function handleSelectAll() {\n const allKeys = items.map((item, i) => getKey(item, i));\n const allChosen = allKeys.every((k) => effectiveSelectedKeys.has(k));\n applySelection(allChosen ? new Set() : new Set(allKeys));\n }\n\n // O(n) header-checkbox state. The component re-renders every scroll frame\n // (scrollTop is state), but these depend only on the items and the selection —\n // so memoise to keep two full-list scans off the scroll path.\n const { allSelected, someSelected } = useMemo(() => {\n if (!multiSelect || items.length === 0) return { allSelected: false, someSelected: false };\n const all = items.every((item, i) => effectiveSelectedKeys.has(getKey(item, i)));\n const some = !all && items.some((item, i) => effectiveSelectedKeys.has(getKey(item, i)));\n return { allSelected: all, someSelected: some };\n }, [multiSelect, items, effectiveSelectedKeys, getKey]);\n\n return { effectiveSelectedKeys, handleRowSelect, handleSelectAll, allSelected, someSelected };\n}\n"],"mappings":"8CA0BA,SAAgB,EAAgB,CAC9B,QACA,SACA,cACA,eACA,qBAC0C,CAC1C,IAAM,EAAe,IAAiB,IAAA,GAChC,CAAC,EAAsB,GAA2B,EAA+B,IAAI,GAAK,EAC1F,EAAwB,EAAe,EAAgB,EAE7D,SAAS,EAAe,EAA4B,CAC7C,GAAc,EAAwB,CAAI,EAC/C,IAAoB,CAAI,CAC1B,CAEA,SAAS,EAAgB,EAAsB,CAC7C,IAAM,EAAO,IAAI,IAAI,CAAqB,EACtC,EAAK,IAAI,CAAG,EAAG,EAAK,OAAO,CAAG,EAAQ,EAAK,IAAI,CAAG,EACtD,EAAe,CAAI,CACrB,CAEA,SAAS,GAAkB,CACzB,IAAM,EAAU,EAAM,KAAK,EAAM,IAAM,EAAO,EAAM,CAAC,CAAC,EAEtD,EADkB,EAAQ,MAAO,GAAM,EAAsB,IAAI,CAAC,CACnD,EAAY,IAAI,IAAQ,IAAI,IAAI,CAAO,CAAC,CACzD,CAKA,GAAM,CAAE,cAAa,gBAAiB,MAAc,CAClD,GAAI,CAAC,GAAe,EAAM,SAAW,EAAG,MAAO,CAAE,YAAa,GAAO,aAAc,EAAM,EACzF,IAAM,EAAM,EAAM,OAAO,EAAM,IAAM,EAAsB,IAAI,EAAO,EAAM,CAAC,CAAC,CAAC,EAE/E,MAAO,CAAE,YAAa,EAAK,aADd,CAAC,GAAO,EAAM,MAAM,EAAM,IAAM,EAAsB,IAAI,EAAO,EAAM,CAAC,CAAC,CAAC,CACzC,CAChD,EAAG,CAAC,EAAa,EAAO,EAAuB,CAAM,CAAC,EAEtD,MAAO,CAAE,wBAAuB,kBAAiB,kBAAiB,cAAa,cAAa,CAC9F"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{buildOffsets as e,findStartIndex as t,getVisibleRange as n}from"./virtualList.utils.mjs";import{useCallback as r,useEffect as i,useLayoutEffect as a,useMemo as o,useRef as s,useState as c}from"react";function l(e,t){if(typeof e==`number`)return e;let n=e.trim();if(n===``)return 0;let r=Number(n);if(!Number.isNaN(r))return r;let i=/^(-?\d*\.?\d+)px$/.exec(n);if(i)return parseFloat(i[1]);if(typeof document>`u`||!t)return 0;let a=document.createElement(`div`);a.style.cssText=`position:absolute;visibility:hidden;height:${n};`,t.appendChild(a);let o=a.getBoundingClientRect().height;return t.removeChild(a),Number.isFinite(o)?o:0}function u({items:u,keys:d,getItemKey:f,estimatedRowHeight:p,rowGap:m,overscan:h,onLoadMore:g,loadMoreThreshold:_}){let[v,y]=c(0),[b,x]=c(0),[S,C]=c(0),[w,T]=c(()=>l(m,null)),[E,D]=c(new Map),[O,k]=c(!1),A=s(!1),j=s(null),M=s(null),N=s([]),P=s(null),F=s(0),I=s([]),[L]=c(()=>typeof ResizeObserver>`u`?null:new ResizeObserver(e=>{D(t=>{let n=null;for(let r of e){let e=r.target,i=Number(e.dataset.index);if(Number.isNaN(i))continue;let a=I.current[i];if(a===void 0)continue;let o=r.borderBoxSize?.[0],s=o?Math.round(o.blockSize):e.offsetHeight;t.get(a)!==s&&(n||=new Map(t),n.set(a,s))}return n??t})}));i(()=>()=>L?.disconnect(),[L]),a(()=>{let e=j.current;if(!e)return;x(e.clientHeight),C(e.clientWidth);let t=new ResizeObserver(()=>{x(e.clientHeight),C(e.clientWidth)});return t.observe(e),()=>t.disconnect()},[]);let R=r(e=>{let t=e.currentTarget;F.current=t.scrollTop,P.current??=requestAnimationFrame(()=>{P.current=null,y(F.current)}),g&&!A.current&&t.scrollTop+t.clientHeight>=t.scrollHeight-_&&(A.current=!0,k(!0),g().finally(()=>{A.current=!1,k(!1)}))},[g,_]);i(()=>()=>{P.current!=null&&cancelAnimationFrame(P.current)},[]),a(()=>{I.current=d}),a(()=>{let e=l(m,j.current);T(t=>t===e?t:e)},[m,S,b]);let{offsets:z,totalHeight:B}=o(()=>e(d,E,p,w),[d,E,p,w]);a(()=>{let e=j.current,n=N.current;if(N.current=z,!e||n.length===0)return;let r=e.scrollTop;if(r<=0)return;let i=t(n,r,n.length-1);if(i>=u.length)return;let a=r-n[i],o=z[i]+a;Math.abs(o-r)>.5&&(e.scrollTop=o,F.current=o,y(o))},[z,u.length]);let V=o(()=>{function e(e,t){let n=j.current;if(!n)return;let r=Math.max(0,e);typeof n.scrollTo==`function`?n.scrollTo({top:r,behavior:t??`auto`}):n.scrollTop=r}function t(t,n){let r=j.current;if(!r||u.length===0)return;let i=Math.max(0,Math.min(t,u.length-1)),a=z[i]??0,o=(z[i+1]??a)-a,s=M.current?.offsetHeight??0,c=Math.max(0,r.clientHeight-s),l=n?.align??`start`,d=a-s;l===`center`?d-=(c-o)/2:l===`end`&&(d-=c-o),e(d,n?.behavior)}return{scrollToIndex:t,scrollToKey(e,n){let r=u.findIndex((t,n)=>(f?f(t,n):n)===e);r>=0&&t(r,n)},scrollToTop(t){e(0,t?.behavior)},getScrollElement:()=>j.current}},[u,z,f]),{startIndex:H,endIndex:U}=o(()=>n(z,v,b,h,u.length),[z,v,b,h,u.length]);return{rootRef:j,headerRef:M,rowObserver:L,keysRef:I,offsets:z,totalHeight:B,containerHeight:b,containerWidth:S,startIndex:H,endIndex:U,handleScroll:R,showLoadMoreSpinner:O,scrollApi:V}}export{u as useVirtualWindow};
|
|
2
|
+
//# sourceMappingURL=useVirtualWindow.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useVirtualWindow.mjs","names":[],"sources":["../../../../package/common/virtualList/useVirtualWindow.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useMemo, useCallback } from 'react';\n\nimport { buildOffsets, findStartIndex, getVisibleRange } from './virtualList.utils';\nimport type { VirtualListHandle, VirtualListScrollOptions } from './virtualList.types';\n\n/**\n * Resolve a `rowGap` value to pixels for the offset math. Numbers and plain\n * `px`/numeric strings parse directly (no DOM, SSR/test-safe); any other CSS\n * length (`em`, `rem`, `%`, `var(...)`) is resolved via a hidden probe appended\n * to `contextEl` so it inherits the list's font-size and custom properties.\n */\nfunction resolveCssLength(value: number | string, contextEl: HTMLElement | null): number {\n if (typeof value === 'number') return value;\n const trimmed = value.trim();\n if (trimmed === '') return 0;\n const asNumber = Number(trimmed);\n if (!Number.isNaN(asNumber)) return asNumber; // \"8\" → 8\n const pxMatch = /^(-?\\d*\\.?\\d+)px$/.exec(trimmed);\n if (pxMatch) return parseFloat(pxMatch[1]); // \"8px\" → 8\n if (typeof document === 'undefined' || !contextEl) return 0;\n const probe = document.createElement('div');\n probe.style.cssText = `position:absolute;visibility:hidden;height:${trimmed};`;\n contextEl.appendChild(probe);\n const px = probe.getBoundingClientRect().height;\n contextEl.removeChild(probe);\n return Number.isFinite(px) ? px : 0;\n}\n\ninterface UseVirtualWindowArgs<T> {\n items: T[];\n /** Stable key per row (already derived by the caller). */\n keys: (string | number)[];\n getItemKey?: (item: T, index: number) => string | number;\n estimatedRowHeight: number;\n rowGap: number | string;\n overscan: number;\n onLoadMore?: () => Promise<void>;\n loadMoreThreshold: number;\n}\n\ninterface UseVirtualWindowResult {\n rootRef: React.RefObject<HTMLDivElement | null>;\n headerRef: React.RefObject<HTMLDivElement | null>;\n /** Shared by every row to measure its height (read back via `data-index`). */\n rowObserver: ResizeObserver | null;\n /** Latest index → key mapping, for async consumers (e.g. the drag hook). */\n keysRef: React.RefObject<(string | number)[]>;\n offsets: number[];\n totalHeight: number;\n containerHeight: number;\n containerWidth: number;\n startIndex: number;\n endIndex: number;\n handleScroll: (e: React.UIEvent<HTMLDivElement>) => void;\n showLoadMoreSpinner: boolean;\n /** The scroll-related imperative methods, for the component to compose into\n * the forwarded handle alongside column controls. */\n scrollApi: Omit<VirtualListHandle, 'recalculateColumns'>;\n}\n\n/**\n * The generic virtualization engine: viewport measurement, per-row height\n * caching, offset/visible-range computation, scroll coalescing, scroll\n * anchoring on height changes, infinite-load triggering, and the imperative\n * scroll handle. Mode-agnostic — knows nothing about columns, selection or\n * dragging.\n */\nexport function useVirtualWindow<T>({\n items,\n keys,\n getItemKey,\n estimatedRowHeight,\n rowGap,\n overscan,\n onLoadMore,\n loadMoreThreshold,\n}: UseVirtualWindowArgs<T>): UseVirtualWindowResult {\n const [scrollTop, setScrollTop] = useState(0);\n const [containerHeight, setContainerHeight] = useState(0);\n const [containerWidth, setContainerWidth] = useState(0);\n // rowGap may be any CSS length; resolve it to px for the offset math. Seed with\n // the synchronous fast path (number / px), then refine before paint for units\n // that need the DOM (em/rem/%/var).\n const [resolvedRowGap, setResolvedRowGap] = useState<number>(() => resolveCssLength(rowGap, null));\n const [heightsMap, setHeightsMap] = useState<Map<string | number, number>>(new Map());\n const [showLoadMoreSpinner, setShowLoadMoreSpinner] = useState(false);\n const isLoadingMoreRef = useRef(false);\n\n const rootRef = useRef<HTMLDivElement>(null);\n const headerRef = useRef<HTMLDivElement>(null);\n const prevOffsetsRef = useRef<number[]>([]);\n const scrollRafRef = useRef<number | null>(null);\n const pendingScrollTopRef = useRef(0);\n const keysRef = useRef<(string | number)[]>([]);\n\n // One ResizeObserver shared by every row, created once via a lazy state\n // initializer so rows mounting in the same commit can register in their\n // layout effect. Batching all entries into a single setState avoids a\n // re-render per row when many rows enter the viewport at once (the main\n // source of scroll jank). The row index is read back from `data-index`.\n const [rowObserver] = useState<ResizeObserver | null>(() => {\n if (typeof ResizeObserver === 'undefined') return null;\n return new ResizeObserver((entries) => {\n setHeightsMap((prev) => {\n let next: Map<string | number, number> | null = null;\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n const idx = Number(el.dataset.index);\n if (Number.isNaN(idx)) continue;\n // Resolve the row's stable key so the cache survives reorders/filters.\n const key = keysRef.current[idx];\n if (key === undefined) continue;\n // Prefer the size the observer already computed — reading offsetHeight\n // here would force a synchronous reflow on every measurement batch.\n const box = entry.borderBoxSize?.[0];\n const h = box ? Math.round(box.blockSize) : el.offsetHeight;\n if (prev.get(key) === h) continue;\n if (!next) next = new Map(prev);\n next.set(key, h);\n }\n return next ?? prev;\n });\n });\n });\n useEffect(() => () => rowObserver?.disconnect(), [rowObserver]);\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n if (!el) return;\n // Measure synchronously before the first paint so the initial render fills\n // the viewport, instead of painting a few overscan rows and re-rendering.\n setContainerHeight(el.clientHeight);\n setContainerWidth(el.clientWidth);\n // Track width too: `fit` columns are measured against this box and capped at\n // its width, so when the container settles to its real width after a route\n // transition / async layout, that change has to re-trigger the measure —\n // otherwise an early measure against a 0/tiny width gets pinned and sticks.\n const observer = new ResizeObserver(() => {\n setContainerHeight(el.clientHeight);\n setContainerWidth(el.clientWidth);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {\n const el = e.currentTarget;\n // Coalesce scroll-driven re-renders to at most one per animation frame.\n // Scroll events can fire several times per frame (especially while dragging\n // the scrollbar thumb); rendering the visible window once per frame keeps\n // the content in step with the cursor instead of lagging behind.\n pendingScrollTopRef.current = el.scrollTop;\n if (scrollRafRef.current == null) {\n scrollRafRef.current = requestAnimationFrame(() => {\n scrollRafRef.current = null;\n setScrollTop(pendingScrollTopRef.current);\n });\n }\n\n if (onLoadMore && !isLoadingMoreRef.current) {\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - loadMoreThreshold) {\n isLoadingMoreRef.current = true;\n setShowLoadMoreSpinner(true);\n onLoadMore().finally(() => {\n isLoadingMoreRef.current = false;\n setShowLoadMoreSpinner(false);\n });\n }\n }\n }, [onLoadMore, loadMoreThreshold]);\n\n useEffect(() => () => {\n if (scrollRafRef.current != null) cancelAnimationFrame(scrollRafRef.current);\n }, []);\n\n useLayoutEffect(() => {\n keysRef.current = keys;\n });\n\n // Resolve the gap to px before paint, re-running when the value or the\n // container's layout changes (a theme/font change that alters em/var is caught\n // by the container ResizeObserver feeding containerWidth/Height).\n useLayoutEffect(() => {\n const px = resolveCssLength(rowGap, rootRef.current);\n setResolvedRowGap((prev) => (prev === px ? prev : px));\n }, [rowGap, containerWidth, containerHeight]);\n\n const { offsets, totalHeight } = useMemo(\n () => buildOffsets(keys, heightsMap, estimatedRowHeight, resolvedRowGap),\n [keys, heightsMap, estimatedRowHeight, resolvedRowGap],\n );\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n const prevOffsets = prevOffsetsRef.current;\n prevOffsetsRef.current = offsets;\n\n // Nothing to anchor against on the first pass or when pinned at the top.\n if (!el || prevOffsets.length === 0) return;\n const curScrollTop = el.scrollTop;\n if (curScrollTop <= 0) return;\n\n // Scroll anchoring: pin the row at the top of the viewport. Find it under\n // the *previous* offsets, then re-derive scrollTop from its *new* offset so\n // it stays visually fixed when rows above it are measured or resized. This\n // is more robust than summing per-row height deltas — it can't drift, and\n // one correction covers any number of simultaneous changes above the fold.\n const prevCount = prevOffsets.length - 1;\n const anchor = findStartIndex(prevOffsets, curScrollTop, prevCount);\n if (anchor >= items.length) return;\n const within = curScrollTop - prevOffsets[anchor];\n const target = offsets[anchor] + within;\n if (Math.abs(target - curScrollTop) > 0.5) {\n el.scrollTop = target;\n pendingScrollTopRef.current = target;\n setScrollTop(target);\n }\n }, [offsets, items.length]);\n\n const scrollApi = useMemo<Omit<VirtualListHandle, 'recalculateColumns'>>(() => {\n function scrollToOffset(top: number, behavior?: ScrollBehavior) {\n const el = rootRef.current;\n if (!el) return;\n const clamped = Math.max(0, top);\n if (typeof el.scrollTo === 'function') el.scrollTo({ top: clamped, behavior: behavior ?? 'auto' });\n else el.scrollTop = clamped;\n }\n function scrollToIndex(index: number, options?: VirtualListScrollOptions) {\n const el = rootRef.current;\n if (!el || items.length === 0) return;\n const i = Math.max(0, Math.min(index, items.length - 1));\n const rowTop = offsets[i] ?? 0;\n const rowHeight = (offsets[i + 1] ?? rowTop) - rowTop;\n // The sticky header overlaps the top of the scroll area, so the usable\n // viewport starts below it — account for that when aligning.\n const headerH = headerRef.current?.offsetHeight ?? 0;\n const usable = Math.max(0, el.clientHeight - headerH);\n const align = options?.align ?? 'start';\n let top = rowTop - headerH;\n if (align === 'center') top -= (usable - rowHeight) / 2;\n else if (align === 'end') top -= usable - rowHeight;\n scrollToOffset(top, options?.behavior);\n }\n return {\n scrollToIndex,\n scrollToKey(key, options) {\n const i = items.findIndex((item, idx) => (getItemKey ? getItemKey(item, idx) : idx) === key);\n if (i >= 0) scrollToIndex(i, options);\n },\n scrollToTop(options) {\n scrollToOffset(0, options?.behavior);\n },\n getScrollElement: () => rootRef.current,\n };\n }, [items, offsets, getItemKey]);\n\n const { startIndex, endIndex } = useMemo(\n () => getVisibleRange(offsets, scrollTop, containerHeight, overscan, items.length),\n [offsets, scrollTop, containerHeight, overscan, items.length],\n );\n\n return {\n rootRef,\n headerRef,\n rowObserver,\n keysRef,\n offsets,\n totalHeight,\n containerHeight,\n containerWidth,\n startIndex,\n endIndex,\n handleScroll,\n showLoadMoreSpinner,\n scrollApi,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"../loading/spinnerLoading/index.mjs";import t from"../checkbox/checkbox.mjs";import n from"./virtualList.module.mjs";import ee from"./virtualRow.mjs";import"./virtualList.utils.mjs";import{useVirtualWindow as r}from"./useVirtualWindow.mjs";import{useSelection as i}from"./useSelection.mjs";import{useColumns as a}from"./useColumns.mjs";import{useRowDrag as o}from"./useRowDrag.mjs";import s,{useCallback as c,useImperativeHandle as te,useMemo as l}from"react";import u from"classnames";import{FontAwesomeIcon as ne}from"@fortawesome/react-fontawesome";import{faGear as re}from"@fortawesome/free-solid-svg-icons";import{Fragment as ie,jsx as d,jsxs as f}from"react/jsx-runtime";function p({items:s,renderRow:p,columns:m,height:h=`100%`,estimatedRowHeight:g=40,overscan:_=3,rowGap:ae=0,rowPadding:v,selectedKey:y,getItemKey:b,onRowClick:oe,visibleColumnKeys:se,onVisibleColumnsChange:ce,persistColumnsKey:le,showColumnToggle:ue,onLoadMore:de,loadMoreThreshold:fe=100,isLoading:pe=!1,multiSelect:x=!1,selectedKeys:me,onSelectionChange:he,reorderable:ge=!1,onReorder:_e,longPressDelay:ve=400,treeReorder:ye=!1,getItemDepth:S,isGroup:C,onTreeDrop:w,treeIndentPx:T=24,dragHandle:E=!1,showDivider:D=!0,rowHover:O=!0,className:k,style:A,classNames:j,styles:M,...N},P){let F=c((e,t)=>b?b(e,t):t,[b]),I=l(()=>s.map((e,t)=>F(e,t)),[s,F]),be=l(()=>S?s.map((e,t)=>S(e,t)):[],[s,S]),xe=c(e=>C?C(s[e],e):!1,[C,s]),L=r({items:s,keys:I,getItemKey:b,estimatedRowHeight:g,rowGap:ae,overscan:_,onLoadMore:de,loadMoreThreshold:fe}),{rootRef:R,headerRef:Se,rowObserver:Ce,keysRef:we,offsets:Te,totalHeight:Ee,startIndex:z,endIndex:B}=L,V=i({items:s,getKey:F,multiSelect:x,selectedKeys:me,onSelectionChange:he}),{effectiveSelectedKeys:H}=V,{hasColumns:U,visibleColumns:W,columnTemplate:G,shouldShowToggle:K,effectiveVisible:De,manuallyHiddenCount:q,toggleOpen:Oe,setToggleOpen:J,toggleRef:ke,handleToggleColumn:Ae,recalculateColumns:Y}=a({columns:m,items:s,multiSelect:x,visibleColumnKeys:se,onVisibleColumnsChange:ce,persistColumnsKey:le,showColumnToggle:ue,rootRef:R,startIndex:z,endIndex:B,containerHeight:L.containerHeight,containerWidth:L.containerWidth});te(P,()=>({...L.scrollApi,recalculateColumns:Y}),[L.scrollApi,Y]);let X=o({reorderable:ge,treeReorder:ye,onReorder:_e,onTreeDrop:w,longPressDelay:ve,dragHandle:E,treeIndentPx:T,keys:I,depths:be,isGroupAt:xe,rootRef:R,keysRef:we}),je=typeof v==`number`?`${v}px`:v,Z=e=>{let r=s[e],i=F(r,e),a=y!=null&&i===y||H.has(i),o=X.getRowDragProps(e,i);return d(ee,{index:e,top:Te[e],padding:je,columnTemplate:G,isSelected:a,showDivider:D,hover:O,onClick:()=>{X.consumeSuppressedClick()||oe?.(r,e)},observer:Ce,ariaRowIndex:U?e+2:void 0,ariaPosInSet:U?void 0:e+1,ariaSetSize:U?void 0:s.length,rowRole:U?`row`:`listitem`,reserveToggleGutter:K,...o,dropIndicatorClassName:j?.dropIndicator,dropIndicatorStyle:M?.dropIndicator,rowClassName:j?.row,rowStyle:M?.row,children:U?f(ie,{children:[x&&d(`div`,{className:u(n.virtualListSelectCell,j?.selectCell),style:M?.selectCell,role:`gridcell`,onClick:e=>e.stopPropagation(),children:d(t,{selected:H.has(i),onToggle:()=>V.handleRowSelect(i),"aria-label":`Select row`})}),W.map(t=>d(`div`,{className:u(n.virtualListCell,j?.cell),style:M?.cell,role:`gridcell`,"data-fit-key":t.width.type===`fit`?t.key:void 0,children:t.renderCell(r,e)},t.key))]}):p?.(r,e)},i)},Q=[];for(let e=z;e<=B;e++)Q.push(Z(e));let $=X.draggingKey==null?-1:I.indexOf(X.draggingKey);return $>=0&&($<z||$>B)&&Q.push(Z($)),f(`div`,{...N,ref:R,className:u(n.virtualList,X.draggingKey!=null&&n.virtualListReordering,k,j?.root),style:{height:h,...A,...M?.root},onScroll:L.handleScroll,role:U?`grid`:`list`,"aria-rowcount":U?s.length+1:void 0,children:[U&&f(`div`,{ref:Se,className:u(n.virtualListHeader,j?.header),style:{gridTemplateColumns:G,...K?{paddingRight:32}:{},...M?.header},role:`row`,"aria-rowindex":1,children:[x&&d(`div`,{className:u(n.virtualListSelectCell,j?.selectCell),style:M?.selectCell,role:`columnheader`,children:d(t,{selected:V.allSelected||V.someSelected,onToggle:V.handleSelectAll,"aria-label":`Select all rows`})}),W.map(e=>d(`div`,{className:u(n.virtualListHeaderCell,j?.headerCell),style:M?.headerCell,role:`columnheader`,"data-fit-key":e.width.type===`fit`?e.key:void 0,children:e.label},e.key)),K&&f(`div`,{ref:ke,className:n.virtualListToggleWrapper,children:[d(`button`,{type:`button`,className:u(n.virtualListHeaderToggle,j?.headerToggle),style:M?.headerToggle,onClick:()=>J(e=>!e),"aria-label":`Toggle column visibility`,children:d(ne,{icon:re,style:M?.headerToggle})}),q>0&&d(`span`,{className:u(n.virtualListColumnChip,j?.columnChip),style:M?.columnChip,"data-column-hidden-count":q,"aria-label":`${q} columns hidden`,children:q}),Oe&&d(`div`,{className:u(n.virtualListTogglePopover,j?.togglePopover),style:M?.togglePopover,children:m.map(e=>d(t,{className:u(n.virtualListToggleItem,j?.toggleItem),style:M?.toggleItem,selected:De.has(e.key),onToggle:()=>Ae(e.key),cursorDefault:!1,children:e.label},e.key))})]})]}),pe?d(`div`,{className:n.virtualListLoadingFull,children:d(e,{className:n.virtualListSpinner})}):d(`div`,{className:u(n.virtualListBody,j?.body),style:{height:Ee,...M?.body},children:Q}),L.showLoadMoreSpinner&&d(`div`,{className:u(n.virtualListLoadingIndicator,j?.loadingIndicator),style:M?.loadingIndicator,children:d(e,{className:n.virtualListSpinner})})]})}var m=s.forwardRef(p);export{m as default};
|
|
2
|
+
//# sourceMappingURL=virtualList.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualList.mjs","names":[],"sources":["../../../../package/common/virtualList/virtualList.tsx"],"sourcesContent":["import React, { useMemo, useCallback, useImperativeHandle } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faGear } from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './virtualList.module.pcss';\nimport SpinnerLoading from '../loading/spinnerLoading';\nimport Checkbox from '../checkbox';\nimport VirtualRow from './virtualRow';\nimport { useVirtualWindow } from './useVirtualWindow';\nimport { useSelection } from './useSelection';\nimport { useColumns } from './useColumns';\nimport { useRowDrag } from './useRowDrag';\nimport type { VirtualListProps, VirtualListHandle } from './virtualList.types';\n\n// Pure helpers live in ./virtualList.utils; re-exported here so existing\n// imports (and unit tests) keep working against the component entry point.\nexport {\n buildOffsets,\n findStartIndex,\n getVisibleRange,\n resolveReorderTarget,\n resolveTreeDropTarget,\n lastDescendantIndex,\n buildColumnTemplate,\n} from './virtualList.utils';\n\n// ─── Orchestrator ─────────────────────────────────────────────────────────────\n// VirtualListInner wires four focused hooks together and renders. Each concern\n// lives in its own module:\n// useVirtualWindow — generic scroll / measurement / windowing (all modes)\n// useSelection — multi-row selection\n// useColumns — table mode: columns, visibility, persistence, fit widths\n// useRowDrag — reorder + tree drag-and-drop (mouse + touch)\n\nfunction VirtualListInner<T>({\n items,\n renderRow,\n columns,\n height = '100%',\n estimatedRowHeight = 40,\n overscan = 3,\n rowGap = 0,\n rowPadding,\n selectedKey,\n getItemKey,\n onRowClick,\n visibleColumnKeys,\n onVisibleColumnsChange,\n persistColumnsKey,\n showColumnToggle,\n onLoadMore,\n loadMoreThreshold = 100,\n isLoading = false,\n multiSelect = false,\n selectedKeys,\n onSelectionChange,\n reorderable = false,\n onReorder,\n longPressDelay = 400,\n treeReorder = false,\n getItemDepth,\n isGroup,\n onTreeDrop,\n treeIndentPx = 24,\n dragHandle = false,\n showDivider = true,\n rowHover = true,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: VirtualListProps<T>, ref: React.ForwardedRef<VirtualListHandle>) {\n const getKey = useCallback(\n (item: T, index: number): string | number => (getItemKey ? getItemKey(item, index) : index),\n [getItemKey],\n );\n const keys = useMemo(() => items.map((item, i) => getKey(item, i)), [items, getKey]);\n const depths = useMemo(\n () => (getItemDepth ? items.map((item, i) => getItemDepth(item, i)) : []),\n [items, getItemDepth],\n );\n const isGroupAt = useCallback(\n (i: number) => (isGroup ? isGroup(items[i], i) : false),\n [isGroup, items],\n );\n\n const win = useVirtualWindow<T>({\n items, keys, getItemKey, estimatedRowHeight, rowGap, overscan,\n onLoadMore, loadMoreThreshold,\n });\n const { rootRef, headerRef, rowObserver, keysRef, offsets, totalHeight, startIndex, endIndex } = win;\n\n const selection = useSelection<T>({ items, getKey, multiSelect, selectedKeys, onSelectionChange });\n const { effectiveSelectedKeys } = selection;\n\n const cols = useColumns<T>({\n columns, items, multiSelect, visibleColumnKeys, onVisibleColumnsChange, persistColumnsKey,\n showColumnToggle, rootRef, startIndex, endIndex,\n containerHeight: win.containerHeight, containerWidth: win.containerWidth,\n });\n const {\n hasColumns, visibleColumns, columnTemplate, shouldShowToggle, effectiveVisible, manuallyHiddenCount,\n toggleOpen, setToggleOpen, toggleRef, handleToggleColumn, recalculateColumns,\n } = cols;\n\n // Compose the forwarded handle from both hooks: scroll methods come from the\n // windowing engine, column controls from the column hook.\n useImperativeHandle(\n ref,\n () => ({ ...win.scrollApi, recalculateColumns }),\n [win.scrollApi, recalculateColumns],\n );\n\n const drag = useRowDrag({\n reorderable, treeReorder, onReorder, onTreeDrop, longPressDelay, dragHandle, treeIndentPx,\n keys, depths, isGroupAt, rootRef, keysRef,\n });\n\n const rowPaddingValue = typeof rowPadding === 'number' ? `${rowPadding}px` : rowPadding;\n\n const renderRowAt = (i: number) => {\n const item = items[i];\n const key = getKey(item, i);\n const isSelected = (selectedKey != null && key === selectedKey) || effectiveSelectedKeys.has(key);\n const dragProps = drag.getRowDragProps(i, key);\n\n return (\n <VirtualRow\n key={key}\n index={i}\n top={offsets[i]}\n padding={rowPaddingValue}\n columnTemplate={columnTemplate}\n isSelected={isSelected}\n showDivider={showDivider}\n hover={rowHover}\n onClick={() => {\n if (drag.consumeSuppressedClick()) return;\n onRowClick?.(item, i);\n }}\n observer={rowObserver}\n ariaRowIndex={hasColumns ? i + 2 : undefined}\n ariaPosInSet={hasColumns ? undefined : i + 1}\n ariaSetSize={hasColumns ? undefined : items.length}\n rowRole={hasColumns ? 'row' : 'listitem'}\n reserveToggleGutter={shouldShowToggle}\n {...dragProps}\n dropIndicatorClassName={classNames?.dropIndicator}\n dropIndicatorStyle={slotStyles?.dropIndicator}\n rowClassName={classNames?.row}\n rowStyle={slotStyles?.row}\n >\n {hasColumns\n ? <>\n {multiSelect && (\n <div\n className={cx(styles.virtualListSelectCell, classNames?.selectCell)}\n style={slotStyles?.selectCell}\n role=\"gridcell\"\n onClick={(e) => e.stopPropagation()}\n >\n <Checkbox\n selected={effectiveSelectedKeys.has(key)}\n onToggle={() => selection.handleRowSelect(key)}\n aria-label=\"Select row\"\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <div\n key={col.key}\n className={cx(styles.virtualListCell, classNames?.cell)}\n style={slotStyles?.cell}\n role=\"gridcell\"\n data-fit-key={col.width.type === 'fit' ? col.key : undefined}\n >\n {col.renderCell(item, i)}\n </div>\n ))}\n </>\n : renderRow?.(item, i)}\n </VirtualRow>\n );\n };\n\n const visibleRows: React.ReactNode[] = [];\n for (let i = startIndex; i <= endIndex; i++) visibleRows.push(renderRowAt(i));\n\n // Keep the row being touch-dragged mounted even if it scrolls out of the\n // window. Touch events are dispatched to the element under the finger at\n // touchstart; if that row unmounts, the browser stops delivering touchmove\n // and the drag freezes. Pinning its DOM node keeps the gesture alive.\n const draggedIndex = drag.draggingKey != null ? keys.indexOf(drag.draggingKey) : -1;\n if (draggedIndex >= 0 && (draggedIndex < startIndex || draggedIndex > endIndex)) {\n visibleRows.push(renderRowAt(draggedIndex));\n }\n\n return (\n <div\n {...rest}\n ref={rootRef}\n className={cx(styles.virtualList, drag.draggingKey != null && styles.virtualListReordering, className, classNames?.root)}\n style={{ height, ...style, ...slotStyles?.root }}\n onScroll={win.handleScroll}\n role={hasColumns ? 'grid' : 'list'}\n aria-rowcount={hasColumns ? items.length + 1 : undefined}\n >\n {hasColumns && (\n <div\n ref={headerRef}\n className={cx(styles.virtualListHeader, classNames?.header)}\n style={{ gridTemplateColumns: columnTemplate, ...(shouldShowToggle ? { paddingRight: 32 } : {}), ...slotStyles?.header }}\n role=\"row\"\n aria-rowindex={1}\n >\n {multiSelect && (\n <div\n className={cx(styles.virtualListSelectCell, classNames?.selectCell)}\n style={slotStyles?.selectCell}\n role=\"columnheader\"\n >\n <Checkbox\n selected={selection.allSelected || selection.someSelected}\n onToggle={selection.handleSelectAll}\n aria-label=\"Select all rows\"\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <div\n key={col.key}\n className={cx(styles.virtualListHeaderCell, classNames?.headerCell)}\n style={slotStyles?.headerCell}\n role=\"columnheader\"\n data-fit-key={col.width.type === 'fit' ? col.key : undefined}\n >\n {col.label}\n </div>\n ))}\n {shouldShowToggle && (\n <div ref={toggleRef} className={styles.virtualListToggleWrapper}>\n <button\n type=\"button\"\n className={cx(styles.virtualListHeaderToggle, classNames?.headerToggle)}\n style={slotStyles?.headerToggle}\n onClick={() => setToggleOpen((v) => !v)}\n aria-label=\"Toggle column visibility\"\n >\n <FontAwesomeIcon\n icon={faGear}\n style={slotStyles?.headerToggle as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n </button>\n {manuallyHiddenCount > 0 && (\n <span\n className={cx(styles.virtualListColumnChip, classNames?.columnChip)}\n style={slotStyles?.columnChip}\n data-column-hidden-count={manuallyHiddenCount}\n aria-label={`${manuallyHiddenCount} columns hidden`}\n >\n {manuallyHiddenCount}\n </span>\n )}\n {toggleOpen && (\n <div\n className={cx(styles.virtualListTogglePopover, classNames?.togglePopover)}\n style={slotStyles?.togglePopover}\n >\n {columns!.map((col) => (\n <Checkbox\n key={col.key}\n className={cx(styles.virtualListToggleItem, classNames?.toggleItem)}\n style={slotStyles?.toggleItem}\n selected={effectiveVisible.has(col.key)}\n onToggle={() => handleToggleColumn(col.key)}\n cursorDefault={false}\n >\n {col.label}\n </Checkbox>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )}\n {isLoading ? (\n <div className={styles.virtualListLoadingFull}>\n <SpinnerLoading className={styles.virtualListSpinner} />\n </div>\n ) : (\n <div\n className={cx(styles.virtualListBody, classNames?.body)}\n style={{ height: totalHeight, ...slotStyles?.body }}\n >\n {visibleRows}\n </div>\n )}\n {win.showLoadMoreSpinner && (\n <div\n className={cx(styles.virtualListLoadingIndicator, classNames?.loadingIndicator)}\n style={slotStyles?.loadingIndicator}\n >\n <SpinnerLoading className={styles.virtualListSpinner} />\n </div>\n )}\n </div>\n );\n}\n\n// forwardRef erases the generic, so cast back to a generic-preserving signature.\nconst VirtualList = React.forwardRef(VirtualListInner) as <T>(\n props: VirtualListProps<T> & { ref?: React.Ref<VirtualListHandle> },\n) => React.ReactElement | null;\n\nexport default VirtualList;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={virtualList:`virtualList_qBPNc`,"virtualList-drag-clone":`virtualList-drag-clone_artnC`,virtualListDragClone:`virtualList-drag-clone_artnC`,"virtualList-header":`virtualList-header_0Ellb`,virtualListHeader:`virtualList-header_0Ellb`,"virtualList-header-cell":`virtualList-header-cell_c8NGV`,virtualListHeaderCell:`virtualList-header-cell_c8NGV`,"virtualList-header-toggle":`virtualList-header-toggle_pYFxD`,virtualListHeaderToggle:`virtualList-header-toggle_pYFxD`,"virtualList-toggle-wrapper":`virtualList-toggle-wrapper_JP32M`,virtualListToggleWrapper:`virtualList-toggle-wrapper_JP32M`,"virtualList-toggle-popover":`virtualList-toggle-popover_gbpd7`,virtualListTogglePopover:`virtualList-toggle-popover_gbpd7`,"virtualList-toggle-item":`virtualList-toggle-item_5gu5d`,virtualListToggleItem:`virtualList-toggle-item_5gu5d`,"virtualList-column-chip":`virtualList-column-chip_nOqr6`,virtualListColumnChip:`virtualList-column-chip_nOqr6`,"virtualList-select-cell":`virtualList-select-cell_s9kAy`,virtualListSelectCell:`virtualList-select-cell_s9kAy`,"virtualList-body":`virtualList-body_k-fRr`,virtualListBody:`virtualList-body_k-fRr`,"virtualList-row":`virtualList-row_TTY50`,virtualListRow:`virtualList-row_TTY50`,"virtualList-row-no-divider":`virtualList-row-no-divider_Ct0gV`,virtualListRowNoDivider:`virtualList-row-no-divider_Ct0gV`,"virtualList-row-no-hover":`virtualList-row-no-hover_2d3mH`,virtualListRowNoHover:`virtualList-row-no-hover_2d3mH`,"virtualList-row-selected":`virtualList-row-selected_hwEN-`,virtualListRowSelected:`virtualList-row-selected_hwEN-`,"virtualList-row-draggable":`virtualList-row-draggable_I86ha`,virtualListRowDraggable:`virtualList-row-draggable_I86ha`,"virtualList-row-dragging":`virtualList-row-dragging_6T5tQ`,virtualListRowDragging:`virtualList-row-dragging_6T5tQ`,"virtualList-row-drop-inside":`virtualList-row-drop-inside_Uhi9n`,virtualListRowDropInside:`virtualList-row-drop-inside_Uhi9n`,"virtualList-drop-line":`virtualList-drop-line_EM-g4`,virtualListDropLine:`virtualList-drop-line_EM-g4`,"virtualList-drop-line-before":`virtualList-drop-line-before_n-0iZ`,virtualListDropLineBefore:`virtualList-drop-line-before_n-0iZ`,"virtualList-drop-line-after":`virtualList-drop-line-after_2dld-`,virtualListDropLineAfter:`virtualList-drop-line-after_2dld-`,"virtualList-reordering":`virtualList-reordering_Rt9E3`,virtualListReordering:`virtualList-reordering_Rt9E3`,"virtualList-cell":`virtualList-cell_H0zBv`,virtualListCell:`virtualList-cell_H0zBv`,"virtualList-loading-full":`virtualList-loading-full_wzZNM`,virtualListLoadingFull:`virtualList-loading-full_wzZNM`,"virtualList-loading-indicator":`virtualList-loading-indicator_EJced`,virtualListLoadingIndicator:`virtualList-loading-indicator_EJced`,"virtualList-spinner":`virtualList-spinner_apClW`,virtualListSpinner:`virtualList-spinner_apClW`};export{e as default};
|
|
2
|
+
//# sourceMappingURL=virtualList.module.mjs.map
|