@nofinite/nui 1.1.1 → 2.0.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/README.md +61 -48
- package/dist/components/accordion/Accordion.cjs +1 -1
- package/dist/components/accordion/Accordion.cjs.map +1 -1
- package/dist/components/accordion/Accordion.js +64 -43
- package/dist/components/accordion/Accordion.js.map +1 -1
- package/dist/components/alert/Alert.cjs +1 -1
- package/dist/components/alert/Alert.cjs.map +1 -1
- package/dist/components/alert/Alert.js +39 -25
- package/dist/components/alert/Alert.js.map +1 -1
- package/dist/components/avatar/Avatar.cjs +1 -1
- package/dist/components/avatar/Avatar.cjs.map +1 -1
- package/dist/components/avatar/Avatar.js +58 -44
- package/dist/components/avatar/Avatar.js.map +1 -1
- package/dist/components/avatar/AvatarGroup.cjs +1 -1
- package/dist/components/avatar/AvatarGroup.cjs.map +1 -1
- package/dist/components/avatar/AvatarGroup.js +34 -25
- package/dist/components/avatar/AvatarGroup.js.map +1 -1
- package/dist/components/badge/Badge.cjs +1 -1
- package/dist/components/badge/Badge.cjs.map +1 -1
- package/dist/components/badge/Badge.js +43 -68
- package/dist/components/badge/Badge.js.map +1 -1
- package/dist/components/badge/BadgeGroup.cjs +1 -1
- package/dist/components/badge/BadgeGroup.cjs.map +1 -1
- package/dist/components/badge/BadgeGroup.js +20 -10
- package/dist/components/badge/BadgeGroup.js.map +1 -1
- package/dist/components/breadcrumbs/Breadcrumbs.cjs +1 -1
- package/dist/components/breadcrumbs/Breadcrumbs.cjs.map +1 -1
- package/dist/components/breadcrumbs/Breadcrumbs.js +59 -39
- package/dist/components/breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/components/button/Button.cjs +1 -1
- package/dist/components/button/Button.cjs.map +1 -1
- package/dist/components/button/Button.js +52 -17
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/card/Card.cjs +1 -1
- package/dist/components/card/Card.cjs.map +1 -1
- package/dist/components/card/Card.js +44 -41
- package/dist/components/card/Card.js.map +1 -1
- package/dist/components/checkbox/Checkbox.cjs +1 -1
- package/dist/components/checkbox/Checkbox.cjs.map +1 -1
- package/dist/components/checkbox/Checkbox.js +59 -40
- package/dist/components/checkbox/Checkbox.js.map +1 -1
- package/dist/components/chip/Chip.cjs +1 -1
- package/dist/components/chip/Chip.cjs.map +1 -1
- package/dist/components/chip/Chip.js +67 -47
- package/dist/components/chip/Chip.js.map +1 -1
- package/dist/components/combobox/Combobox.cjs +1 -1
- package/dist/components/combobox/Combobox.cjs.map +1 -1
- package/dist/components/combobox/Combobox.js +123 -108
- package/dist/components/combobox/Combobox.js.map +1 -1
- package/dist/components/commandpalette/CommandPalette.cjs +1 -1
- package/dist/components/commandpalette/CommandPalette.cjs.map +1 -1
- package/dist/components/commandpalette/CommandPalette.js +96 -73
- package/dist/components/commandpalette/CommandPalette.js.map +1 -1
- package/dist/components/contextmenu/ContextMenu.cjs +1 -1
- package/dist/components/contextmenu/ContextMenu.cjs.map +1 -1
- package/dist/components/contextmenu/ContextMenu.js +79 -58
- package/dist/components/contextmenu/ContextMenu.js.map +1 -1
- package/dist/components/datagrid/DataGrid.cjs +1 -1
- package/dist/components/datagrid/DataGrid.cjs.map +1 -1
- package/dist/components/datagrid/DataGrid.js +184 -202
- package/dist/components/datagrid/DataGrid.js.map +1 -1
- package/dist/components/datepicker/DatePicker.cjs +1 -1
- package/dist/components/datepicker/DatePicker.cjs.map +1 -1
- package/dist/components/datepicker/DatePicker.js +197 -164
- package/dist/components/datepicker/DatePicker.js.map +1 -1
- package/dist/components/daterangepicker/DateRangePicker.cjs +1 -1
- package/dist/components/daterangepicker/DateRangePicker.cjs.map +1 -1
- package/dist/components/daterangepicker/DateRangePicker.js +254 -213
- package/dist/components/daterangepicker/DateRangePicker.js.map +1 -1
- package/dist/components/dialog/DialogProvider.cjs +2 -0
- package/dist/components/dialog/DialogProvider.cjs.map +1 -0
- package/dist/components/dialog/DialogProvider.js +71 -0
- package/dist/components/dialog/DialogProvider.js.map +1 -0
- package/dist/components/dialog/dialogStore.cjs +2 -0
- package/dist/components/dialog/dialogStore.cjs.map +1 -0
- package/dist/components/dialog/dialogStore.js +60 -0
- package/dist/components/dialog/dialogStore.js.map +1 -0
- package/dist/components/drawer/Drawer.cjs +1 -1
- package/dist/components/drawer/Drawer.cjs.map +1 -1
- package/dist/components/drawer/Drawer.js +69 -47
- package/dist/components/drawer/Drawer.js.map +1 -1
- package/dist/components/dropdown/Dropdown.cjs +1 -1
- package/dist/components/dropdown/Dropdown.cjs.map +1 -1
- package/dist/components/dropdown/Dropdown.js +134 -108
- package/dist/components/dropdown/Dropdown.js.map +1 -1
- package/dist/components/fileuploader/FileUploader.cjs +1 -1
- package/dist/components/fileuploader/FileUploader.cjs.map +1 -1
- package/dist/components/fileuploader/FileUploader.js +96 -61
- package/dist/components/fileuploader/FileUploader.js.map +1 -1
- package/dist/components/hovercard/HoverCard.cjs +1 -1
- package/dist/components/hovercard/HoverCard.cjs.map +1 -1
- package/dist/components/hovercard/HoverCard.js +124 -69
- package/dist/components/hovercard/HoverCard.js.map +1 -1
- package/dist/components/input/Input.cjs +1 -1
- package/dist/components/input/Input.cjs.map +1 -1
- package/dist/components/input/Input.js +62 -37
- package/dist/components/input/Input.js.map +1 -1
- package/dist/components/layout/Container.cjs +1 -1
- package/dist/components/layout/Container.cjs.map +1 -1
- package/dist/components/layout/Container.js +21 -30
- package/dist/components/layout/Container.js.map +1 -1
- package/dist/components/layout/Flex.cjs +1 -1
- package/dist/components/layout/Flex.cjs.map +1 -1
- package/dist/components/layout/Flex.js +36 -19
- package/dist/components/layout/Flex.js.map +1 -1
- package/dist/components/layout/Grid.cjs +1 -1
- package/dist/components/layout/Grid.cjs.map +1 -1
- package/dist/components/layout/Grid.js +30 -18
- package/dist/components/layout/Grid.js.map +1 -1
- package/dist/components/link/Link.cjs +2 -0
- package/dist/components/link/Link.cjs.map +1 -0
- package/dist/components/link/Link.js +41 -0
- package/dist/components/link/Link.js.map +1 -0
- package/dist/components/megamenu/MegaMenu.cjs +1 -1
- package/dist/components/megamenu/MegaMenu.cjs.map +1 -1
- package/dist/components/megamenu/MegaMenu.js +107 -38
- package/dist/components/megamenu/MegaMenu.js.map +1 -1
- package/dist/components/modal/Modal.cjs +1 -1
- package/dist/components/modal/Modal.cjs.map +1 -1
- package/dist/components/modal/Modal.js +91 -83
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/multiselect/MultiSelect.cjs +2 -0
- package/dist/components/multiselect/MultiSelect.cjs.map +1 -0
- package/dist/components/multiselect/MultiSelect.js +176 -0
- package/dist/components/multiselect/MultiSelect.js.map +1 -0
- package/dist/components/nuiprovider/NUIProvider.cjs +2 -0
- package/dist/components/nuiprovider/NUIProvider.cjs.map +1 -0
- package/dist/components/nuiprovider/NUIProvider.js +36 -0
- package/dist/components/nuiprovider/NUIProvider.js.map +1 -0
- package/dist/components/pagination/Pagination.cjs +1 -1
- package/dist/components/pagination/Pagination.cjs.map +1 -1
- package/dist/components/pagination/Pagination.js +74 -41
- package/dist/components/pagination/Pagination.js.map +1 -1
- package/dist/components/popover/Popover.cjs +1 -1
- package/dist/components/popover/Popover.cjs.map +1 -1
- package/dist/components/popover/Popover.js +99 -100
- package/dist/components/popover/Popover.js.map +1 -1
- package/dist/components/progress/Progress.cjs +1 -1
- package/dist/components/progress/Progress.cjs.map +1 -1
- package/dist/components/progress/Progress.js +44 -22
- package/dist/components/progress/Progress.js.map +1 -1
- package/dist/components/radiogroup/RadioGroup.cjs +1 -1
- package/dist/components/radiogroup/RadioGroup.cjs.map +1 -1
- package/dist/components/radiogroup/RadioGroup.js +69 -74
- package/dist/components/radiogroup/RadioGroup.js.map +1 -1
- package/dist/components/rating/Rating.cjs +1 -1
- package/dist/components/rating/Rating.cjs.map +1 -1
- package/dist/components/rating/Rating.js +72 -33
- package/dist/components/rating/Rating.js.map +1 -1
- package/dist/components/resizable/Resizable.cjs +2 -0
- package/dist/components/resizable/Resizable.cjs.map +1 -0
- package/dist/components/resizable/Resizable.js +134 -0
- package/dist/components/resizable/Resizable.js.map +1 -0
- package/dist/components/select/Select.cjs +1 -1
- package/dist/components/select/Select.cjs.map +1 -1
- package/dist/components/select/Select.js +114 -113
- package/dist/components/select/Select.js.map +1 -1
- package/dist/components/skeleton/Skeleton.cjs +1 -1
- package/dist/components/skeleton/Skeleton.cjs.map +1 -1
- package/dist/components/skeleton/Skeleton.js +90 -67
- package/dist/components/skeleton/Skeleton.js.map +1 -1
- package/dist/components/slider/Slider.cjs +1 -1
- package/dist/components/slider/Slider.cjs.map +1 -1
- package/dist/components/slider/Slider.js +85 -82
- package/dist/components/slider/Slider.js.map +1 -1
- package/dist/components/spinner/Spinner.cjs +1 -1
- package/dist/components/spinner/Spinner.cjs.map +1 -1
- package/dist/components/spinner/Spinner.js +60 -17
- package/dist/components/spinner/Spinner.js.map +1 -1
- package/dist/components/stepper/Stepper.cjs +1 -5
- package/dist/components/stepper/Stepper.cjs.map +1 -1
- package/dist/components/stepper/Stepper.js +65 -39
- package/dist/components/stepper/Stepper.js.map +1 -1
- package/dist/components/switch/Switch.cjs +1 -1
- package/dist/components/switch/Switch.cjs.map +1 -1
- package/dist/components/switch/Switch.js +89 -62
- package/dist/components/switch/Switch.js.map +1 -1
- package/dist/components/table/Table.cjs +1 -1
- package/dist/components/table/Table.cjs.map +1 -1
- package/dist/components/table/Table.js +62 -35
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/tabs/Tabs.cjs +1 -1
- package/dist/components/tabs/Tabs.cjs.map +1 -1
- package/dist/components/tabs/Tabs.js +110 -50
- package/dist/components/tabs/Tabs.js.map +1 -1
- package/dist/components/textarea/Textarea.cjs +1 -1
- package/dist/components/textarea/Textarea.cjs.map +1 -1
- package/dist/components/textarea/Textarea.js +63 -58
- package/dist/components/textarea/Textarea.js.map +1 -1
- package/dist/components/timepicker/TimePicker.cjs +2 -0
- package/dist/components/timepicker/TimePicker.cjs.map +1 -0
- package/dist/components/timepicker/TimePicker.js +159 -0
- package/dist/components/timepicker/TimePicker.js.map +1 -0
- package/dist/components/timerangepicker/TimeRangePicker.cjs +2 -0
- package/dist/components/timerangepicker/TimeRangePicker.cjs.map +1 -0
- package/dist/components/timerangepicker/TimeRangePicker.js +208 -0
- package/dist/components/timerangepicker/TimeRangePicker.js.map +1 -0
- package/dist/components/toast/Toast.cjs +1 -1
- package/dist/components/toast/Toast.cjs.map +1 -1
- package/dist/components/toast/Toast.js +91 -38
- package/dist/components/toast/Toast.js.map +1 -1
- package/dist/components/tooltip/Tooltip.cjs +1 -1
- package/dist/components/tooltip/Tooltip.cjs.map +1 -1
- package/dist/components/tooltip/Tooltip.js +72 -56
- package/dist/components/tooltip/Tooltip.js.map +1 -1
- package/dist/components/treeview/TreeView.cjs +1 -1
- package/dist/components/treeview/TreeView.cjs.map +1 -1
- package/dist/components/treeview/TreeView.js +120 -90
- package/dist/components/treeview/TreeView.js.map +1 -1
- package/dist/components/virtuallist/VirtualList.cjs +1 -1
- package/dist/components/virtuallist/VirtualList.cjs.map +1 -1
- package/dist/components/virtuallist/VirtualList.js +52 -34
- package/dist/components/virtuallist/VirtualList.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -0
- package/dist/index.js +118 -107
- package/dist/index.js.map +1 -1
- package/dist/package.json +49 -6
- package/dist/types/components/accordion/Accordion.d.ts +7 -3
- package/dist/types/components/accordion/Accordion.d.ts.map +1 -1
- package/dist/types/components/alert/Alert.d.ts +18 -5
- package/dist/types/components/alert/Alert.d.ts.map +1 -1
- package/dist/types/components/avatar/Avatar.d.ts +12 -8
- package/dist/types/components/avatar/Avatar.d.ts.map +1 -1
- package/dist/types/components/avatar/AvatarGroup.d.ts +11 -4
- package/dist/types/components/avatar/AvatarGroup.d.ts.map +1 -1
- package/dist/types/components/badge/Badge.d.ts +19 -11
- package/dist/types/components/badge/Badge.d.ts.map +1 -1
- package/dist/types/components/badge/BadgeGroup.d.ts +7 -4
- package/dist/types/components/badge/BadgeGroup.d.ts.map +1 -1
- package/dist/types/components/breadcrumbs/Breadcrumbs.d.ts +14 -6
- package/dist/types/components/breadcrumbs/Breadcrumbs.d.ts.map +1 -1
- package/dist/types/components/button/Button.d.ts +25 -10
- package/dist/types/components/button/Button.d.ts.map +1 -1
- package/dist/types/components/card/Card.d.ts +12 -21
- package/dist/types/components/card/Card.d.ts.map +1 -1
- package/dist/types/components/checkbox/Checkbox.d.ts +12 -7
- package/dist/types/components/checkbox/Checkbox.d.ts.map +1 -1
- package/dist/types/components/chip/Chip.d.ts +14 -11
- package/dist/types/components/chip/Chip.d.ts.map +1 -1
- package/dist/types/components/combobox/Combobox.d.ts +15 -4
- package/dist/types/components/combobox/Combobox.d.ts.map +1 -1
- package/dist/types/components/commandpalette/CommandPalette.d.ts +12 -3
- package/dist/types/components/commandpalette/CommandPalette.d.ts.map +1 -1
- package/dist/types/components/contextmenu/ContextMenu.d.ts +14 -6
- package/dist/types/components/contextmenu/ContextMenu.d.ts.map +1 -1
- package/dist/types/components/datagrid/DataGrid.d.ts +16 -4
- package/dist/types/components/datagrid/DataGrid.d.ts.map +1 -1
- package/dist/types/components/datepicker/DatePicker.d.ts +13 -1
- package/dist/types/components/datepicker/DatePicker.d.ts.map +1 -1
- package/dist/types/components/daterangepicker/DateRangePicker.d.ts +3 -1
- package/dist/types/components/daterangepicker/DateRangePicker.d.ts.map +1 -1
- package/dist/types/components/dialog/DialogProvider.d.ts +2 -0
- package/dist/types/components/dialog/DialogProvider.d.ts.map +1 -0
- package/dist/types/components/dialog/dialogStore.d.ts +42 -0
- package/dist/types/components/dialog/dialogStore.d.ts.map +1 -0
- package/dist/types/components/drawer/Drawer.d.ts +18 -4
- package/dist/types/components/drawer/Drawer.d.ts.map +1 -1
- package/dist/types/components/dropdown/Dropdown.d.ts +21 -16
- package/dist/types/components/dropdown/Dropdown.d.ts.map +1 -1
- package/dist/types/components/fileuploader/FileUploader.d.ts +22 -3
- package/dist/types/components/fileuploader/FileUploader.d.ts.map +1 -1
- package/dist/types/components/hovercard/HoverCard.d.ts +45 -5
- package/dist/types/components/hovercard/HoverCard.d.ts.map +1 -1
- package/dist/types/components/input/Input.d.ts +20 -10
- package/dist/types/components/input/Input.d.ts.map +1 -1
- package/dist/types/components/layout/Container.d.ts +8 -4
- package/dist/types/components/layout/Container.d.ts.map +1 -1
- package/dist/types/components/layout/Flex.d.ts +27 -10
- package/dist/types/components/layout/Flex.d.ts.map +1 -1
- package/dist/types/components/layout/Grid.d.ts +11 -5
- package/dist/types/components/layout/Grid.d.ts.map +1 -1
- package/dist/types/components/link/Link.d.ts +22 -0
- package/dist/types/components/link/Link.d.ts.map +1 -0
- package/dist/types/components/megamenu/MegaMenu.d.ts +8 -11
- package/dist/types/components/megamenu/MegaMenu.d.ts.map +1 -1
- package/dist/types/components/modal/Modal.d.ts +8 -7
- package/dist/types/components/modal/Modal.d.ts.map +1 -1
- package/dist/types/components/multiselect/MultiSelect.d.ts +33 -0
- package/dist/types/components/multiselect/MultiSelect.d.ts.map +1 -0
- package/dist/types/components/nuiprovider/NUIProvider.d.ts +29 -0
- package/dist/types/components/nuiprovider/NUIProvider.d.ts.map +1 -0
- package/dist/types/components/pagination/Pagination.d.ts +17 -3
- package/dist/types/components/pagination/Pagination.d.ts.map +1 -1
- package/dist/types/components/popover/Popover.d.ts +54 -16
- package/dist/types/components/popover/Popover.d.ts.map +1 -1
- package/dist/types/components/progress/Progress.d.ts +17 -7
- package/dist/types/components/progress/Progress.d.ts.map +1 -1
- package/dist/types/components/radiogroup/RadioGroup.d.ts +15 -10
- package/dist/types/components/radiogroup/RadioGroup.d.ts.map +1 -1
- package/dist/types/components/rating/Rating.d.ts +24 -10
- package/dist/types/components/rating/Rating.d.ts.map +1 -1
- package/dist/types/components/resizable/Resizable.d.ts +24 -0
- package/dist/types/components/resizable/Resizable.d.ts.map +1 -0
- package/dist/types/components/select/Select.d.ts +17 -8
- package/dist/types/components/select/Select.d.ts.map +1 -1
- package/dist/types/components/skeleton/Skeleton.d.ts +37 -36
- package/dist/types/components/skeleton/Skeleton.d.ts.map +1 -1
- package/dist/types/components/slider/Slider.d.ts +15 -4
- package/dist/types/components/slider/Slider.d.ts.map +1 -1
- package/dist/types/components/spinner/Spinner.d.ts +14 -4
- package/dist/types/components/spinner/Spinner.d.ts.map +1 -1
- package/dist/types/components/stepper/Stepper.d.ts +17 -3
- package/dist/types/components/stepper/Stepper.d.ts.map +1 -1
- package/dist/types/components/switch/Switch.d.ts +20 -5
- package/dist/types/components/switch/Switch.d.ts.map +1 -1
- package/dist/types/components/table/Table.d.ts +24 -4
- package/dist/types/components/table/Table.d.ts.map +1 -1
- package/dist/types/components/tabs/Tabs.d.ts +25 -12
- package/dist/types/components/tabs/Tabs.d.ts.map +1 -1
- package/dist/types/components/textarea/Textarea.d.ts +8 -5
- package/dist/types/components/textarea/Textarea.d.ts.map +1 -1
- package/dist/types/components/timepicker/TimePicker.d.ts +26 -0
- package/dist/types/components/timepicker/TimePicker.d.ts.map +1 -0
- package/dist/types/components/timerangepicker/TimeRangePicker.d.ts +32 -0
- package/dist/types/components/timerangepicker/TimeRangePicker.d.ts.map +1 -0
- package/dist/types/components/toast/Toast.d.ts +23 -7
- package/dist/types/components/toast/Toast.d.ts.map +1 -1
- package/dist/types/components/tooltip/Tooltip.d.ts +13 -2
- package/dist/types/components/tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/components/treeview/TreeView.d.ts +20 -6
- package/dist/types/components/treeview/TreeView.d.ts.map +1 -1
- package/dist/types/components/virtuallist/VirtualList.d.ts +12 -16
- package/dist/types/components/virtuallist/VirtualList.d.ts.map +1 -1
- package/dist/types/index.d.ts +8 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/utils/cn/cn.d.ts +19 -0
- package/dist/types/utils/cn/cn.d.ts.map +1 -0
- package/dist/types/utils/generateid/generateId.d.ts +7 -0
- package/dist/types/utils/generateid/generateId.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/inertmanager/inertManager.d.ts +13 -0
- package/dist/types/utils/inertmanager/inertManager.d.ts.map +1 -1
- package/dist/types/utils/keyboardnav/keyboardNav.d.ts +17 -6
- package/dist/types/utils/keyboardnav/keyboardNav.d.ts.map +1 -1
- package/dist/types/utils/onclickoutside/onClickOutside.d.ts +9 -1
- package/dist/types/utils/onclickoutside/onClickOutside.d.ts.map +1 -1
- package/dist/types/utils/portal/portal.d.ts +14 -1
- package/dist/types/utils/portal/portal.d.ts.map +1 -1
- package/dist/types/utils/restorefocus/restoreFocus.d.ts +8 -4
- package/dist/types/utils/restorefocus/restoreFocus.d.ts.map +1 -1
- package/dist/types/utils/scrolllock/scrollLock.d.ts +10 -2
- package/dist/types/utils/scrolllock/scrollLock.d.ts.map +1 -1
- package/dist/types/utils/slot/slot.d.ts +12 -0
- package/dist/types/utils/slot/slot.d.ts.map +1 -0
- package/dist/types/utils/trapfocus/trapFocus.d.ts +6 -2
- package/dist/types/utils/trapfocus/trapFocus.d.ts.map +1 -1
- package/dist/utils/cn/cn.cjs +2 -0
- package/dist/utils/cn/cn.cjs.map +1 -0
- package/dist/utils/cn/cn.js +21 -0
- package/dist/utils/cn/cn.js.map +1 -0
- package/dist/utils/inertmanager/inertManager.cjs.map +1 -1
- package/dist/utils/inertmanager/inertManager.js.map +1 -1
- package/dist/utils/onclickoutside/onClickOutside.cjs +1 -1
- package/dist/utils/onclickoutside/onClickOutside.cjs.map +1 -1
- package/dist/utils/onclickoutside/onClickOutside.js +10 -6
- package/dist/utils/onclickoutside/onClickOutside.js.map +1 -1
- package/dist/utils/portal/portal.cjs.map +1 -1
- package/dist/utils/portal/portal.js.map +1 -1
- package/dist/utils/restorefocus/restoreFocus.cjs.map +1 -1
- package/dist/utils/restorefocus/restoreFocus.js.map +1 -1
- package/dist/utils/scrolllock/scrollLock.cjs.map +1 -1
- package/dist/utils/scrolllock/scrollLock.js +7 -0
- package/dist/utils/scrolllock/scrollLock.js.map +1 -1
- package/dist/utils/slot/slot.cjs +2 -0
- package/dist/utils/slot/slot.cjs.map +1 -0
- package/dist/utils/slot/slot.js +57 -0
- package/dist/utils/slot/slot.js.map +1 -0
- package/dist/utils/trapfocus/trapFocus.cjs.map +1 -1
- package/dist/utils/trapfocus/trapFocus.js.map +1 -1
- package/package.json +49 -6
- package/dist/components/layout/HStack.cjs +0 -2
- package/dist/components/layout/HStack.cjs.map +0 -1
- package/dist/components/layout/HStack.js +0 -9
- package/dist/components/layout/HStack.js.map +0 -1
- package/dist/components/layout/Stack.cjs +0 -2
- package/dist/components/layout/Stack.cjs.map +0 -1
- package/dist/components/layout/Stack.js +0 -9
- package/dist/components/layout/Stack.js.map +0 -1
- package/dist/styles/nui.css +0 -1
- package/dist/theme/NUIProvider.cjs +0 -2
- package/dist/theme/NUIProvider.cjs.map +0 -1
- package/dist/theme/NUIProvider.js +0 -34
- package/dist/theme/NUIProvider.js.map +0 -1
- package/dist/theme/useTheme.cjs +0 -2
- package/dist/theme/useTheme.cjs.map +0 -1
- package/dist/theme/useTheme.js +0 -9
- package/dist/theme/useTheme.js.map +0 -1
- package/dist/types/components/layout/HStack.d.ts +0 -8
- package/dist/types/components/layout/HStack.d.ts.map +0 -1
- package/dist/types/components/layout/Stack.d.ts +0 -8
- package/dist/types/components/layout/Stack.d.ts.map +0 -1
- package/dist/types/theme/NUIProvider.d.ts +0 -14
- package/dist/types/theme/NUIProvider.d.ts.map +0 -1
- package/dist/types/theme/useTheme.d.ts +0 -11
- package/dist/types/theme/useTheme.d.ts.map +0 -1
- package/dist/utils/generateid/generateId.cjs +0 -2
- package/dist/utils/generateid/generateId.cjs.map +0 -1
- package/dist/utils/generateid/generateId.js +0 -7
- package/dist/utils/generateid/generateId.js.map +0 -1
- package/dist/utils/keyboardnav/keyboardNav.cjs +0 -2
- package/dist/utils/keyboardnav/keyboardNav.cjs.map +0 -1
- package/dist/utils/keyboardnav/keyboardNav.js +0 -10
- package/dist/utils/keyboardnav/keyboardNav.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MultiSelect.cjs","sources":["../../../src/components/multiselect/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport React, {\n useState,\n useRef,\n useEffect,\n useCallback,\n useLayoutEffect,\n KeyboardEvent,\n forwardRef,\n} from 'react';\nimport { cn } from '../../utils';\nimport { Portal, onClickOutside, restoreFocus } from '../../utils';\nimport './MultiSelect.css';\n\n/* ============================================================\n * Types\n * ============================================================ */\n\nexport type MultiSelectOption = {\n value: string;\n label: React.ReactNode;\n disabled?: boolean;\n};\n\nexport interface MultiSelectProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange'> {\n /** Array of available options */\n options: MultiSelectOption[];\n /** Controlled state for selected values */\n value?: string[]; \n /** Uncontrolled initial state for selected values */\n defaultValue?: string[]; \n /** Callback fired when the selection changes */\n onChange?: (value: string[]) => void;\n /** Text displayed when no options are selected */\n placeholder?: string;\n /** Name attribute applied to hidden inputs for native form submission */\n name?: string; \n /** Toggles error styling */\n error?: boolean;\n /** Number of tags to render before collapsing into a summary string (e.g., \"3 selected\") */\n maxTags?: number; \n}\n\n/* Helper: find next enabled index given direction */\nfunction findNextEnabled(options: MultiSelectOption[], start: number, direction: 1 | -1) {\n const len = options.length;\n let i = start;\n for (let step = 0; step < len; step++) {\n i = (i + direction + len) % len;\n if (!options[i].disabled) return i;\n }\n return -1;\n}\n\n/* ============================================================\n * Component\n * ============================================================ */\n\n/**\n * MultiSelect Component\n * * A custom, WAI-ARIA compliant dropdown for selecting multiple options.\n * * Architecture Note: Unlike a standard Select, the dropdown list intentionally \n * remains open after a selection is made, allowing the user to quickly select \n * multiple items without repeatedly reopening the menu.\n */\nexport const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(({\n options,\n value,\n defaultValue,\n onChange,\n placeholder = 'Select multiple...',\n disabled = false,\n error = false,\n name,\n id,\n className,\n maxTags = 3,\n ...props\n}, ref) => {\n const isControlled = value !== undefined;\n const [internalValue, setInternalValue] = useState<string[]>(defaultValue || []);\n const selectedValues = isControlled ? value : internalValue;\n\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState<number>(() => options.findIndex((o) => !o.disabled));\n\n // Used for keyboard typeahead navigation\n const typeaheadRef = useRef({ buffer: '', lastTime: 0 });\n \n const triggerRef = useRef<HTMLButtonElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const activeOptionRef = useRef<HTMLDivElement | null>(null);\n\n const reactId = React.useId();\n const baseId = id ?? reactId;\n const listboxId = `${baseId}-listbox`;\n const labelId = `${baseId}-label`;\n\n /* ----------------------------------------------------\n Ref Merging\n ---------------------------------------------------- */\n const setTriggerRef = useCallback((node: HTMLButtonElement | null) => {\n triggerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n }, [ref]);\n\n /* ----------------------------------------------------\n Smart Position & Width Sync\n ---------------------------------------------------- */\n const [coords, setCoords] = useState({ top: -9999, left: -9999, width: 0 });\n\n const updatePosition = useCallback(() => {\n if (!triggerRef.current || !listRef.current) return;\n\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const listRect = listRef.current.getBoundingClientRect();\n const scrollY = window.scrollY;\n const scrollX = window.scrollX;\n\n let top = triggerRect.bottom + scrollY + 4;\n const left = triggerRect.left + scrollX;\n const width = triggerRect.width; \n\n // Viewport Bottom Collision & Hard Top Clamp\n const padding = 16;\n if (triggerRect.bottom + listRect.height + 4 > document.documentElement.clientHeight - padding) {\n top = triggerRect.top + scrollY - listRect.height - 4; \n if (top < padding + scrollY) top = padding + scrollY; \n }\n\n setCoords({ top, left, width });\n }, []);\n\n useLayoutEffect(() => {\n if (!open) return;\n updatePosition();\n window.addEventListener('resize', updatePosition);\n window.addEventListener('scroll', updatePosition, true);\n return () => {\n window.removeEventListener('resize', updatePosition);\n window.removeEventListener('scroll', updatePosition, true);\n };\n }, [open, updatePosition]);\n\n /* ----------------------------------------------------\n Focus & Scroll Management\n ---------------------------------------------------- */\n const closeList = useCallback(() => {\n setOpen(false);\n restoreFocus(triggerRef.current);\n }, []);\n\n useEffect(() => {\n if (!open) return;\n const cleanup = onClickOutside([listRef, triggerRef], () => setOpen(false));\n return cleanup;\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n // Reset active index to first non-disabled item when opened\n const idx = options.findIndex((o) => !o.disabled);\n setActiveIndex(idx >= 0 ? idx : -1);\n \n // Defer focus slightly to ensure Portal has rendered\n const timeoutId = setTimeout(() => listRef.current?.focus(), 10);\n return () => clearTimeout(timeoutId);\n }, [open, options]);\n\n // Auto-scroll to active item\n useEffect(() => {\n if (open && activeOptionRef.current) {\n activeOptionRef.current.scrollIntoView({ block: 'nearest' });\n }\n }, [activeIndex, open]);\n\n /* ----------------------------------------------------\n Event Handlers\n ---------------------------------------------------- */\n const toggleOption = useCallback((optValue: string) => {\n const isSelected = selectedValues.includes(optValue);\n const nextValues = isSelected \n ? selectedValues.filter(v => v !== optValue) \n : [...selectedValues, optValue];\n\n if (!isControlled) setInternalValue(nextValues);\n onChange?.(nextValues);\n \n // WAI-ARIA Standard: Do not close the dropdown for Multi-Select!\n // Refocus the list so the user can keep navigating via keyboard.\n listRef.current?.focus();\n }, [isControlled, selectedValues, onChange]);\n\n const onTriggerKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n if (disabled) return;\n if (['ArrowDown', 'ArrowUp', ' ', 'Enter'].includes(e.key)) {\n e.preventDefault();\n setOpen(true);\n }\n };\n\n const onListKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n const key = e.key;\n if (key === 'ArrowDown') {\n e.preventDefault();\n const next = findNextEnabled(options, activeIndex, 1);\n if (next >= 0) setActiveIndex(next);\n } else if (key === 'ArrowUp') {\n e.preventDefault();\n const prev = findNextEnabled(options, activeIndex, -1);\n if (prev >= 0) setActiveIndex(prev);\n } else if (key === 'Home') {\n e.preventDefault();\n const first = options.findIndex((o) => !o.disabled);\n if (first >= 0) setActiveIndex(first);\n } else if (key === 'End') {\n e.preventDefault();\n const last = options.length - 1 - [...options].reverse().findIndex((o) => !o.disabled);\n if (last >= 0) setActiveIndex(last);\n } else if (key === 'Enter' || key === ' ') {\n e.preventDefault();\n if (activeIndex >= 0) {\n const opt = options[activeIndex];\n if (!opt.disabled) toggleOption(opt.value);\n }\n } else if (key === 'Escape') {\n e.preventDefault();\n closeList();\n } else if (key.length === 1 && key.match(/\\S/)) {\n // Typeahead logic\n const now = Date.now();\n if (now - typeaheadRef.current.lastTime > 700) typeaheadRef.current.buffer = '';\n typeaheadRef.current.buffer += key.toLowerCase();\n typeaheadRef.current.lastTime = now;\n\n const buf = typeaheadRef.current.buffer;\n const start = activeIndex >= 0 ? activeIndex + 1 : 0;\n const len = options.length;\n for (let i = 0; i < len; i++) {\n const idx = (start + i) % len;\n const lab = String(options[idx].label).toLowerCase();\n if (!options[idx].disabled && lab.startsWith(buf)) {\n setActiveIndex(idx);\n break;\n }\n }\n }\n };\n\n /* ----------------------------------------------------\n Trigger Rendering Logic\n ---------------------------------------------------- */\n const renderTriggerContent = () => {\n if (selectedValues.length === 0) {\n return <span className=\"nui-multiselect-placeholder\">{placeholder}</span>;\n }\n\n if (selectedValues.length > maxTags) {\n return (\n <span className=\"nui-multiselect-summary\">\n {selectedValues.length} items selected\n </span>\n );\n }\n\n // Render individual tags\n return (\n <div className=\"nui-multiselect-tags\">\n {selectedValues.map(val => {\n const label = options.find(o => o.value === val)?.label ?? val;\n return (\n <span key={val} className=\"nui-multiselect-tag\">\n {label}\n </span>\n );\n })}\n </div>\n );\n };\n\n /* ----------------------------------------------------\n Render\n ---------------------------------------------------- */\n return (\n <div className={cn(\"nui-multiselect-root\", className)}>\n \n {/* Hidden inputs for native form submission */}\n {name && selectedValues.map((val) => (\n <input key={val} type=\"hidden\" name={name} value={val} />\n ))}\n\n <button\n ref={setTriggerRef}\n id={labelId}\n type=\"button\"\n className={cn(\"nui-multiselect-trigger\", error && \"error\")}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={open ? listboxId : undefined}\n aria-disabled={disabled || undefined}\n onClick={() => !disabled && setOpen((s) => !s)}\n onKeyDown={onTriggerKeyDown}\n disabled={disabled}\n {...props}\n >\n <div className=\"nui-multiselect-value-container\">\n {renderTriggerContent()}\n </div>\n <svg className=\"nui-multiselect-chevron\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </button>\n\n {open && (\n <Portal>\n <div\n id={listboxId}\n ref={listRef}\n className=\"nui-multiselect-listbox\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n aria-labelledby={labelId}\n tabIndex={0}\n style={{ top: coords.top, left: coords.left, width: coords.width }}\n onKeyDown={onListKeyDown}\n >\n {options.map((opt, i) => {\n const isSelected = selectedValues.includes(opt.value);\n const isActive = activeIndex === i;\n \n return (\n <div\n key={opt.value}\n ref={isActive ? activeOptionRef : null}\n id={`${listboxId}-option-${i}`}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={opt.disabled || undefined}\n className={cn(\n \"nui-multiselect-option\",\n isActive && \"active\",\n isSelected && \"selected\",\n opt.disabled && \"disabled\"\n )}\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()} \n onClick={() => !opt.disabled && toggleOption(opt.value)}\n onMouseEnter={() => !opt.disabled && setActiveIndex(i)}\n >\n \n {/* Custom Checkbox UI */}\n <div className={cn(\"nui-multiselect-checkbox\", isSelected && \"checked\")} aria-hidden=\"true\">\n {isSelected && (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n )}\n </div>\n\n <span className=\"nui-multiselect-option-label\">{opt.label}</span>\n </div>\n );\n })}\n </div>\n </Portal>\n )}\n </div>\n );\n});\nMultiSelect.displayName = 'MultiSelect';"],"names":["findNextEnabled","options","start","direction","len","i","step","MultiSelect","forwardRef","value","defaultValue","onChange","placeholder","disabled","error","name","id","className","maxTags","props","ref","isControlled","internalValue","setInternalValue","useState","selectedValues","open","setOpen","activeIndex","setActiveIndex","o","typeaheadRef","useRef","triggerRef","listRef","activeOptionRef","reactId","React","baseId","listboxId","labelId","setTriggerRef","useCallback","node","coords","setCoords","updatePosition","triggerRect","listRect","scrollY","scrollX","top","left","width","padding","useLayoutEffect","closeList","restoreFocus","useEffect","onClickOutside","idx","timeoutId","toggleOption","optValue","nextValues","v","onTriggerKeyDown","onListKeyDown","key","next","prev","first","last","opt","now","buf","lab","renderTriggerContent","jsx","jsxs","val","label","cn","s","Portal","isSelected","isActive","e"],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { jsxs as I, jsx as l } from "react/jsx-runtime";
|
|
2
|
+
import te, { forwardRef as ne, useState as N, useRef as E, useCallback as L, useLayoutEffect as ie, useEffect as B } from "react";
|
|
3
|
+
/* empty css */
|
|
4
|
+
import { restoreFocus as le } from "../../utils/restorefocus/restoreFocus.js";
|
|
5
|
+
import { onClickOutside as re } from "../../utils/onclickoutside/onClickOutside.js";
|
|
6
|
+
import { cn as C } from "../../utils/cn/cn.js";
|
|
7
|
+
import { Portal as se } from "../../utils/portal/portal.js";
|
|
8
|
+
function V(i, k, R) {
|
|
9
|
+
const m = i.length;
|
|
10
|
+
let h = k;
|
|
11
|
+
for (let d = 0; d < m; d++)
|
|
12
|
+
if (h = (h + R + m) % m, !i[h].disabled) return h;
|
|
13
|
+
return -1;
|
|
14
|
+
}
|
|
15
|
+
const ce = ne(({
|
|
16
|
+
options: i,
|
|
17
|
+
value: k,
|
|
18
|
+
defaultValue: R,
|
|
19
|
+
onChange: m,
|
|
20
|
+
placeholder: h = "Select multiple...",
|
|
21
|
+
disabled: d = !1,
|
|
22
|
+
error: W = !1,
|
|
23
|
+
name: K,
|
|
24
|
+
id: z,
|
|
25
|
+
className: H,
|
|
26
|
+
maxTags: P = 3,
|
|
27
|
+
...U
|
|
28
|
+
}, v) => {
|
|
29
|
+
const S = k !== void 0, [X, Y] = N(R || []), c = S ? k : X, [s, y] = N(!1), [o, u] = N(() => i.findIndex((e) => !e.disabled)), w = E({ buffer: "", lastTime: 0 }), g = E(null), b = E(null), T = E(null), F = te.useId(), M = z ?? F, A = `${M}-listbox`, O = `${M}-label`, q = L((e) => {
|
|
30
|
+
g.current = e, typeof v == "function" ? v(e) : v && (v.current = e);
|
|
31
|
+
}, [v]), [j, G] = N({ top: -9999, left: -9999, width: 0 }), p = L(() => {
|
|
32
|
+
if (!g.current || !b.current) return;
|
|
33
|
+
const e = g.current.getBoundingClientRect(), n = b.current.getBoundingClientRect(), t = window.scrollY, r = window.scrollX;
|
|
34
|
+
let a = e.bottom + t + 4;
|
|
35
|
+
const D = e.left + r, x = e.width, f = 16;
|
|
36
|
+
e.bottom + n.height + 4 > document.documentElement.clientHeight - f && (a = e.top + t - n.height - 4, a < f + t && (a = f + t)), G({ top: a, left: D, width: x });
|
|
37
|
+
}, []);
|
|
38
|
+
ie(() => {
|
|
39
|
+
if (s)
|
|
40
|
+
return p(), window.addEventListener("resize", p), window.addEventListener("scroll", p, !0), () => {
|
|
41
|
+
window.removeEventListener("resize", p), window.removeEventListener("scroll", p, !0);
|
|
42
|
+
};
|
|
43
|
+
}, [s, p]);
|
|
44
|
+
const J = L(() => {
|
|
45
|
+
y(!1), le(g.current);
|
|
46
|
+
}, []);
|
|
47
|
+
B(() => s ? re([b, g], () => y(!1)) : void 0, [s]), B(() => {
|
|
48
|
+
if (!s) return;
|
|
49
|
+
const e = i.findIndex((t) => !t.disabled);
|
|
50
|
+
u(e >= 0 ? e : -1);
|
|
51
|
+
const n = setTimeout(() => b.current?.focus(), 10);
|
|
52
|
+
return () => clearTimeout(n);
|
|
53
|
+
}, [s, i]), B(() => {
|
|
54
|
+
s && T.current && T.current.scrollIntoView({ block: "nearest" });
|
|
55
|
+
}, [o, s]);
|
|
56
|
+
const $ = L((e) => {
|
|
57
|
+
const t = c.includes(e) ? c.filter((r) => r !== e) : [...c, e];
|
|
58
|
+
S || Y(t), m?.(t), b.current?.focus();
|
|
59
|
+
}, [S, c, m]), Q = (e) => {
|
|
60
|
+
d || ["ArrowDown", "ArrowUp", " ", "Enter"].includes(e.key) && (e.preventDefault(), y(!0));
|
|
61
|
+
}, Z = (e) => {
|
|
62
|
+
const n = e.key;
|
|
63
|
+
if (n === "ArrowDown") {
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
const t = V(i, o, 1);
|
|
66
|
+
t >= 0 && u(t);
|
|
67
|
+
} else if (n === "ArrowUp") {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
const t = V(i, o, -1);
|
|
70
|
+
t >= 0 && u(t);
|
|
71
|
+
} else if (n === "Home") {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
const t = i.findIndex((r) => !r.disabled);
|
|
74
|
+
t >= 0 && u(t);
|
|
75
|
+
} else if (n === "End") {
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
const t = i.length - 1 - [...i].reverse().findIndex((r) => !r.disabled);
|
|
78
|
+
t >= 0 && u(t);
|
|
79
|
+
} else if (n === "Enter" || n === " ") {
|
|
80
|
+
if (e.preventDefault(), o >= 0) {
|
|
81
|
+
const t = i[o];
|
|
82
|
+
t.disabled || $(t.value);
|
|
83
|
+
}
|
|
84
|
+
} else if (n === "Escape")
|
|
85
|
+
e.preventDefault(), J();
|
|
86
|
+
else if (n.length === 1 && n.match(/\S/)) {
|
|
87
|
+
const t = Date.now();
|
|
88
|
+
t - w.current.lastTime > 700 && (w.current.buffer = ""), w.current.buffer += n.toLowerCase(), w.current.lastTime = t;
|
|
89
|
+
const r = w.current.buffer, a = o >= 0 ? o + 1 : 0, D = i.length;
|
|
90
|
+
for (let x = 0; x < D; x++) {
|
|
91
|
+
const f = (a + x) % D, ee = String(i[f].label).toLowerCase();
|
|
92
|
+
if (!i[f].disabled && ee.startsWith(r)) {
|
|
93
|
+
u(f);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}, _ = () => c.length === 0 ? /* @__PURE__ */ l("span", { className: "nui-multiselect-placeholder", children: h }) : c.length > P ? /* @__PURE__ */ I("span", { className: "nui-multiselect-summary", children: [
|
|
99
|
+
c.length,
|
|
100
|
+
" items selected"
|
|
101
|
+
] }) : /* @__PURE__ */ l("div", { className: "nui-multiselect-tags", children: c.map((e) => {
|
|
102
|
+
const n = i.find((t) => t.value === e)?.label ?? e;
|
|
103
|
+
return /* @__PURE__ */ l("span", { className: "nui-multiselect-tag", children: n }, e);
|
|
104
|
+
}) });
|
|
105
|
+
return /* @__PURE__ */ I("div", { className: C("nui-multiselect-root", H), children: [
|
|
106
|
+
K && c.map((e) => /* @__PURE__ */ l("input", { type: "hidden", name: K, value: e }, e)),
|
|
107
|
+
/* @__PURE__ */ I(
|
|
108
|
+
"button",
|
|
109
|
+
{
|
|
110
|
+
ref: q,
|
|
111
|
+
id: O,
|
|
112
|
+
type: "button",
|
|
113
|
+
className: C("nui-multiselect-trigger", W && "error"),
|
|
114
|
+
"aria-haspopup": "listbox",
|
|
115
|
+
"aria-expanded": s,
|
|
116
|
+
"aria-controls": s ? A : void 0,
|
|
117
|
+
"aria-disabled": d || void 0,
|
|
118
|
+
onClick: () => !d && y((e) => !e),
|
|
119
|
+
onKeyDown: Q,
|
|
120
|
+
disabled: d,
|
|
121
|
+
...U,
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ l("div", { className: "nui-multiselect-value-container", children: _() }),
|
|
124
|
+
/* @__PURE__ */ l("svg", { className: "nui-multiselect-chevron", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ l("polyline", { points: "6 9 12 15 18 9" }) })
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
),
|
|
128
|
+
s && /* @__PURE__ */ l(se, { children: /* @__PURE__ */ l(
|
|
129
|
+
"div",
|
|
130
|
+
{
|
|
131
|
+
id: A,
|
|
132
|
+
ref: b,
|
|
133
|
+
className: "nui-multiselect-listbox",
|
|
134
|
+
role: "listbox",
|
|
135
|
+
"aria-multiselectable": "true",
|
|
136
|
+
"aria-labelledby": O,
|
|
137
|
+
tabIndex: 0,
|
|
138
|
+
style: { top: j.top, left: j.left, width: j.width },
|
|
139
|
+
onKeyDown: Z,
|
|
140
|
+
children: i.map((e, n) => {
|
|
141
|
+
const t = c.includes(e.value), r = o === n;
|
|
142
|
+
return /* @__PURE__ */ I(
|
|
143
|
+
"div",
|
|
144
|
+
{
|
|
145
|
+
ref: r ? T : null,
|
|
146
|
+
id: `${A}-option-${n}`,
|
|
147
|
+
role: "option",
|
|
148
|
+
"aria-selected": t,
|
|
149
|
+
"aria-disabled": e.disabled || void 0,
|
|
150
|
+
className: C(
|
|
151
|
+
"nui-multiselect-option",
|
|
152
|
+
r && "active",
|
|
153
|
+
t && "selected",
|
|
154
|
+
e.disabled && "disabled"
|
|
155
|
+
),
|
|
156
|
+
tabIndex: -1,
|
|
157
|
+
onMouseDown: (a) => a.preventDefault(),
|
|
158
|
+
onClick: () => !e.disabled && $(e.value),
|
|
159
|
+
onMouseEnter: () => !e.disabled && u(n),
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ l("div", { className: C("nui-multiselect-checkbox", t && "checked"), "aria-hidden": "true", children: t && /* @__PURE__ */ l("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ l("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
162
|
+
/* @__PURE__ */ l("span", { className: "nui-multiselect-option-label", children: e.label })
|
|
163
|
+
]
|
|
164
|
+
},
|
|
165
|
+
e.value
|
|
166
|
+
);
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
) })
|
|
170
|
+
] });
|
|
171
|
+
});
|
|
172
|
+
ce.displayName = "MultiSelect";
|
|
173
|
+
export {
|
|
174
|
+
ce as MultiSelect
|
|
175
|
+
};
|
|
176
|
+
//# sourceMappingURL=MultiSelect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MultiSelect.js","sources":["../../../src/components/multiselect/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport React, {\n useState,\n useRef,\n useEffect,\n useCallback,\n useLayoutEffect,\n KeyboardEvent,\n forwardRef,\n} from 'react';\nimport { cn } from '../../utils';\nimport { Portal, onClickOutside, restoreFocus } from '../../utils';\nimport './MultiSelect.css';\n\n/* ============================================================\n * Types\n * ============================================================ */\n\nexport type MultiSelectOption = {\n value: string;\n label: React.ReactNode;\n disabled?: boolean;\n};\n\nexport interface MultiSelectProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange'> {\n /** Array of available options */\n options: MultiSelectOption[];\n /** Controlled state for selected values */\n value?: string[]; \n /** Uncontrolled initial state for selected values */\n defaultValue?: string[]; \n /** Callback fired when the selection changes */\n onChange?: (value: string[]) => void;\n /** Text displayed when no options are selected */\n placeholder?: string;\n /** Name attribute applied to hidden inputs for native form submission */\n name?: string; \n /** Toggles error styling */\n error?: boolean;\n /** Number of tags to render before collapsing into a summary string (e.g., \"3 selected\") */\n maxTags?: number; \n}\n\n/* Helper: find next enabled index given direction */\nfunction findNextEnabled(options: MultiSelectOption[], start: number, direction: 1 | -1) {\n const len = options.length;\n let i = start;\n for (let step = 0; step < len; step++) {\n i = (i + direction + len) % len;\n if (!options[i].disabled) return i;\n }\n return -1;\n}\n\n/* ============================================================\n * Component\n * ============================================================ */\n\n/**\n * MultiSelect Component\n * * A custom, WAI-ARIA compliant dropdown for selecting multiple options.\n * * Architecture Note: Unlike a standard Select, the dropdown list intentionally \n * remains open after a selection is made, allowing the user to quickly select \n * multiple items without repeatedly reopening the menu.\n */\nexport const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(({\n options,\n value,\n defaultValue,\n onChange,\n placeholder = 'Select multiple...',\n disabled = false,\n error = false,\n name,\n id,\n className,\n maxTags = 3,\n ...props\n}, ref) => {\n const isControlled = value !== undefined;\n const [internalValue, setInternalValue] = useState<string[]>(defaultValue || []);\n const selectedValues = isControlled ? value : internalValue;\n\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState<number>(() => options.findIndex((o) => !o.disabled));\n\n // Used for keyboard typeahead navigation\n const typeaheadRef = useRef({ buffer: '', lastTime: 0 });\n \n const triggerRef = useRef<HTMLButtonElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const activeOptionRef = useRef<HTMLDivElement | null>(null);\n\n const reactId = React.useId();\n const baseId = id ?? reactId;\n const listboxId = `${baseId}-listbox`;\n const labelId = `${baseId}-label`;\n\n /* ----------------------------------------------------\n Ref Merging\n ---------------------------------------------------- */\n const setTriggerRef = useCallback((node: HTMLButtonElement | null) => {\n triggerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n }, [ref]);\n\n /* ----------------------------------------------------\n Smart Position & Width Sync\n ---------------------------------------------------- */\n const [coords, setCoords] = useState({ top: -9999, left: -9999, width: 0 });\n\n const updatePosition = useCallback(() => {\n if (!triggerRef.current || !listRef.current) return;\n\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const listRect = listRef.current.getBoundingClientRect();\n const scrollY = window.scrollY;\n const scrollX = window.scrollX;\n\n let top = triggerRect.bottom + scrollY + 4;\n const left = triggerRect.left + scrollX;\n const width = triggerRect.width; \n\n // Viewport Bottom Collision & Hard Top Clamp\n const padding = 16;\n if (triggerRect.bottom + listRect.height + 4 > document.documentElement.clientHeight - padding) {\n top = triggerRect.top + scrollY - listRect.height - 4; \n if (top < padding + scrollY) top = padding + scrollY; \n }\n\n setCoords({ top, left, width });\n }, []);\n\n useLayoutEffect(() => {\n if (!open) return;\n updatePosition();\n window.addEventListener('resize', updatePosition);\n window.addEventListener('scroll', updatePosition, true);\n return () => {\n window.removeEventListener('resize', updatePosition);\n window.removeEventListener('scroll', updatePosition, true);\n };\n }, [open, updatePosition]);\n\n /* ----------------------------------------------------\n Focus & Scroll Management\n ---------------------------------------------------- */\n const closeList = useCallback(() => {\n setOpen(false);\n restoreFocus(triggerRef.current);\n }, []);\n\n useEffect(() => {\n if (!open) return;\n const cleanup = onClickOutside([listRef, triggerRef], () => setOpen(false));\n return cleanup;\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n // Reset active index to first non-disabled item when opened\n const idx = options.findIndex((o) => !o.disabled);\n setActiveIndex(idx >= 0 ? idx : -1);\n \n // Defer focus slightly to ensure Portal has rendered\n const timeoutId = setTimeout(() => listRef.current?.focus(), 10);\n return () => clearTimeout(timeoutId);\n }, [open, options]);\n\n // Auto-scroll to active item\n useEffect(() => {\n if (open && activeOptionRef.current) {\n activeOptionRef.current.scrollIntoView({ block: 'nearest' });\n }\n }, [activeIndex, open]);\n\n /* ----------------------------------------------------\n Event Handlers\n ---------------------------------------------------- */\n const toggleOption = useCallback((optValue: string) => {\n const isSelected = selectedValues.includes(optValue);\n const nextValues = isSelected \n ? selectedValues.filter(v => v !== optValue) \n : [...selectedValues, optValue];\n\n if (!isControlled) setInternalValue(nextValues);\n onChange?.(nextValues);\n \n // WAI-ARIA Standard: Do not close the dropdown for Multi-Select!\n // Refocus the list so the user can keep navigating via keyboard.\n listRef.current?.focus();\n }, [isControlled, selectedValues, onChange]);\n\n const onTriggerKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n if (disabled) return;\n if (['ArrowDown', 'ArrowUp', ' ', 'Enter'].includes(e.key)) {\n e.preventDefault();\n setOpen(true);\n }\n };\n\n const onListKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n const key = e.key;\n if (key === 'ArrowDown') {\n e.preventDefault();\n const next = findNextEnabled(options, activeIndex, 1);\n if (next >= 0) setActiveIndex(next);\n } else if (key === 'ArrowUp') {\n e.preventDefault();\n const prev = findNextEnabled(options, activeIndex, -1);\n if (prev >= 0) setActiveIndex(prev);\n } else if (key === 'Home') {\n e.preventDefault();\n const first = options.findIndex((o) => !o.disabled);\n if (first >= 0) setActiveIndex(first);\n } else if (key === 'End') {\n e.preventDefault();\n const last = options.length - 1 - [...options].reverse().findIndex((o) => !o.disabled);\n if (last >= 0) setActiveIndex(last);\n } else if (key === 'Enter' || key === ' ') {\n e.preventDefault();\n if (activeIndex >= 0) {\n const opt = options[activeIndex];\n if (!opt.disabled) toggleOption(opt.value);\n }\n } else if (key === 'Escape') {\n e.preventDefault();\n closeList();\n } else if (key.length === 1 && key.match(/\\S/)) {\n // Typeahead logic\n const now = Date.now();\n if (now - typeaheadRef.current.lastTime > 700) typeaheadRef.current.buffer = '';\n typeaheadRef.current.buffer += key.toLowerCase();\n typeaheadRef.current.lastTime = now;\n\n const buf = typeaheadRef.current.buffer;\n const start = activeIndex >= 0 ? activeIndex + 1 : 0;\n const len = options.length;\n for (let i = 0; i < len; i++) {\n const idx = (start + i) % len;\n const lab = String(options[idx].label).toLowerCase();\n if (!options[idx].disabled && lab.startsWith(buf)) {\n setActiveIndex(idx);\n break;\n }\n }\n }\n };\n\n /* ----------------------------------------------------\n Trigger Rendering Logic\n ---------------------------------------------------- */\n const renderTriggerContent = () => {\n if (selectedValues.length === 0) {\n return <span className=\"nui-multiselect-placeholder\">{placeholder}</span>;\n }\n\n if (selectedValues.length > maxTags) {\n return (\n <span className=\"nui-multiselect-summary\">\n {selectedValues.length} items selected\n </span>\n );\n }\n\n // Render individual tags\n return (\n <div className=\"nui-multiselect-tags\">\n {selectedValues.map(val => {\n const label = options.find(o => o.value === val)?.label ?? val;\n return (\n <span key={val} className=\"nui-multiselect-tag\">\n {label}\n </span>\n );\n })}\n </div>\n );\n };\n\n /* ----------------------------------------------------\n Render\n ---------------------------------------------------- */\n return (\n <div className={cn(\"nui-multiselect-root\", className)}>\n \n {/* Hidden inputs for native form submission */}\n {name && selectedValues.map((val) => (\n <input key={val} type=\"hidden\" name={name} value={val} />\n ))}\n\n <button\n ref={setTriggerRef}\n id={labelId}\n type=\"button\"\n className={cn(\"nui-multiselect-trigger\", error && \"error\")}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={open ? listboxId : undefined}\n aria-disabled={disabled || undefined}\n onClick={() => !disabled && setOpen((s) => !s)}\n onKeyDown={onTriggerKeyDown}\n disabled={disabled}\n {...props}\n >\n <div className=\"nui-multiselect-value-container\">\n {renderTriggerContent()}\n </div>\n <svg className=\"nui-multiselect-chevron\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </button>\n\n {open && (\n <Portal>\n <div\n id={listboxId}\n ref={listRef}\n className=\"nui-multiselect-listbox\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n aria-labelledby={labelId}\n tabIndex={0}\n style={{ top: coords.top, left: coords.left, width: coords.width }}\n onKeyDown={onListKeyDown}\n >\n {options.map((opt, i) => {\n const isSelected = selectedValues.includes(opt.value);\n const isActive = activeIndex === i;\n \n return (\n <div\n key={opt.value}\n ref={isActive ? activeOptionRef : null}\n id={`${listboxId}-option-${i}`}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={opt.disabled || undefined}\n className={cn(\n \"nui-multiselect-option\",\n isActive && \"active\",\n isSelected && \"selected\",\n opt.disabled && \"disabled\"\n )}\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()} \n onClick={() => !opt.disabled && toggleOption(opt.value)}\n onMouseEnter={() => !opt.disabled && setActiveIndex(i)}\n >\n \n {/* Custom Checkbox UI */}\n <div className={cn(\"nui-multiselect-checkbox\", isSelected && \"checked\")} aria-hidden=\"true\">\n {isSelected && (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n )}\n </div>\n\n <span className=\"nui-multiselect-option-label\">{opt.label}</span>\n </div>\n );\n })}\n </div>\n </Portal>\n )}\n </div>\n );\n});\nMultiSelect.displayName = 'MultiSelect';"],"names":["findNextEnabled","options","start","direction","len","i","step","MultiSelect","forwardRef","value","defaultValue","onChange","placeholder","disabled","error","name","id","className","maxTags","props","ref","isControlled","internalValue","setInternalValue","useState","selectedValues","open","setOpen","activeIndex","setActiveIndex","o","typeaheadRef","useRef","triggerRef","listRef","activeOptionRef","reactId","React","baseId","listboxId","labelId","setTriggerRef","useCallback","node","coords","setCoords","updatePosition","triggerRect","listRect","scrollY","scrollX","top","left","width","padding","useLayoutEffect","closeList","restoreFocus","useEffect","onClickOutside","idx","timeoutId","toggleOption","optValue","nextValues","v","onTriggerKeyDown","onListKeyDown","key","next","prev","first","last","opt","now","buf","lab","renderTriggerContent","jsx","jsxs","val","label","cn","s","Portal","isSelected","isActive","e"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("react/jsx-runtime"),t=require("react"),m=t.createContext(void 0);function w(){const i=t.useContext(m);if(i===void 0)throw new Error("useTheme must be used within a <NUIProvider>");return i}function T({children:i,defaultTheme:u="system",storageKey:c="nui-theme"}){const[r,d]=t.useState(u),[l,h]=t.useState("light"),[a,f]=t.useState(!1),s=t.useCallback(e=>{const n=document.documentElement;let o;e==="system"?o=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":o=e,n.setAttribute("data-theme",o),o==="dark"?n.classList.add("dark"):n.classList.remove("dark"),h(o)},[]);return t.useEffect(()=>{f(!0);const e=window.localStorage.getItem(c);e?(d(e),s(e)):s(u)},[c,u,s]),t.useEffect(()=>{a&&(window.localStorage.setItem(c,r),s(r))},[r,c,a,s]),t.useEffect(()=>{if(!a||r!=="system")return;const e=window.matchMedia("(prefers-color-scheme: dark)"),n=()=>s("system");return e.addEventListener("change",n),()=>e.removeEventListener("change",n)},[r,a,s]),v.jsx(m.Provider,{value:{theme:r,resolvedTheme:l,setTheme:d},children:i})}exports.NUIProvider=T;exports.useTheme=w;
|
|
2
|
+
//# sourceMappingURL=NUIProvider.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NUIProvider.cjs","sources":["../../../src/components/nuiprovider/NUIProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useCallback } from 'react';\n\n/* ============================================================\n * Types\n * ============================================================ */\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\nexport interface NUIProviderProps {\n children: React.ReactNode;\n /** The default theme if nothing is in local storage. Defaults to 'system'. */\n defaultTheme?: ThemeMode;\n /** The local storage key used to persist the theme preference. Defaults to 'nui-theme'. */\n storageKey?: string;\n}\n\nexport interface ThemeContextState {\n /** The user's selected preference (includes 'system') */\n theme: ThemeMode;\n /** The actual calculated theme currently rendered in the DOM ('light' or 'dark') */\n resolvedTheme: 'light' | 'dark';\n /** Function to update the theme */\n setTheme: (theme: ThemeMode) => void;\n}\n\n/* ============================================================\n * Context & Hook\n * ============================================================ */\n\nconst ThemeContext = createContext<ThemeContextState | undefined>(undefined);\n\n/**\n * useTheme Hook\n * * Consumes the NUI Theme context to read or update the current theme.\n */\nexport function useTheme() {\n const context = useContext(ThemeContext);\n if (context === undefined) {\n throw new Error('useTheme must be used within a <NUIProvider>');\n }\n return context;\n}\n\n/* ============================================================\n * Component\n * ============================================================ */\n\n/**\n * NUIProvider\n * * The root provider for the NUI component library.\n * * Manages theme state, synchronizes with localStorage, and listens for system preference changes.\n */\nexport function NUIProvider({\n children,\n defaultTheme = 'system',\n storageKey = 'nui-theme',\n}: NUIProviderProps) {\n const [theme, setTheme] = useState<ThemeMode>(defaultTheme);\n const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light');\n const [isMounted, setIsMounted] = useState(false);\n\n // 1. Core logic to apply the theme to the DOM\n const applyTheme = useCallback((mode: ThemeMode) => {\n const root = document.documentElement;\n let finalTheme: 'light' | 'dark';\n\n if (mode === 'system') {\n finalTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n } else {\n finalTheme = mode;\n }\n\n // Set standard data attribute for CSS variables\n root.setAttribute('data-theme', finalTheme);\n \n // Toggle the 'dark' class for Tailwind CSS compatibility\n if (finalTheme === 'dark') {\n root.classList.add('dark');\n } else {\n root.classList.remove('dark');\n }\n\n setResolvedTheme(finalTheme);\n }, []);\n\n // 2. Hydration & Initial Load\n useEffect(() => {\n setIsMounted(true);\n const storedTheme = window.localStorage.getItem(storageKey) as ThemeMode | null;\n \n if (storedTheme) {\n setTheme(storedTheme);\n applyTheme(storedTheme);\n } else {\n applyTheme(defaultTheme);\n }\n }, [storageKey, defaultTheme, applyTheme]);\n\n // 3. Sync state changes to LocalStorage\n useEffect(() => {\n if (!isMounted) return;\n window.localStorage.setItem(storageKey, theme);\n applyTheme(theme);\n }, [theme, storageKey, isMounted, applyTheme]);\n\n // 4. System Preference Listener\n useEffect(() => {\n if (!isMounted || theme !== 'system') return;\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const handleChange = () => applyTheme('system');\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, [theme, isMounted, applyTheme]);\n\n // 5. Render Provider\n return (\n <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>\n {children}\n </ThemeContext.Provider>\n );\n}"],"names":["ThemeContext","createContext","useTheme","context","useContext","NUIProvider","children","defaultTheme","storageKey","theme","setTheme","useState","resolvedTheme","setResolvedTheme","isMounted","setIsMounted","applyTheme","useCallback","mode","root","finalTheme","useEffect","storedTheme","mediaQuery","handleChange","jsx"],"mappings":"wIA+BMA,EAAeC,EAAAA,cAA6C,MAAS,EAMpE,SAASC,GAAW,CACzB,MAAMC,EAAUC,EAAAA,WAAWJ,CAAY,EACvC,GAAIG,IAAY,OACd,MAAM,IAAI,MAAM,8CAA8C,EAEhE,OAAOA,CACT,CAWO,SAASE,EAAY,CAC1B,SAAAC,EACA,aAAAC,EAAe,SACf,WAAAC,EAAa,WACf,EAAqB,CACnB,KAAM,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAAoBJ,CAAY,EACpD,CAACK,EAAeC,CAAgB,EAAIF,EAAAA,SAA2B,OAAO,EACtE,CAACG,EAAWC,CAAY,EAAIJ,EAAAA,SAAS,EAAK,EAG1CK,EAAaC,cAAaC,GAAoB,CAClD,MAAMC,EAAO,SAAS,gBACtB,IAAIC,EAEAF,IAAS,SACXE,EAAa,OAAO,WAAW,8BAA8B,EAAE,QAAU,OAAS,QAElFA,EAAaF,EAIfC,EAAK,aAAa,aAAcC,CAAU,EAGtCA,IAAe,OACjBD,EAAK,UAAU,IAAI,MAAM,EAEzBA,EAAK,UAAU,OAAO,MAAM,EAG9BN,EAAiBO,CAAU,CAC7B,EAAG,CAAA,CAAE,EAGLC,OAAAA,EAAAA,UAAU,IAAM,CACdN,EAAa,EAAI,EACjB,MAAMO,EAAc,OAAO,aAAa,QAAQd,CAAU,EAEtDc,GACFZ,EAASY,CAAW,EACpBN,EAAWM,CAAW,GAEtBN,EAAWT,CAAY,CAE3B,EAAG,CAACC,EAAYD,EAAcS,CAAU,CAAC,EAGzCK,EAAAA,UAAU,IAAM,CACTP,IACL,OAAO,aAAa,QAAQN,EAAYC,CAAK,EAC7CO,EAAWP,CAAK,EAClB,EAAG,CAACA,EAAOD,EAAYM,EAAWE,CAAU,CAAC,EAG7CK,EAAAA,UAAU,IAAM,CACd,GAAI,CAACP,GAAaL,IAAU,SAAU,OAEtC,MAAMc,EAAa,OAAO,WAAW,8BAA8B,EAC7DC,EAAe,IAAMR,EAAW,QAAQ,EAE9C,OAAAO,EAAW,iBAAiB,SAAUC,CAAY,EAC3C,IAAMD,EAAW,oBAAoB,SAAUC,CAAY,CACpE,EAAG,CAACf,EAAOK,EAAWE,CAAU,CAAC,EAI/BS,MAACzB,EAAa,SAAb,CAAsB,MAAO,CAAE,MAAAS,EAAO,cAAAG,EAAe,SAAAF,GACnD,SAAAJ,EACH,CAEJ"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as w } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as k, useContext as p, useState as a, useCallback as T, useEffect as d } from "react";
|
|
3
|
+
const l = k(void 0);
|
|
4
|
+
function C() {
|
|
5
|
+
const n = p(l);
|
|
6
|
+
if (n === void 0)
|
|
7
|
+
throw new Error("useTheme must be used within a <NUIProvider>");
|
|
8
|
+
return n;
|
|
9
|
+
}
|
|
10
|
+
function E({
|
|
11
|
+
children: n,
|
|
12
|
+
defaultTheme: m = "system",
|
|
13
|
+
storageKey: i = "nui-theme"
|
|
14
|
+
}) {
|
|
15
|
+
const [s, h] = a(m), [u, f] = a("light"), [c, v] = a(!1), t = T((e) => {
|
|
16
|
+
const o = document.documentElement;
|
|
17
|
+
let r;
|
|
18
|
+
e === "system" ? r = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : r = e, o.setAttribute("data-theme", r), r === "dark" ? o.classList.add("dark") : o.classList.remove("dark"), f(r);
|
|
19
|
+
}, []);
|
|
20
|
+
return d(() => {
|
|
21
|
+
v(!0);
|
|
22
|
+
const e = window.localStorage.getItem(i);
|
|
23
|
+
e ? (h(e), t(e)) : t(m);
|
|
24
|
+
}, [i, m, t]), d(() => {
|
|
25
|
+
c && (window.localStorage.setItem(i, s), t(s));
|
|
26
|
+
}, [s, i, c, t]), d(() => {
|
|
27
|
+
if (!c || s !== "system") return;
|
|
28
|
+
const e = window.matchMedia("(prefers-color-scheme: dark)"), o = () => t("system");
|
|
29
|
+
return e.addEventListener("change", o), () => e.removeEventListener("change", o);
|
|
30
|
+
}, [s, c, t]), /* @__PURE__ */ w(l.Provider, { value: { theme: s, resolvedTheme: u, setTheme: h }, children: n });
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
E as NUIProvider,
|
|
34
|
+
C as useTheme
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=NUIProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NUIProvider.js","sources":["../../../src/components/nuiprovider/NUIProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useCallback } from 'react';\n\n/* ============================================================\n * Types\n * ============================================================ */\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\nexport interface NUIProviderProps {\n children: React.ReactNode;\n /** The default theme if nothing is in local storage. Defaults to 'system'. */\n defaultTheme?: ThemeMode;\n /** The local storage key used to persist the theme preference. Defaults to 'nui-theme'. */\n storageKey?: string;\n}\n\nexport interface ThemeContextState {\n /** The user's selected preference (includes 'system') */\n theme: ThemeMode;\n /** The actual calculated theme currently rendered in the DOM ('light' or 'dark') */\n resolvedTheme: 'light' | 'dark';\n /** Function to update the theme */\n setTheme: (theme: ThemeMode) => void;\n}\n\n/* ============================================================\n * Context & Hook\n * ============================================================ */\n\nconst ThemeContext = createContext<ThemeContextState | undefined>(undefined);\n\n/**\n * useTheme Hook\n * * Consumes the NUI Theme context to read or update the current theme.\n */\nexport function useTheme() {\n const context = useContext(ThemeContext);\n if (context === undefined) {\n throw new Error('useTheme must be used within a <NUIProvider>');\n }\n return context;\n}\n\n/* ============================================================\n * Component\n * ============================================================ */\n\n/**\n * NUIProvider\n * * The root provider for the NUI component library.\n * * Manages theme state, synchronizes with localStorage, and listens for system preference changes.\n */\nexport function NUIProvider({\n children,\n defaultTheme = 'system',\n storageKey = 'nui-theme',\n}: NUIProviderProps) {\n const [theme, setTheme] = useState<ThemeMode>(defaultTheme);\n const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light');\n const [isMounted, setIsMounted] = useState(false);\n\n // 1. Core logic to apply the theme to the DOM\n const applyTheme = useCallback((mode: ThemeMode) => {\n const root = document.documentElement;\n let finalTheme: 'light' | 'dark';\n\n if (mode === 'system') {\n finalTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n } else {\n finalTheme = mode;\n }\n\n // Set standard data attribute for CSS variables\n root.setAttribute('data-theme', finalTheme);\n \n // Toggle the 'dark' class for Tailwind CSS compatibility\n if (finalTheme === 'dark') {\n root.classList.add('dark');\n } else {\n root.classList.remove('dark');\n }\n\n setResolvedTheme(finalTheme);\n }, []);\n\n // 2. Hydration & Initial Load\n useEffect(() => {\n setIsMounted(true);\n const storedTheme = window.localStorage.getItem(storageKey) as ThemeMode | null;\n \n if (storedTheme) {\n setTheme(storedTheme);\n applyTheme(storedTheme);\n } else {\n applyTheme(defaultTheme);\n }\n }, [storageKey, defaultTheme, applyTheme]);\n\n // 3. Sync state changes to LocalStorage\n useEffect(() => {\n if (!isMounted) return;\n window.localStorage.setItem(storageKey, theme);\n applyTheme(theme);\n }, [theme, storageKey, isMounted, applyTheme]);\n\n // 4. System Preference Listener\n useEffect(() => {\n if (!isMounted || theme !== 'system') return;\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const handleChange = () => applyTheme('system');\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, [theme, isMounted, applyTheme]);\n\n // 5. Render Provider\n return (\n <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>\n {children}\n </ThemeContext.Provider>\n );\n}"],"names":["ThemeContext","createContext","useTheme","context","useContext","NUIProvider","children","defaultTheme","storageKey","theme","setTheme","useState","resolvedTheme","setResolvedTheme","isMounted","setIsMounted","applyTheme","useCallback","mode","root","finalTheme","useEffect","storedTheme","mediaQuery","handleChange","jsx"],"mappings":";;AA+BA,MAAMA,IAAeC,EAA6C,MAAS;AAMpE,SAASC,IAAW;AACzB,QAAMC,IAAUC,EAAWJ,CAAY;AACvC,MAAIG,MAAY;AACd,UAAM,IAAI,MAAM,8CAA8C;AAEhE,SAAOA;AACT;AAWO,SAASE,EAAY;AAAA,EAC1B,UAAAC;AAAA,EACA,cAAAC,IAAe;AAAA,EACf,YAAAC,IAAa;AACf,GAAqB;AACnB,QAAM,CAACC,GAAOC,CAAQ,IAAIC,EAAoBJ,CAAY,GACpD,CAACK,GAAeC,CAAgB,IAAIF,EAA2B,OAAO,GACtE,CAACG,GAAWC,CAAY,IAAIJ,EAAS,EAAK,GAG1CK,IAAaC,EAAY,CAACC,MAAoB;AAClD,UAAMC,IAAO,SAAS;AACtB,QAAIC;AAEJ,IAAIF,MAAS,WACXE,IAAa,OAAO,WAAW,8BAA8B,EAAE,UAAU,SAAS,UAElFA,IAAaF,GAIfC,EAAK,aAAa,cAAcC,CAAU,GAGtCA,MAAe,SACjBD,EAAK,UAAU,IAAI,MAAM,IAEzBA,EAAK,UAAU,OAAO,MAAM,GAG9BN,EAAiBO,CAAU;AAAA,EAC7B,GAAG,CAAA,CAAE;AAGL,SAAAC,EAAU,MAAM;AACd,IAAAN,EAAa,EAAI;AACjB,UAAMO,IAAc,OAAO,aAAa,QAAQd,CAAU;AAE1D,IAAIc,KACFZ,EAASY,CAAW,GACpBN,EAAWM,CAAW,KAEtBN,EAAWT,CAAY;AAAA,EAE3B,GAAG,CAACC,GAAYD,GAAcS,CAAU,CAAC,GAGzCK,EAAU,MAAM;AACd,IAAKP,MACL,OAAO,aAAa,QAAQN,GAAYC,CAAK,GAC7CO,EAAWP,CAAK;AAAA,EAClB,GAAG,CAACA,GAAOD,GAAYM,GAAWE,CAAU,CAAC,GAG7CK,EAAU,MAAM;AACd,QAAI,CAACP,KAAaL,MAAU,SAAU;AAEtC,UAAMc,IAAa,OAAO,WAAW,8BAA8B,GAC7DC,IAAe,MAAMR,EAAW,QAAQ;AAE9C,WAAAO,EAAW,iBAAiB,UAAUC,CAAY,GAC3C,MAAMD,EAAW,oBAAoB,UAAUC,CAAY;AAAA,EACpE,GAAG,CAACf,GAAOK,GAAWE,CAAU,CAAC,GAI/B,gBAAAS,EAACzB,EAAa,UAAb,EAAsB,OAAO,EAAE,OAAAS,GAAO,eAAAG,GAAe,UAAAF,KACnD,UAAAJ,GACH;AAEJ;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react/jsx-runtime"),y=require("react");;/* empty css */const m=require("../../utils/cn/cn.cjs");function w({page:p,total:i,onChange:k,siblings:a=1,className:v,disabled:l=!1,...b}){const r=Math.max(1,Math.min(p,i)),c=e=>{l||e<1||e>i||e===r||k(e)},P=y.useMemo(()=>{const e=5+a*2;if(i<=e)return Array.from({length:i},(o,s)=>s+1);const t=Math.max(r-a,1),x=Math.min(r+a,i),u=t>2,g=x<i-2,f=1,j=i;if(!u&&g){const o=3+2*a;return[...Array.from({length:o},(h,d)=>d+1),"right-ellipsis",j]}if(u&&!g){const o=3+2*a,s=Array.from({length:o},(h,d)=>i-o+1+d);return[f,"left-ellipsis",...s]}if(u&&g){const o=Array.from({length:x-t+1},(s,h)=>t+h);return[f,"left-ellipsis",...o,"right-ellipsis",j]}return[]},[i,r,a]);return i<=1?null:n.jsx("nav",{className:m.cn("nui-pagination",v),"aria-label":"Pagination Navigation",...b,children:n.jsxs("ul",{className:"nui-pagination-list",children:[n.jsx("li",{children:n.jsx("button",{className:"nui-pagination-btn nui-pagination-btn--nav",onClick:()=>c(r-1),disabled:l||r===1,"aria-label":"Previous Page",children:n.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:n.jsx("polyline",{points:"15 18 9 12 15 6"})})})}),P.map(e=>{if(e==="left-ellipsis"||e==="right-ellipsis")return n.jsx("li",{className:"nui-pagination-ellipsis","aria-hidden":"true",children:n.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[n.jsx("circle",{cx:"12",cy:"12",r:"1"}),n.jsx("circle",{cx:"19",cy:"12",r:"1"}),n.jsx("circle",{cx:"5",cy:"12",r:"1"})]})},e);const t=e===r;return n.jsx("li",{children:n.jsx("button",{className:m.cn("nui-pagination-btn",t&&"nui-pagination-btn--active"),"aria-current":t?"page":void 0,"aria-label":t?`Page ${e}`:`Go to page ${e}`,disabled:l,onClick:()=>c(e),children:e})},`page-${e}`)}),n.jsx("li",{children:n.jsx("button",{className:"nui-pagination-btn nui-pagination-btn--nav",onClick:()=>c(r+1),disabled:l||r===i,"aria-label":"Next Page",children:n.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:n.jsx("polyline",{points:"9 18 15 12 9 6"})})})})]})})}exports.Pagination=w;
|
|
2
2
|
//# sourceMappingURL=Pagination.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.cjs","sources":["../../../src/components/pagination/Pagination.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"Pagination.cjs","sources":["../../../src/components/pagination/Pagination.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport { cn } from '../../utils';\nimport './Pagination.css';\n\n/* ============================================================\n * Types\n * ============================================================ */\n\nexport interface PaginationProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange'> {\n /** The current active page number (1-indexed) */\n page: number;\n /** The total number of pages available */\n total: number;\n /** Callback fired when a new page is selected */\n onChange: (page: number) => void;\n /** Number of page links to show on each side of the current page. Defaults to 1. */\n siblings?: number;\n /** Custom class name applied to the root navigation element */\n className?: string;\n /** Disables all interaction with the pagination controls */\n disabled?: boolean;\n}\n\ntype PaginationItem = number | 'left-ellipsis' | 'right-ellipsis';\n\n/* ============================================================\n * Component\n * ============================================================ */\n\n/**\n * Pagination Component\n * * A navigation structure for splitting large lists across multiple pages.\n * * Automatically calculates when to collapse page ranges into ellipses based on siblings.\n * * Uses standard <nav> and <ul> elements for WAI-ARIA compliance.\n */\nexport function Pagination({\n page,\n total,\n onChange,\n siblings = 1,\n className,\n disabled = false,\n ...props\n}: PaginationProps) {\n \n // Guard against invalid ranges supplied by the developer\n const currentPage = Math.max(1, Math.min(page, total));\n\n const goTo = (p: number) => {\n if (disabled || p < 1 || p > total || p === currentPage) return;\n onChange(p);\n };\n\n /* ----------------------------------------------------\n Mathematically Perfect Page Generation\n ---------------------------------------------------- */\n const pages = useMemo<PaginationItem[]>(() => {\n // Math: 1 (first) + 1 (last) + 2 (siblings) + 1 (current) + 2 (ellipses)\n const totalPageNumbersToShow = 5 + siblings * 2;\n\n // 1. If we don't have enough pages to warrant an ellipsis, show them all\n if (total <= totalPageNumbersToShow) {\n return Array.from({ length: total }, (_, i) => i + 1);\n }\n\n const leftSiblingIndex = Math.max(currentPage - siblings, 1);\n const rightSiblingIndex = Math.min(currentPage + siblings, total);\n\n // 2. We only show an ellipsis if there are MORE than 2 pages hidden\n const showLeftDots = leftSiblingIndex > 2;\n const showRightDots = rightSiblingIndex < total - 2;\n\n const firstPageIndex = 1;\n const lastPageIndex = total;\n\n // Case 1: Show right dots only (e.g., [1] 2 3 4 5 ... 10)\n if (!showLeftDots && showRightDots) {\n const leftItemCount = 3 + 2 * siblings;\n const leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);\n return [...leftRange, 'right-ellipsis', lastPageIndex];\n }\n\n // Case 2: Show left dots only (e.g., 1 ... 6 7 8 9 [10])\n if (showLeftDots && !showRightDots) {\n const rightItemCount = 3 + 2 * siblings;\n const rightRange = Array.from({ length: rightItemCount }, (_, i) => total - rightItemCount + 1 + i);\n return [firstPageIndex, 'left-ellipsis', ...rightRange];\n }\n\n // Case 3: Show both dots (e.g., 1 ... 4 [5] 6 ... 10)\n if (showLeftDots && showRightDots) {\n const middleRange = Array.from(\n { length: rightSiblingIndex - leftSiblingIndex + 1 },\n (_, i) => leftSiblingIndex + i\n );\n return [firstPageIndex, 'left-ellipsis', ...middleRange, 'right-ellipsis', lastPageIndex];\n }\n\n return [];\n }, [total, currentPage, siblings]);\n\n if (total <= 1) return null;\n\n /* ----------------------------------------------------\n Render\n ---------------------------------------------------- */\n return (\n <nav\n className={cn(\"nui-pagination\", className)}\n aria-label=\"Pagination Navigation\"\n {...props}\n >\n <ul className=\"nui-pagination-list\">\n \n {/* Previous Button */}\n <li>\n <button\n className=\"nui-pagination-btn nui-pagination-btn--nav\"\n onClick={() => goTo(currentPage - 1)}\n disabled={disabled || currentPage === 1}\n aria-label=\"Previous Page\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <polyline points=\"15 18 9 12 15 6\"></polyline>\n </svg>\n </button>\n </li>\n\n {/* Page Numbers & Ellipses */}\n {pages.map((p) => {\n if (p === 'left-ellipsis' || p === 'right-ellipsis') {\n return (\n <li key={p} className=\"nui-pagination-ellipsis\" aria-hidden=\"true\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\"></circle>\n <circle cx=\"19\" cy=\"12\" r=\"1\"></circle>\n <circle cx=\"5\" cy=\"12\" r=\"1\"></circle>\n </svg>\n </li>\n );\n }\n\n const isCurrent = p === currentPage;\n\n return (\n <li key={`page-${p}`}>\n <button\n className={cn(\n \"nui-pagination-btn\",\n isCurrent && \"nui-pagination-btn--active\"\n )}\n aria-current={isCurrent ? 'page' : undefined}\n aria-label={isCurrent ? `Page ${p}` : `Go to page ${p}`}\n disabled={disabled}\n onClick={() => goTo(p)}\n >\n {p}\n </button>\n </li>\n );\n })}\n\n {/* Next Button */}\n <li>\n <button\n className=\"nui-pagination-btn nui-pagination-btn--nav\"\n onClick={() => goTo(currentPage + 1)}\n disabled={disabled || currentPage === total}\n aria-label=\"Next Page\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <polyline points=\"9 18 15 12 9 6\"></polyline>\n </svg>\n </button>\n </li>\n </ul>\n </nav>\n );\n}"],"names":["Pagination","page","total","onChange","siblings","className","disabled","props","currentPage","goTo","p","pages","useMemo","totalPageNumbersToShow","_","i","leftSiblingIndex","rightSiblingIndex","showLeftDots","showRightDots","firstPageIndex","lastPageIndex","leftItemCount","rightItemCount","rightRange","middleRange","jsx","cn","jsxs","isCurrent"],"mappings":"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"}
|
|
@@ -1,62 +1,95 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as i, jsxs as x } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo as C } from "react";
|
|
2
3
|
/* empty css */
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import { cn as k } from "../../utils/cn/cn.js";
|
|
5
|
+
function M({
|
|
6
|
+
page: v,
|
|
7
|
+
total: e,
|
|
8
|
+
onChange: b,
|
|
9
|
+
siblings: a = 1,
|
|
10
|
+
className: P,
|
|
11
|
+
disabled: s = !1,
|
|
12
|
+
...w
|
|
9
13
|
}) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
const r = Math.max(1, Math.min(v, e)), c = (n) => {
|
|
15
|
+
s || n < 1 || n > e || n === r || b(n);
|
|
16
|
+
}, y = C(() => {
|
|
17
|
+
const n = 5 + a * 2;
|
|
18
|
+
if (e <= n)
|
|
19
|
+
return Array.from({ length: e }, (o, l) => l + 1);
|
|
20
|
+
const t = Math.max(r - a, 1), f = Math.min(r + a, e), h = t > 2, u = f < e - 2, m = 1, p = e;
|
|
21
|
+
if (!h && u) {
|
|
22
|
+
const o = 3 + 2 * a;
|
|
23
|
+
return [...Array.from({ length: o }, (g, d) => d + 1), "right-ellipsis", p];
|
|
24
|
+
}
|
|
25
|
+
if (h && !u) {
|
|
26
|
+
const o = 3 + 2 * a, l = Array.from({ length: o }, (g, d) => e - o + 1 + d);
|
|
27
|
+
return [m, "left-ellipsis", ...l];
|
|
28
|
+
}
|
|
29
|
+
if (h && u) {
|
|
30
|
+
const o = Array.from(
|
|
31
|
+
{ length: f - t + 1 },
|
|
32
|
+
(l, g) => t + g
|
|
33
|
+
);
|
|
34
|
+
return [m, "left-ellipsis", ...o, "right-ellipsis", p];
|
|
35
|
+
}
|
|
36
|
+
return [];
|
|
37
|
+
}, [e, r, a]);
|
|
38
|
+
return e <= 1 ? null : /* @__PURE__ */ i(
|
|
18
39
|
"nav",
|
|
19
40
|
{
|
|
20
|
-
className:
|
|
41
|
+
className: k("nui-pagination", P),
|
|
21
42
|
"aria-label": "Pagination Navigation",
|
|
22
|
-
|
|
23
|
-
|
|
43
|
+
...w,
|
|
44
|
+
children: /* @__PURE__ */ x("ul", { className: "nui-pagination-list", children: [
|
|
45
|
+
/* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
|
|
24
46
|
"button",
|
|
25
47
|
{
|
|
26
|
-
className: "
|
|
27
|
-
onClick: () => c(
|
|
28
|
-
disabled:
|
|
48
|
+
className: "nui-pagination-btn nui-pagination-btn--nav",
|
|
49
|
+
onClick: () => c(r - 1),
|
|
50
|
+
disabled: s || r === 1,
|
|
29
51
|
"aria-label": "Previous Page",
|
|
30
|
-
children: "
|
|
52
|
+
children: /* @__PURE__ */ i("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ i("polyline", { points: "15 18 9 12 15 6" }) })
|
|
31
53
|
}
|
|
32
|
-
),
|
|
33
|
-
|
|
34
|
-
(
|
|
54
|
+
) }),
|
|
55
|
+
y.map((n) => {
|
|
56
|
+
if (n === "left-ellipsis" || n === "right-ellipsis")
|
|
57
|
+
return /* @__PURE__ */ i("li", { className: "nui-pagination-ellipsis", "aria-hidden": "true", children: /* @__PURE__ */ x("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
58
|
+
/* @__PURE__ */ i("circle", { cx: "12", cy: "12", r: "1" }),
|
|
59
|
+
/* @__PURE__ */ i("circle", { cx: "19", cy: "12", r: "1" }),
|
|
60
|
+
/* @__PURE__ */ i("circle", { cx: "5", cy: "12", r: "1" })
|
|
61
|
+
] }) }, n);
|
|
62
|
+
const t = n === r;
|
|
63
|
+
return /* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
|
|
35
64
|
"button",
|
|
36
65
|
{
|
|
37
|
-
className:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
66
|
+
className: k(
|
|
67
|
+
"nui-pagination-btn",
|
|
68
|
+
t && "nui-pagination-btn--active"
|
|
69
|
+
),
|
|
70
|
+
"aria-current": t ? "page" : void 0,
|
|
71
|
+
"aria-label": t ? `Page ${n}` : `Go to page ${n}`,
|
|
72
|
+
disabled: s,
|
|
73
|
+
onClick: () => c(n),
|
|
74
|
+
children: n
|
|
75
|
+
}
|
|
76
|
+
) }, `page-${n}`);
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ i("li", { children: /* @__PURE__ */ i(
|
|
46
79
|
"button",
|
|
47
80
|
{
|
|
48
|
-
className: "
|
|
49
|
-
onClick: () => c(
|
|
50
|
-
disabled:
|
|
81
|
+
className: "nui-pagination-btn nui-pagination-btn--nav",
|
|
82
|
+
onClick: () => c(r + 1),
|
|
83
|
+
disabled: s || r === e,
|
|
51
84
|
"aria-label": "Next Page",
|
|
52
|
-
children: "
|
|
85
|
+
children: /* @__PURE__ */ i("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ i("polyline", { points: "9 18 15 12 9 6" }) })
|
|
53
86
|
}
|
|
54
|
-
)
|
|
55
|
-
]
|
|
87
|
+
) })
|
|
88
|
+
] })
|
|
56
89
|
}
|
|
57
90
|
);
|
|
58
91
|
}
|
|
59
92
|
export {
|
|
60
|
-
|
|
93
|
+
M as Pagination
|
|
61
94
|
};
|
|
62
95
|
//# sourceMappingURL=Pagination.js.map
|