@nofinite/nui 1.1.2 → 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.js","sources":["../../../src/components/drawer/Drawer.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"Drawer.js","sources":["../../../src/components/drawer/Drawer.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useRef, useEffect, useCallback, useState, forwardRef } from 'react';\nimport { cn } from '../../utils';\nimport { \n Portal, \n onClickOutside, \n trapFocus, \n restoreFocus, \n scrollLock, \n applyInertToSiblings, \n removeInertFromSiblings \n} from '../../utils';\nimport './Drawer.css';\n\n/* ----------------------------------------------------\n Props\n---------------------------------------------------- */\nexport interface DrawerProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Controls the open/closed state of the drawer */\n open: boolean;\n /** Callback fired when the drawer requests to be closed (e.g., Escape key, outside click) */\n onClose: () => void;\n /** The edge of the screen the drawer attaches to. Defaults to 'right' */\n position?: 'left' | 'right' | 'bottom' | 'top';\n /** Prevents the drawer from closing when the Escape key is pressed */\n disableEsc?: boolean;\n /** Prevents the drawer from closing when a click occurs outside the content area */\n disableClickOutside?: boolean;\n /** Custom class name applied to the backdrop overlay */\n overlayClassName?: string;\n}\n\n/* ----------------------------------------------------\n Component\n---------------------------------------------------- */\n\n/**\n * Drawer Component\n * * A sliding panel overlay for auxiliary content.\n * * Architecture Note (2-Step Unmount):\n * To allow smooth CSS exit transitions, the component uses two states:\n * 1. `isMounted`: Controls presence in the React Tree (DOM).\n * 2. `isVisible`: Controls the `data-state` attribute which triggers CSS transforms.\n * Upon closing, `isVisible` flips immediately, then a 300ms timeout delays the `isMounted` flip.\n */\nexport const Drawer = forwardRef<HTMLDivElement, DrawerProps>(\n (\n {\n open,\n onClose,\n position = 'right',\n className,\n overlayClassName,\n children,\n disableEsc = false,\n disableClickOutside = false,\n ...props\n },\n ref\n ) => {\n // 1. Mount & Animation States\n const [isMounted, setIsMounted] = useState(open);\n const [isVisible, setIsVisible] = useState(false);\n\n const overlayRef = useRef<HTMLDivElement | null>(null);\n const internalDrawerRef = useRef<HTMLDivElement | null>(null);\n const previouslyFocused = useRef<HTMLElement | null>(null);\n\n // Merge forwarded ref with internal ref\n const setRefs = useCallback(\n (node: HTMLDivElement) => {\n internalDrawerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref]\n );\n\n const handleClose = useCallback(() => {\n onClose();\n }, [onClose]);\n\n // 2. Handle Entrance & Exit Animations\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout>;\n\n if (open) {\n setIsMounted(true);\n // Micro-delay to ensure the DOM paints the element before applying the active transform class\n timer = setTimeout(() => setIsVisible(true), 15);\n } else {\n setIsVisible(false);\n // Wait for CSS transition (0.3s) to finish before unmounting from DOM\n timer = setTimeout(() => setIsMounted(false), 300);\n }\n\n return () => {\n if (timer) clearTimeout(timer);\n };\n }, [open]);\n\n // 3. Handle Escape Key\n useEffect(() => {\n if (!isVisible || disableEsc) return;\n\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n handleClose();\n }\n };\n\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [isVisible, disableEsc, handleClose]);\n\n // 4. Accessibility & Lifecycle Effects\n useEffect(() => {\n if (!isVisible) return;\n\n // Capture the element that had focus before the drawer opened\n previouslyFocused.current = document.activeElement as HTMLElement;\n\n // Lock body scroll\n scrollLock.lock();\n\n // WAI-ARIA Standard: Hide siblings from screen readers\n const inertTargets = overlayRef.current\n ? applyInertToSiblings(overlayRef.current)\n : [];\n\n // Trap focus inside the drawer\n const trapCleanup = internalDrawerRef.current\n ? trapFocus(internalDrawerRef.current)\n : undefined;\n\n // Click outside\n let cleanupOutside: (() => void) | undefined;\n if (!disableClickOutside && internalDrawerRef.current) {\n cleanupOutside = onClickOutside(internalDrawerRef, handleClose);\n }\n\n return () => {\n cleanupOutside?.();\n trapCleanup?.();\n scrollLock.unlock();\n removeInertFromSiblings(inertTargets);\n restoreFocus(previouslyFocused.current);\n };\n }, [isVisible, disableClickOutside, handleClose]);\n\n if (!isMounted) return null;\n\n return (\n <Portal>\n <div\n ref={overlayRef}\n className={cn('nui-drawer-overlay', overlayClassName)}\n data-state={isVisible ? 'open' : 'closed'}\n aria-hidden=\"true\"\n />\n <div\n ref={setRefs}\n className={cn('nui-drawer', `nui-drawer--${position}`, className)}\n data-state={isVisible ? 'open' : 'closed'}\n role=\"dialog\"\n aria-modal=\"true\"\n {...props}\n >\n {children}\n </div>\n </Portal>\n );\n }\n);\n\nDrawer.displayName = 'Drawer';"],"names":["Drawer","forwardRef","open","onClose","position","className","overlayClassName","children","disableEsc","disableClickOutside","props","ref","isMounted","setIsMounted","useState","isVisible","setIsVisible","overlayRef","useRef","internalDrawerRef","previouslyFocused","setRefs","useCallback","node","handleClose","useEffect","timer","onKey","e","scrollLock","inertTargets","applyInertToSiblings","trapCleanup","trapFocus","cleanupOutside","onClickOutside","removeInertFromSiblings","restoreFocus","Portal","jsx","cn"],"mappings":";;;;;;;;;;AA8CO,MAAMA,IAASC;AAAA,EACpB,CACE;AAAA,IACE,MAAAC;AAAA,IACA,SAAAC;AAAA,IACA,UAAAC,IAAW;AAAA,IACX,WAAAC;AAAA,IACA,kBAAAC;AAAA,IACA,UAAAC;AAAA,IACA,YAAAC,IAAa;AAAA,IACb,qBAAAC,IAAsB;AAAA,IACtB,GAAGC;AAAA,EAAA,GAELC,MACG;AAEH,UAAM,CAACC,GAAWC,CAAY,IAAIC,EAASZ,CAAI,GACzC,CAACa,GAAWC,CAAY,IAAIF,EAAS,EAAK,GAE1CG,IAAaC,EAA8B,IAAI,GAC/CC,IAAoBD,EAA8B,IAAI,GACtDE,IAAoBF,EAA2B,IAAI,GAGnDG,IAAUC;AAAA,MACd,CAACC,MAAyB;AACxB,QAAAJ,EAAkB,UAAUI,GACxB,OAAOZ,KAAQ,aAAYA,EAAIY,CAAI,IAC9BZ,QAAS,UAAUY;AAAA,MAC9B;AAAA,MACA,CAACZ,CAAG;AAAA,IAAA,GAGAa,IAAcF,EAAY,MAAM;AACpC,MAAAnB,EAAA;AAAA,IACF,GAAG,CAACA,CAAO,CAAC;AAuEZ,WApEAsB,EAAU,MAAM;AACd,UAAIC;AAEJ,aAAIxB,KACFW,EAAa,EAAI,GAEjBa,IAAQ,WAAW,MAAMV,EAAa,EAAI,GAAG,EAAE,MAE/CA,EAAa,EAAK,GAElBU,IAAQ,WAAW,MAAMb,EAAa,EAAK,GAAG,GAAG,IAG5C,MAAM;AACX,QAAIa,kBAAoBA,CAAK;AAAA,MAC/B;AAAA,IACF,GAAG,CAACxB,CAAI,CAAC,GAGTuB,EAAU,MAAM;AACd,UAAI,CAACV,KAAaP,EAAY;AAE9B,YAAMmB,IAAQ,CAACC,MAAqB;AAClC,QAAIA,EAAE,QAAQ,aACZA,EAAE,eAAA,GACFJ,EAAA;AAAA,MAEJ;AAEA,sBAAS,iBAAiB,WAAWG,CAAK,GACnC,MAAM,SAAS,oBAAoB,WAAWA,CAAK;AAAA,IAC5D,GAAG,CAACZ,GAAWP,GAAYgB,CAAW,CAAC,GAGvCC,EAAU,MAAM;AACd,UAAI,CAACV,EAAW;AAGhB,MAAAK,EAAkB,UAAU,SAAS,eAGrCS,EAAW,KAAA;AAGX,YAAMC,IAAeb,EAAW,UAC5Bc,EAAqBd,EAAW,OAAO,IACvC,CAAA,GAGEe,IAAcb,EAAkB,UAClCc,EAAUd,EAAkB,OAAO,IACnC;AAGJ,UAAIe;AACJ,aAAI,CAACzB,KAAuBU,EAAkB,YAC5Ce,IAAiBC,EAAehB,GAAmBK,CAAW,IAGzD,MAAM;AACX,QAAAU,IAAA,GACAF,IAAA,GACAH,EAAW,OAAA,GACXO,EAAwBN,CAAY,GACpCO,EAAajB,EAAkB,OAAO;AAAA,MACxC;AAAA,IACF,GAAG,CAACL,GAAWN,GAAqBe,CAAW,CAAC,GAE3CZ,sBAGF0B,GAAA,EACC,UAAA;AAAA,MAAA,gBAAAC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,KAAKtB;AAAA,UACL,WAAWuB,EAAG,sBAAsBlC,CAAgB;AAAA,UACpD,cAAYS,IAAY,SAAS;AAAA,UACjC,eAAY;AAAA,QAAA;AAAA,MAAA;AAAA,MAEd,gBAAAwB;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,KAAKlB;AAAA,UACL,WAAWmB,EAAG,cAAc,eAAepC,CAAQ,IAAIC,CAAS;AAAA,UAChE,cAAYU,IAAY,SAAS;AAAA,UACjC,MAAK;AAAA,UACL,cAAW;AAAA,UACV,GAAGL;AAAA,UAEH,UAAAH;AAAA,QAAA;AAAA,MAAA;AAAA,IACH,GACF,IApBqB;AAAA,EAsBzB;AACF;AAEAP,EAAO,cAAc;"}
|
|
@@ -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 m=require("react/jsx-runtime"),r=require("react");;/* empty css */const E=require("../../utils/restorefocus/restoreFocus.cjs"),D=require("../../utils/cn/cn.cjs"),h=require("../../utils/onclickoutside/onClickOutside.cjs"),v=r.createContext(null);function g(){const u=r.useContext(v);if(!u)throw new Error("Dropdown components must be inside <Dropdown>");return u}const k=r.forwardRef(({children:u,className:o,...i},a)=>{const[s,e]=r.useState(!1),n=r.useRef(null);return r.useEffect(()=>{!s&&n.current&&E.restoreFocus(n.current)},[s]),m.jsx(v.Provider,{value:{open:s,setOpen:e,triggerRef:n},children:m.jsx("div",{ref:a,className:D.cn("nui-dropdown",o),...i,children:u})})});k.displayName="Dropdown";const R=r.forwardRef(({children:u},o)=>{const{open:i,setOpen:a,triggerRef:s}=g();if(r.isValidElement(u)){const e=u,n=e.props.ref??e.ref,l={"aria-haspopup":"menu","aria-expanded":i,onClick:t=>{t.preventDefault(),a(c=>!c),e.props.onClick?.(t)},ref:t=>{s.current=t,typeof o=="function"?o(t):o&&(o.current=t),typeof n=="function"?n(t):n&&typeof n=="object"&&"current"in n&&(n.current=t)}};return r.cloneElement(e,l)}return m.jsx("button",{type:"button",className:"nui-dropdown__trigger",ref:e=>{s.current=e,typeof o=="function"?o(e):o&&(o.current=e)},"aria-haspopup":"menu","aria-expanded":i,onClick:e=>{e.preventDefault(),a(n=>!n)},children:u})});R.displayName="Dropdown.Trigger";const b=r.forwardRef(({className:u,children:o,align:i="start",...a},s)=>{const{open:e,setOpen:n,triggerRef:l}=g(),t=r.useRef(null),c=r.useCallback(f=>{t.current=f,typeof s=="function"?s(f):s&&(s.current=f)},[s]);return r.useEffect(()=>e?h.onClickOutside([t,l],()=>{n(!1)}):void 0,[e,n,l]),r.useEffect(()=>{if(!e)return;const f=d=>{if(d.key==="Escape"){n(!1);return}if(!t.current)return;const p=Array.from(t.current.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])'));if(!p.length)return;const w=p.indexOf(document.activeElement);if(d.key==="ArrowDown"){d.preventDefault();const y=w<p.length-1?w+1:0;p[y]?.focus()}else if(d.key==="ArrowUp"){d.preventDefault();const y=w>0?w-1:p.length-1;p[y]?.focus()}};document.addEventListener("keydown",f);const x=t.current?.querySelector('[role="menuitem"]:not([aria-disabled="true"])');return x&&x.focus(),()=>document.removeEventListener("keydown",f)},[e,n]),e?m.jsx("div",{ref:c,className:D.cn("nui-dropdown__menu",i==="end"&&"nui-dropdown__menu--end",u),role:"menu",...a,children:o}):null});b.displayName="Dropdown.Menu";const C=r.forwardRef(({children:u,onSelect:o,className:i,onClick:a,...s},e)=>{const{setOpen:n}=g(),l=c=>{o?.(),a?.(c),n(!1)},t=c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),l(c))};return m.jsx("div",{ref:e,className:D.cn("nui-dropdown__item",i),role:"menuitem",tabIndex:-1,onClick:l,onKeyDown:t,...s,children:u})});C.displayName="Dropdown.Item";const j=Object.assign(k,{Trigger:R,Menu:b,Item:C});exports.Dropdown=j;
|
|
2
2
|
//# sourceMappingURL=Dropdown.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.cjs","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["/**\r\n * Dropdown.tsx (Fixed Version — No TS Errors)\r\n * -------------------------------------------\r\n * Accessible dropdown menu:\r\n * - Arrow key navigation\r\n * - Roving tabindex\r\n * - ESC and click outside to close\r\n * - Focus restore\r\n * - Portal rendering\r\n * - Fully typed with no TS or ESLint errors\r\n */\r\n\r\nimport React, {\r\n createContext,\r\n useState,\r\n useContext,\r\n useRef,\r\n useEffect,\r\n ReactNode,\r\n} from 'react';\r\n\r\nimport './Dropdown.css';\r\n\r\nimport { Portal, onClickOutside, restoreFocus, createKeyboardNavigation } from '../../utils/index';\r\n\r\n/* ============================================================\r\n * Context Types\r\n * ============================================================ */\r\n\r\ninterface DropdownContextProps {\r\n open: boolean;\r\n setOpen: React.Dispatch<React.SetStateAction<boolean>>;\r\n triggerRef: React.RefObject<HTMLButtonElement | null>;\r\n menuRef: React.RefObject<HTMLDivElement | null>;\r\n registerItem: (el: HTMLElement) => void;\r\n items: React.RefObject<HTMLElement[]>;\r\n}\r\n\r\nconst DropdownContext = createContext<DropdownContextProps | null>(null);\r\n\r\nfunction useDropdown() {\r\n const ctx = useContext(DropdownContext);\r\n if (!ctx) throw new Error('Dropdown components must be inside <Dropdown>');\r\n return ctx;\r\n}\r\n\r\n/* ============================================================\r\n * Dropdown root\r\n * ============================================================ */\r\n\r\nexport function Dropdown({ children }: { children: ReactNode }) {\r\n const [open, setOpen] = useState(false);\r\n\r\n const triggerRef = useRef<HTMLButtonElement>(null);\r\n const menuRef = useRef<HTMLDivElement>(null);\r\n const items = useRef<HTMLElement[]>([]);\r\n\r\n const registerItem = (el: HTMLElement) => {\r\n items.current.push(el);\r\n };\r\n\r\n // Restore focus to trigger when closing\r\n useEffect(() => {\r\n if (!open) restoreFocus(triggerRef.current);\r\n }, [open]);\r\n\r\n return (\r\n <DropdownContext.Provider\r\n value={{\r\n open,\r\n setOpen,\r\n triggerRef,\r\n menuRef,\r\n registerItem,\r\n items,\r\n }}\r\n >\r\n <div className=\"ui-dropdown\">{children}</div>\r\n </DropdownContext.Provider>\r\n );\r\n}\r\n\r\n/* ============================================================\r\n * Trigger\r\n * ============================================================ */\r\n\r\nexport function DropdownTrigger({\r\n children,\r\n className = '',\r\n}: {\r\n children: ReactNode;\r\n className?: string;\r\n}) {\r\n const { open, setOpen, triggerRef } = useDropdown();\r\n\r\n return (\r\n <button\r\n ref={triggerRef}\r\n className={`ui-dropdown-trigger ${className}`}\r\n aria-haspopup=\"menu\"\r\n aria-expanded={open}\r\n onClick={() => setOpen((prev) => !prev)}\r\n >\r\n {children}\r\n </button>\r\n );\r\n}\r\n\r\n/* ============================================================\r\n * Menu\r\n * ============================================================ */\r\n\r\nexport function DropdownMenu({\r\n className = '',\r\n children,\r\n}: {\r\n className?: string;\r\n children: ReactNode;\r\n}) {\r\n const { open, setOpen, menuRef, items } = useDropdown();\r\n\r\n // Click outside\r\n useEffect(() => {\r\n if (!open) return;\r\n return onClickOutside(menuRef, () => setOpen(false));\r\n }, [open, menuRef, setOpen]);\r\n\r\n // ESC\r\n useEffect(() => {\r\n if (!open) return;\r\n\r\n const handler = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') setOpen(false);\r\n };\r\n\r\n document.addEventListener('keydown', handler);\r\n return () => document.removeEventListener('keydown', handler);\r\n }, [open, setOpen]);\r\n\r\n // Keyboard navigation\r\n useEffect(() => {\r\n if (!open) return;\r\n\r\n const menu = menuRef.current;\r\n if (!menu) return;\r\n\r\n const nav = createKeyboardNavigation({\r\n items: items.current,\r\n onSelect: (i) => items.current[i]?.click(),\r\n });\r\n\r\n menu.addEventListener('keydown', nav);\r\n items.current[0]?.focus();\r\n\r\n return () => menu.removeEventListener('keydown', nav);\r\n }, [open, menuRef, items]);\r\n\r\n if (!open) return null;\r\n\r\n return (\r\n <Portal>\r\n <div className=\"ui-dropdown-menu-wrapper\">\r\n <div\r\n ref={menuRef}\r\n className={`ui-dropdown-menu ${className}`}\r\n role=\"menu\"\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n </Portal>\r\n );\r\n}\r\n\r\n/* ============================================================\r\n * Menu Item\r\n * ============================================================ */\r\n\r\nexport function DropdownItem({\r\n children,\r\n onSelect,\r\n className = '',\r\n}: {\r\n children: ReactNode;\r\n onSelect?: () => void;\r\n className?: string;\r\n}) {\r\n const { registerItem, setOpen } = useDropdown();\r\n const itemRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n if (itemRef.current) registerItem(itemRef.current);\r\n }, [registerItem]);\r\n\r\n const handleClick = () => {\r\n onSelect?.();\r\n setOpen(false);\r\n };\r\n\r\n return (\r\n <div\r\n ref={itemRef}\r\n className={`ui-dropdown-item ${className}`}\r\n role=\"menuitem\"\r\n tabIndex={-1}\r\n onClick={handleClick}\r\n >\r\n {children}\r\n </div>\r\n );\r\n}\r\n"],"names":["DropdownContext","createContext","useDropdown","ctx","useContext","Dropdown","children","open","setOpen","useState","triggerRef","useRef","menuRef","items","registerItem","el","useEffect","restoreFocus","jsx","DropdownTrigger","className","prev","DropdownMenu","onClickOutside","handler","e","menu","nav","createKeyboardNavigation","i","Portal","DropdownItem","onSelect","itemRef","handleClick"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dropdown.cjs","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport React, {\n createContext,\n useState,\n useContext,\n useRef,\n useEffect,\n forwardRef,\n useCallback,\n} from 'react';\nimport { cn, onClickOutside, restoreFocus } from '../../utils';\nimport './Dropdown.css';\n\n/* ============================================================\n * Context Types\n * ============================================================ */\n\ninterface DropdownContextProps {\n open: boolean;\n setOpen: React.Dispatch<React.SetStateAction<boolean>>;\n triggerRef: React.RefObject<HTMLButtonElement | null>;\n}\n\nconst DropdownContext = createContext<DropdownContextProps | null>(null);\n\nfunction useDropdown() {\n const ctx = useContext(DropdownContext);\n if (!ctx) throw new Error('Dropdown components must be inside <Dropdown>');\n return ctx;\n}\n\n/* ============================================================\n * 1. Dropdown Root\n * ============================================================ */\n\nexport interface DropdownRootProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n}\n\n/**\n * Dropdown Component (Root)\n * * Implements a Compound Component Architecture.\n * * Provides state and ref context to Trigger, Menu, and Items.\n */\nconst DropdownRoot = forwardRef<HTMLDivElement, DropdownRootProps>(\n ({ children, className, ...props }, ref) => {\n const [open, setOpen] = useState(false);\n const triggerRef = useRef<HTMLButtonElement>(null);\n\n // Restore focus to trigger when closing for WAI-ARIA compliance\n useEffect(() => {\n if (!open && triggerRef.current) {\n restoreFocus(triggerRef.current);\n }\n }, [open]);\n\n return (\n <DropdownContext.Provider value={{ open, setOpen, triggerRef }}>\n <div ref={ref} className={cn(\"nui-dropdown\", className)} {...props}>\n {children}\n </div>\n </DropdownContext.Provider>\n );\n }\n);\nDropdownRoot.displayName = 'Dropdown';\n\n/* ============================================================\n * 2. Dropdown Trigger\n * ============================================================ */\n\nexport interface DropdownTriggerProps {\n children: React.ReactNode; \n}\n\n/**\n * Dropdown Trigger\n * * Handles click events to toggle the menu.\n * * Automatically merges refs and props if a valid React Element (like <Button>) is passed.\n */\nconst DropdownTrigger = forwardRef<HTMLElement, DropdownTriggerProps>(\n ({ children }, ref) => {\n const { open, setOpen, triggerRef } = useDropdown();\n\n // SCENARIO A: The user passed a single React Element (e.g., <Button>)\n if (React.isValidElement(children)) {\n const child = children as React.ReactElement<React.HTMLProps<HTMLElement>>;\n const childRef = child.props.ref ?? (child as unknown as { ref?: React.Ref<HTMLElement> }).ref;\n\n // We explicitly type the props for the cloned element here\n const triggerProps: React.HTMLProps<HTMLElement> = {\n 'aria-haspopup': 'menu',\n 'aria-expanded': open,\n onClick: (e: React.MouseEvent<HTMLElement>) => {\n e.preventDefault();\n setOpen((prev) => !prev);\n child.props.onClick?.(e);\n },\n ref: (node: HTMLElement | null) => {\n triggerRef.current = node as HTMLButtonElement;\n \n if (typeof ref === 'function') ref(node);\n else if (ref) (ref as { current: HTMLElement | null }).current = node;\n\n if (typeof childRef === 'function') childRef(node);\n else if (childRef && typeof childRef === 'object' && 'current' in childRef) {\n (childRef as { current: HTMLElement | null }).current = node;\n }\n }\n };\n\n return React.cloneElement(child, triggerProps);\n }\n\n // SCENARIO B: The user passed plain text, numbers, or multiple elements\n // We apply standard HTML attributes directly without spreading\n return (\n <button\n type=\"button\"\n className=\"nui-dropdown__trigger\"\n ref={(node) => {\n triggerRef.current = node;\n \n if (typeof ref === 'function') ref(node);\n else if (ref) (ref as { current: HTMLButtonElement | null }).current = node;\n }}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault();\n setOpen((prev) => !prev);\n }}\n >\n {children}\n </button>\n );\n }\n);\nDropdownTrigger.displayName = 'Dropdown.Trigger';\n\n/* ============================================================\n * 3. Dropdown Menu\n * ============================================================ */\n\nexport interface DropdownMenuProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n /** Aligns the popover menu relative to the trigger. Defaults to 'start' */\n align?: 'start' | 'end';\n}\n\n/**\n * Dropdown Menu\n * * The popover container.\n * * Handles Click Outside detection and Arrow Key Navigation.\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ className, children, align = 'start', ...props }, ref) => {\n const { open, setOpen, triggerRef } = useDropdown();\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Merge refs\n const setRefs = useCallback(\n (node: HTMLDivElement) => {\n menuRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref]\n );\n\n // Click outside handler\n useEffect(() => {\n if (!open) return;\n // Pass both refs in an array so clicking the trigger doesn't immediately close it via the outside listener\n const cleanup = onClickOutside([menuRef, triggerRef], () => {\n setOpen(false);\n });\n return cleanup;\n }, [open, setOpen, triggerRef]);\n\n // Keyboard Navigation (ESC, ArrowUp, ArrowDown)\n useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setOpen(false);\n return;\n }\n\n if (!menuRef.current) return;\n \n // Find all focusable items inside the menu\n const items = Array.from(\n menuRef.current.querySelectorAll('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n ) as HTMLElement[];\n \n if (!items.length) return;\n\n const currentIndex = items.indexOf(document.activeElement as HTMLElement);\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n const nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n items[nextIndex]?.focus();\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n const prevIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n items[prevIndex]?.focus();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n \n // Auto-focus first item on open\n const firstItem = menuRef.current?.querySelector('[role=\"menuitem\"]:not([aria-disabled=\"true\"])') as HTMLElement;\n if (firstItem) firstItem.focus();\n\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [open, setOpen]);\n\n if (!open) return null;\n\n return (\n <div\n ref={setRefs}\n className={cn(\n \"nui-dropdown__menu\", \n align === 'end' && \"nui-dropdown__menu--end\", \n className\n )}\n role=\"menu\"\n {...props}\n >\n {children}\n </div>\n );\n }\n);\nDropdownMenu.displayName = 'Dropdown.Menu';\n\n/* ============================================================\n * 4. Dropdown Item\n * ============================================================ */\n\nexport interface DropdownItemProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n /** Callback fired when the item is selected via click or keyboard */\n onSelect?: () => void;\n}\n\n/**\n * Dropdown Item\n * * Handles selection and automatically closes the parent menu.\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n ({ children, onSelect, className, onClick, ...props }, ref) => {\n const { setOpen } = useDropdown();\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n onSelect?.();\n onClick?.(e);\n setOpen(false);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick(e as unknown as React.MouseEvent<HTMLDivElement>);\n }\n };\n\n return (\n <div\n ref={ref}\n className={cn(\"nui-dropdown__item\", className)}\n role=\"menuitem\"\n tabIndex={-1} // -1 allows programmatic focus via arrow keys\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\nDropdownItem.displayName = 'Dropdown.Item';\n\n/* ============================================================\n * Export\n * ============================================================ */\n\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n});"],"names":["DropdownContext","createContext","useDropdown","ctx","useContext","DropdownRoot","forwardRef","children","className","props","ref","open","setOpen","useState","triggerRef","useRef","useEffect","restoreFocus","jsx","cn","DropdownTrigger","React","child","childRef","triggerProps","e","prev","node","DropdownMenu","align","menuRef","setRefs","useCallback","onClickOutside","handleKeyDown","items","currentIndex","nextIndex","prevIndex","firstItem","DropdownItem","onSelect","onClick","handleClick","Dropdown"],"mappings":"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"}
|
|
@@ -1,115 +1,141 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { useState as
|
|
1
|
+
import { jsx as d } from "react/jsx-runtime";
|
|
2
|
+
import x, { forwardRef as w, useState as N, useRef as h, useEffect as D, createContext as _, useCallback as O, useContext as A } from "react";
|
|
3
3
|
/* empty css */
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { onClickOutside as
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return o;
|
|
4
|
+
import { restoreFocus as j } from "../../utils/restorefocus/restoreFocus.js";
|
|
5
|
+
import { cn as g } from "../../utils/cn/cn.js";
|
|
6
|
+
import { onClickOutside as K } from "../../utils/onclickoutside/onClickOutside.js";
|
|
7
|
+
const C = _(null);
|
|
8
|
+
function v() {
|
|
9
|
+
const i = A(C);
|
|
10
|
+
if (!i) throw new Error("Dropdown components must be inside <Dropdown>");
|
|
11
|
+
return i;
|
|
13
12
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
n
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}) {
|
|
39
|
-
const { open: e, setOpen: r, triggerRef: t } = p();
|
|
40
|
-
return /* @__PURE__ */ s(
|
|
41
|
-
"button",
|
|
42
|
-
{
|
|
43
|
-
ref: t,
|
|
44
|
-
className: `ui-dropdown-trigger ${u}`,
|
|
45
|
-
"aria-haspopup": "menu",
|
|
46
|
-
"aria-expanded": e,
|
|
47
|
-
onClick: () => r((n) => !n),
|
|
48
|
-
children: o
|
|
13
|
+
const R = w(
|
|
14
|
+
({ children: i, className: r, ...u }, c) => {
|
|
15
|
+
const [o, e] = N(!1), n = h(null);
|
|
16
|
+
return D(() => {
|
|
17
|
+
!o && n.current && j(n.current);
|
|
18
|
+
}, [o]), /* @__PURE__ */ d(C.Provider, { value: { open: o, setOpen: e, triggerRef: n }, children: /* @__PURE__ */ d("div", { ref: c, className: g("nui-dropdown", r), ...u, children: i }) });
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
R.displayName = "Dropdown";
|
|
22
|
+
const b = w(
|
|
23
|
+
({ children: i }, r) => {
|
|
24
|
+
const { open: u, setOpen: c, triggerRef: o } = v();
|
|
25
|
+
if (x.isValidElement(i)) {
|
|
26
|
+
const e = i, n = e.props.ref ?? e.ref, p = {
|
|
27
|
+
"aria-haspopup": "menu",
|
|
28
|
+
"aria-expanded": u,
|
|
29
|
+
onClick: (t) => {
|
|
30
|
+
t.preventDefault(), c((s) => !s), e.props.onClick?.(t);
|
|
31
|
+
},
|
|
32
|
+
ref: (t) => {
|
|
33
|
+
o.current = t, typeof r == "function" ? r(t) : r && (r.current = t), typeof n == "function" ? n(t) : n && typeof n == "object" && "current" in n && (n.current = t);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return x.cloneElement(e, p);
|
|
49
37
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
38
|
+
return /* @__PURE__ */ d(
|
|
39
|
+
"button",
|
|
40
|
+
{
|
|
41
|
+
type: "button",
|
|
42
|
+
className: "nui-dropdown__trigger",
|
|
43
|
+
ref: (e) => {
|
|
44
|
+
o.current = e, typeof r == "function" ? r(e) : r && (r.current = e);
|
|
45
|
+
},
|
|
46
|
+
"aria-haspopup": "menu",
|
|
47
|
+
"aria-expanded": u,
|
|
48
|
+
onClick: (e) => {
|
|
49
|
+
e.preventDefault(), c((n) => !n);
|
|
50
|
+
},
|
|
51
|
+
children: i
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
b.displayName = "Dropdown.Trigger";
|
|
57
|
+
const E = w(
|
|
58
|
+
({ className: i, children: r, align: u = "start", ...c }, o) => {
|
|
59
|
+
const { open: e, setOpen: n, triggerRef: p } = v(), t = h(null), s = O(
|
|
60
|
+
(a) => {
|
|
61
|
+
t.current = a, typeof o == "function" ? o(a) : o && (o.current = a);
|
|
62
|
+
},
|
|
63
|
+
[o]
|
|
64
|
+
);
|
|
65
|
+
return D(() => e ? K([t, p], () => {
|
|
66
|
+
n(!1);
|
|
67
|
+
}) : void 0, [e, n, p]), D(() => {
|
|
68
|
+
if (!e) return;
|
|
69
|
+
const a = (f) => {
|
|
70
|
+
if (f.key === "Escape") {
|
|
71
|
+
n(!1);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!t.current) return;
|
|
75
|
+
const l = Array.from(
|
|
76
|
+
t.current.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')
|
|
77
|
+
);
|
|
78
|
+
if (!l.length) return;
|
|
79
|
+
const m = l.indexOf(document.activeElement);
|
|
80
|
+
if (f.key === "ArrowDown") {
|
|
81
|
+
f.preventDefault();
|
|
82
|
+
const y = m < l.length - 1 ? m + 1 : 0;
|
|
83
|
+
l[y]?.focus();
|
|
84
|
+
} else if (f.key === "ArrowUp") {
|
|
85
|
+
f.preventDefault();
|
|
86
|
+
const y = m > 0 ? m - 1 : l.length - 1;
|
|
87
|
+
l[y]?.focus();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
document.addEventListener("keydown", a);
|
|
91
|
+
const k = t.current?.querySelector('[role="menuitem"]:not([aria-disabled="true"])');
|
|
92
|
+
return k && k.focus(), () => document.removeEventListener("keydown", a);
|
|
93
|
+
}, [e, n]), e ? /* @__PURE__ */ d(
|
|
94
|
+
"div",
|
|
95
|
+
{
|
|
96
|
+
ref: s,
|
|
97
|
+
className: g(
|
|
98
|
+
"nui-dropdown__menu",
|
|
99
|
+
u === "end" && "nui-dropdown__menu--end",
|
|
100
|
+
i
|
|
101
|
+
),
|
|
102
|
+
role: "menu",
|
|
103
|
+
...c,
|
|
104
|
+
children: r
|
|
105
|
+
}
|
|
106
|
+
) : null;
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
E.displayName = "Dropdown.Menu";
|
|
110
|
+
const I = w(
|
|
111
|
+
({ children: i, onSelect: r, className: u, onClick: c, ...o }, e) => {
|
|
112
|
+
const { setOpen: n } = v(), p = (s) => {
|
|
113
|
+
r?.(), c?.(s), n(!1);
|
|
114
|
+
}, t = (s) => {
|
|
115
|
+
(s.key === "Enter" || s.key === " ") && (s.preventDefault(), p(s));
|
|
64
116
|
};
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
children: o,
|
|
87
|
-
onSelect: u,
|
|
88
|
-
className: e = ""
|
|
89
|
-
}) {
|
|
90
|
-
const { registerItem: r, setOpen: t } = p(), n = m(null);
|
|
91
|
-
d(() => {
|
|
92
|
-
n.current && r(n.current);
|
|
93
|
-
}, [r]);
|
|
94
|
-
const i = () => {
|
|
95
|
-
u?.(), t(!1);
|
|
96
|
-
};
|
|
97
|
-
return /* @__PURE__ */ s(
|
|
98
|
-
"div",
|
|
99
|
-
{
|
|
100
|
-
ref: n,
|
|
101
|
-
className: `ui-dropdown-item ${e}`,
|
|
102
|
-
role: "menuitem",
|
|
103
|
-
tabIndex: -1,
|
|
104
|
-
onClick: i,
|
|
105
|
-
children: o
|
|
106
|
-
}
|
|
107
|
-
);
|
|
108
|
-
}
|
|
117
|
+
return /* @__PURE__ */ d(
|
|
118
|
+
"div",
|
|
119
|
+
{
|
|
120
|
+
ref: e,
|
|
121
|
+
className: g("nui-dropdown__item", u),
|
|
122
|
+
role: "menuitem",
|
|
123
|
+
tabIndex: -1,
|
|
124
|
+
onClick: p,
|
|
125
|
+
onKeyDown: t,
|
|
126
|
+
...o,
|
|
127
|
+
children: i
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
I.displayName = "Dropdown.Item";
|
|
133
|
+
const F = Object.assign(R, {
|
|
134
|
+
Trigger: b,
|
|
135
|
+
Menu: E,
|
|
136
|
+
Item: I
|
|
137
|
+
});
|
|
109
138
|
export {
|
|
110
|
-
|
|
111
|
-
$ as DropdownItem,
|
|
112
|
-
L as DropdownMenu,
|
|
113
|
-
I as DropdownTrigger
|
|
139
|
+
F as Dropdown
|
|
114
140
|
};
|
|
115
141
|
//# sourceMappingURL=Dropdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["/**\r\n * Dropdown.tsx (Fixed Version — No TS Errors)\r\n * -------------------------------------------\r\n * Accessible dropdown menu:\r\n * - Arrow key navigation\r\n * - Roving tabindex\r\n * - ESC and click outside to close\r\n * - Focus restore\r\n * - Portal rendering\r\n * - Fully typed with no TS or ESLint errors\r\n */\r\n\r\nimport React, {\r\n createContext,\r\n useState,\r\n useContext,\r\n useRef,\r\n useEffect,\r\n ReactNode,\r\n} from 'react';\r\n\r\nimport './Dropdown.css';\r\n\r\nimport { Portal, onClickOutside, restoreFocus, createKeyboardNavigation } from '../../utils/index';\r\n\r\n/* ============================================================\r\n * Context Types\r\n * ============================================================ */\r\n\r\ninterface DropdownContextProps {\r\n open: boolean;\r\n setOpen: React.Dispatch<React.SetStateAction<boolean>>;\r\n triggerRef: React.RefObject<HTMLButtonElement | null>;\r\n menuRef: React.RefObject<HTMLDivElement | null>;\r\n registerItem: (el: HTMLElement) => void;\r\n items: React.RefObject<HTMLElement[]>;\r\n}\r\n\r\nconst DropdownContext = createContext<DropdownContextProps | null>(null);\r\n\r\nfunction useDropdown() {\r\n const ctx = useContext(DropdownContext);\r\n if (!ctx) throw new Error('Dropdown components must be inside <Dropdown>');\r\n return ctx;\r\n}\r\n\r\n/* ============================================================\r\n * Dropdown root\r\n * ============================================================ */\r\n\r\nexport function Dropdown({ children }: { children: ReactNode }) {\r\n const [open, setOpen] = useState(false);\r\n\r\n const triggerRef = useRef<HTMLButtonElement>(null);\r\n const menuRef = useRef<HTMLDivElement>(null);\r\n const items = useRef<HTMLElement[]>([]);\r\n\r\n const registerItem = (el: HTMLElement) => {\r\n items.current.push(el);\r\n };\r\n\r\n // Restore focus to trigger when closing\r\n useEffect(() => {\r\n if (!open) restoreFocus(triggerRef.current);\r\n }, [open]);\r\n\r\n return (\r\n <DropdownContext.Provider\r\n value={{\r\n open,\r\n setOpen,\r\n triggerRef,\r\n menuRef,\r\n registerItem,\r\n items,\r\n }}\r\n >\r\n <div className=\"ui-dropdown\">{children}</div>\r\n </DropdownContext.Provider>\r\n );\r\n}\r\n\r\n/* ============================================================\r\n * Trigger\r\n * ============================================================ */\r\n\r\nexport function DropdownTrigger({\r\n children,\r\n className = '',\r\n}: {\r\n children: ReactNode;\r\n className?: string;\r\n}) {\r\n const { open, setOpen, triggerRef } = useDropdown();\r\n\r\n return (\r\n <button\r\n ref={triggerRef}\r\n className={`ui-dropdown-trigger ${className}`}\r\n aria-haspopup=\"menu\"\r\n aria-expanded={open}\r\n onClick={() => setOpen((prev) => !prev)}\r\n >\r\n {children}\r\n </button>\r\n );\r\n}\r\n\r\n/* ============================================================\r\n * Menu\r\n * ============================================================ */\r\n\r\nexport function DropdownMenu({\r\n className = '',\r\n children,\r\n}: {\r\n className?: string;\r\n children: ReactNode;\r\n}) {\r\n const { open, setOpen, menuRef, items } = useDropdown();\r\n\r\n // Click outside\r\n useEffect(() => {\r\n if (!open) return;\r\n return onClickOutside(menuRef, () => setOpen(false));\r\n }, [open, menuRef, setOpen]);\r\n\r\n // ESC\r\n useEffect(() => {\r\n if (!open) return;\r\n\r\n const handler = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') setOpen(false);\r\n };\r\n\r\n document.addEventListener('keydown', handler);\r\n return () => document.removeEventListener('keydown', handler);\r\n }, [open, setOpen]);\r\n\r\n // Keyboard navigation\r\n useEffect(() => {\r\n if (!open) return;\r\n\r\n const menu = menuRef.current;\r\n if (!menu) return;\r\n\r\n const nav = createKeyboardNavigation({\r\n items: items.current,\r\n onSelect: (i) => items.current[i]?.click(),\r\n });\r\n\r\n menu.addEventListener('keydown', nav);\r\n items.current[0]?.focus();\r\n\r\n return () => menu.removeEventListener('keydown', nav);\r\n }, [open, menuRef, items]);\r\n\r\n if (!open) return null;\r\n\r\n return (\r\n <Portal>\r\n <div className=\"ui-dropdown-menu-wrapper\">\r\n <div\r\n ref={menuRef}\r\n className={`ui-dropdown-menu ${className}`}\r\n role=\"menu\"\r\n >\r\n {children}\r\n </div>\r\n </div>\r\n </Portal>\r\n );\r\n}\r\n\r\n/* ============================================================\r\n * Menu Item\r\n * ============================================================ */\r\n\r\nexport function DropdownItem({\r\n children,\r\n onSelect,\r\n className = '',\r\n}: {\r\n children: ReactNode;\r\n onSelect?: () => void;\r\n className?: string;\r\n}) {\r\n const { registerItem, setOpen } = useDropdown();\r\n const itemRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n if (itemRef.current) registerItem(itemRef.current);\r\n }, [registerItem]);\r\n\r\n const handleClick = () => {\r\n onSelect?.();\r\n setOpen(false);\r\n };\r\n\r\n return (\r\n <div\r\n ref={itemRef}\r\n className={`ui-dropdown-item ${className}`}\r\n role=\"menuitem\"\r\n tabIndex={-1}\r\n onClick={handleClick}\r\n >\r\n {children}\r\n </div>\r\n );\r\n}\r\n"],"names":["DropdownContext","createContext","useDropdown","ctx","useContext","Dropdown","children","open","setOpen","useState","triggerRef","useRef","menuRef","items","registerItem","el","useEffect","restoreFocus","jsx","DropdownTrigger","className","prev","DropdownMenu","onClickOutside","handler","e","menu","nav","createKeyboardNavigation","i","Portal","DropdownItem","onSelect","itemRef","handleClick"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport React, {\n createContext,\n useState,\n useContext,\n useRef,\n useEffect,\n forwardRef,\n useCallback,\n} from 'react';\nimport { cn, onClickOutside, restoreFocus } from '../../utils';\nimport './Dropdown.css';\n\n/* ============================================================\n * Context Types\n * ============================================================ */\n\ninterface DropdownContextProps {\n open: boolean;\n setOpen: React.Dispatch<React.SetStateAction<boolean>>;\n triggerRef: React.RefObject<HTMLButtonElement | null>;\n}\n\nconst DropdownContext = createContext<DropdownContextProps | null>(null);\n\nfunction useDropdown() {\n const ctx = useContext(DropdownContext);\n if (!ctx) throw new Error('Dropdown components must be inside <Dropdown>');\n return ctx;\n}\n\n/* ============================================================\n * 1. Dropdown Root\n * ============================================================ */\n\nexport interface DropdownRootProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n}\n\n/**\n * Dropdown Component (Root)\n * * Implements a Compound Component Architecture.\n * * Provides state and ref context to Trigger, Menu, and Items.\n */\nconst DropdownRoot = forwardRef<HTMLDivElement, DropdownRootProps>(\n ({ children, className, ...props }, ref) => {\n const [open, setOpen] = useState(false);\n const triggerRef = useRef<HTMLButtonElement>(null);\n\n // Restore focus to trigger when closing for WAI-ARIA compliance\n useEffect(() => {\n if (!open && triggerRef.current) {\n restoreFocus(triggerRef.current);\n }\n }, [open]);\n\n return (\n <DropdownContext.Provider value={{ open, setOpen, triggerRef }}>\n <div ref={ref} className={cn(\"nui-dropdown\", className)} {...props}>\n {children}\n </div>\n </DropdownContext.Provider>\n );\n }\n);\nDropdownRoot.displayName = 'Dropdown';\n\n/* ============================================================\n * 2. Dropdown Trigger\n * ============================================================ */\n\nexport interface DropdownTriggerProps {\n children: React.ReactNode; \n}\n\n/**\n * Dropdown Trigger\n * * Handles click events to toggle the menu.\n * * Automatically merges refs and props if a valid React Element (like <Button>) is passed.\n */\nconst DropdownTrigger = forwardRef<HTMLElement, DropdownTriggerProps>(\n ({ children }, ref) => {\n const { open, setOpen, triggerRef } = useDropdown();\n\n // SCENARIO A: The user passed a single React Element (e.g., <Button>)\n if (React.isValidElement(children)) {\n const child = children as React.ReactElement<React.HTMLProps<HTMLElement>>;\n const childRef = child.props.ref ?? (child as unknown as { ref?: React.Ref<HTMLElement> }).ref;\n\n // We explicitly type the props for the cloned element here\n const triggerProps: React.HTMLProps<HTMLElement> = {\n 'aria-haspopup': 'menu',\n 'aria-expanded': open,\n onClick: (e: React.MouseEvent<HTMLElement>) => {\n e.preventDefault();\n setOpen((prev) => !prev);\n child.props.onClick?.(e);\n },\n ref: (node: HTMLElement | null) => {\n triggerRef.current = node as HTMLButtonElement;\n \n if (typeof ref === 'function') ref(node);\n else if (ref) (ref as { current: HTMLElement | null }).current = node;\n\n if (typeof childRef === 'function') childRef(node);\n else if (childRef && typeof childRef === 'object' && 'current' in childRef) {\n (childRef as { current: HTMLElement | null }).current = node;\n }\n }\n };\n\n return React.cloneElement(child, triggerProps);\n }\n\n // SCENARIO B: The user passed plain text, numbers, or multiple elements\n // We apply standard HTML attributes directly without spreading\n return (\n <button\n type=\"button\"\n className=\"nui-dropdown__trigger\"\n ref={(node) => {\n triggerRef.current = node;\n \n if (typeof ref === 'function') ref(node);\n else if (ref) (ref as { current: HTMLButtonElement | null }).current = node;\n }}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault();\n setOpen((prev) => !prev);\n }}\n >\n {children}\n </button>\n );\n }\n);\nDropdownTrigger.displayName = 'Dropdown.Trigger';\n\n/* ============================================================\n * 3. Dropdown Menu\n * ============================================================ */\n\nexport interface DropdownMenuProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n /** Aligns the popover menu relative to the trigger. Defaults to 'start' */\n align?: 'start' | 'end';\n}\n\n/**\n * Dropdown Menu\n * * The popover container.\n * * Handles Click Outside detection and Arrow Key Navigation.\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ className, children, align = 'start', ...props }, ref) => {\n const { open, setOpen, triggerRef } = useDropdown();\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Merge refs\n const setRefs = useCallback(\n (node: HTMLDivElement) => {\n menuRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref]\n );\n\n // Click outside handler\n useEffect(() => {\n if (!open) return;\n // Pass both refs in an array so clicking the trigger doesn't immediately close it via the outside listener\n const cleanup = onClickOutside([menuRef, triggerRef], () => {\n setOpen(false);\n });\n return cleanup;\n }, [open, setOpen, triggerRef]);\n\n // Keyboard Navigation (ESC, ArrowUp, ArrowDown)\n useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setOpen(false);\n return;\n }\n\n if (!menuRef.current) return;\n \n // Find all focusable items inside the menu\n const items = Array.from(\n menuRef.current.querySelectorAll('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n ) as HTMLElement[];\n \n if (!items.length) return;\n\n const currentIndex = items.indexOf(document.activeElement as HTMLElement);\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n const nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n items[nextIndex]?.focus();\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n const prevIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n items[prevIndex]?.focus();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n \n // Auto-focus first item on open\n const firstItem = menuRef.current?.querySelector('[role=\"menuitem\"]:not([aria-disabled=\"true\"])') as HTMLElement;\n if (firstItem) firstItem.focus();\n\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [open, setOpen]);\n\n if (!open) return null;\n\n return (\n <div\n ref={setRefs}\n className={cn(\n \"nui-dropdown__menu\", \n align === 'end' && \"nui-dropdown__menu--end\", \n className\n )}\n role=\"menu\"\n {...props}\n >\n {children}\n </div>\n );\n }\n);\nDropdownMenu.displayName = 'Dropdown.Menu';\n\n/* ============================================================\n * 4. Dropdown Item\n * ============================================================ */\n\nexport interface DropdownItemProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n /** Callback fired when the item is selected via click or keyboard */\n onSelect?: () => void;\n}\n\n/**\n * Dropdown Item\n * * Handles selection and automatically closes the parent menu.\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n ({ children, onSelect, className, onClick, ...props }, ref) => {\n const { setOpen } = useDropdown();\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n onSelect?.();\n onClick?.(e);\n setOpen(false);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick(e as unknown as React.MouseEvent<HTMLDivElement>);\n }\n };\n\n return (\n <div\n ref={ref}\n className={cn(\"nui-dropdown__item\", className)}\n role=\"menuitem\"\n tabIndex={-1} // -1 allows programmatic focus via arrow keys\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\nDropdownItem.displayName = 'Dropdown.Item';\n\n/* ============================================================\n * Export\n * ============================================================ */\n\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n});"],"names":["DropdownContext","createContext","useDropdown","ctx","useContext","DropdownRoot","forwardRef","children","className","props","ref","open","setOpen","useState","triggerRef","useRef","useEffect","restoreFocus","jsx","cn","DropdownTrigger","React","child","childRef","triggerProps","e","prev","node","DropdownMenu","align","menuRef","setRefs","useCallback","onClickOutside","handleKeyDown","items","currentIndex","nextIndex","prevIndex","firstItem","DropdownItem","onSelect","onClick","handleClick","Dropdown"],"mappings":"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"}
|
|
@@ -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"),h=require("react");;/* empty css */const g=require("../../utils/cn/cn.cjs");function C(r,u=2){if(!+r)return"0 Bytes";const s=1024,a=u<0?0:u,p=["Bytes","KB","MB","GB","TB"],o=Math.floor(Math.log(r)/Math.log(s));return`${parseFloat((r/Math.pow(s,o)).toFixed(a))} ${p[o]}`}function $({value:r,defaultValue:u,onChange:s,multiple:a=!1,accept:p,maxSize:o,className:m,placeholder:k="Drag & drop files here, or click to browse",disabled:i=!1}){const l=h.useRef(null),f=r!==void 0,[y,v]=h.useState(u||[]),c=f?r:y,[N,x]=h.useState(!1),j=h.useCallback(e=>{let t=e;o&&(t=e.filter(L=>L.size<=o));const d=a?[...c,...t]:[t[0]].filter(Boolean);f||v(d),s?.(d)},[c,a,o,f,s]),B=e=>{if(i)return;const t=c.filter(d=>d!==e);f||v(t),s?.(t)},D=e=>{e.preventDefault(),e.stopPropagation(),i||x(!0)},F=e=>{e.preventDefault(),e.stopPropagation(),x(!1)},M=e=>{e.preventDefault(),e.stopPropagation(),x(!1),!i&&e.dataTransfer.files&&e.dataTransfer.files.length>0&&j(Array.from(e.dataTransfer.files))},w=e=>{e.target.files&&e.target.files.length>0&&j(Array.from(e.target.files)),l.current&&(l.current.value="")};return n.jsxs("div",{className:g.cn("nui-file-uploader",m),children:[n.jsxs("div",{role:"button",tabIndex:i?-1:0,"aria-label":"Upload files","aria-disabled":i,className:g.cn("nui-file-dropzone",N&&"dragover",i&&"disabled"),onClick:()=>!i&&l.current?.click(),onKeyDown:e=>{!i&&(e.key==="Enter"||e.key===" ")&&(e.preventDefault(),l.current?.click())},onDragOver:D,onDragLeave:F,onDrop:M,children:[n.jsxs("svg",{className:"nui-file-icon",width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[n.jsx("path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"}),n.jsx("polyline",{points:"17 8 12 3 7 8"}),n.jsx("line",{x1:"12",y1:"3",x2:"12",y2:"15"})]}),n.jsx("span",{className:"nui-file-placeholder",children:k})]}),n.jsx("input",{ref:l,type:"file","data-testid":"nui-file-input",accept:p,multiple:a,disabled:i,onChange:w,className:"nui-file-hidden-input",tabIndex:-1,"aria-hidden":"true"}),c.length>0&&n.jsx("ul",{className:"nui-file-list","aria-label":"Selected files",children:c.map(e=>{const t=`${e.name}-${e.size}-${e.lastModified}`;return n.jsxs("li",{className:"nui-file-item",children:[n.jsxs("div",{className:"nui-file-info",children:[n.jsxs("svg",{className:"nui-file-item-icon",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("path",{d:"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"}),n.jsx("polyline",{points:"13 2 13 9 20 9"})]}),n.jsxs("div",{className:"nui-file-text",children:[n.jsx("span",{className:"nui-file-name",children:e.name}),n.jsx("span",{className:"nui-file-size",children:C(e.size)})]})]}),n.jsx("button",{type:"button",className:"nui-file-remove","aria-label":`Remove ${e.name}`,onClick:()=>B(e),disabled:i,children:n.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[n.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),n.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]},t)})})]})}exports.FileUploader=$;
|
|
2
2
|
//# sourceMappingURL=FileUploader.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileUploader.cjs","sources":["../../../src/components/fileuploader/FileUploader.tsx"],"sourcesContent":["/**\r\n * FileUploader.tsx — FINAL VERSION\r\n * --------------------------------\r\n * Features:\r\n * - Drag & drop\r\n * - Click to upload\r\n * - Keyboard activate\r\n * - File list preview\r\n * - Remove file\r\n * - Accept filters\r\n * - Multiple uploads\r\n */\r\n\r\nimport { useRef, useState, useCallback, DragEvent, ChangeEvent } from 'react';\r\nimport './FileUploader.css';\r\n\r\nexport interface FileUploaderProps {\r\n multiple?: boolean;\r\n accept?: string;\r\n onChange?: (files: File[]) => void;\r\n className?: string;\r\n placeholder?: string;\r\n}\r\n\r\nexport function FileUploader({\r\n multiple = false,\r\n accept,\r\n onChange,\r\n className = '',\r\n placeholder = 'Drag files here or click to upload',\r\n}: FileUploaderProps) {\r\n const inputRef = useRef<HTMLInputElement | null>(null);\r\n const [files, setFiles] = useState<File[]>([]);\r\n const [dragOver, setDragOver] = useState(false);\r\n\r\n const updateFiles = useCallback(\r\n (newFiles: File[]) => {\r\n setFiles(newFiles);\r\n onChange?.(newFiles);\r\n },\r\n [onChange]\r\n );\r\n\r\n const handleDrop = (e: DragEvent) => {\r\n e.preventDefault();\r\n setDragOver(false);\r\n\r\n const dropped = Array.from(e.dataTransfer.files);\r\n\r\n if (!multiple) {\r\n updateFiles([dropped[0]]);\r\n return;\r\n }\r\n\r\n updateFiles([...files, ...dropped]);\r\n };\r\n\r\n const handleSelect = (e: ChangeEvent<HTMLInputElement>) => {\r\n const selected = e.target.files ? Array.from(e.target.files) : [];\r\n if (!multiple) {\r\n updateFiles([selected[0]]);\r\n return;\r\n }\r\n updateFiles([...files, ...selected]);\r\n };\r\n\r\n const removeFile = (index: number) => {\r\n const newList = files.filter((_, i) => i !== index);\r\n updateFiles(newList);\r\n };\r\n\r\n return (\r\n <div className={`ui-fileupload ${className}`}>\r\n {/* DROP ZONE */}\r\n <div\r\n className={`ui-fileupload-dropzone ${dragOver ? 'dragover' : ''}`}\r\n tabIndex={0}\r\n role=\"button\"\r\n aria-label=\"Upload files\"\r\n onClick={() => inputRef.current?.click()}\r\n onKeyDown={(e) => {\r\n if (e.key === 'Enter' || e.key === ' ') inputRef.current?.click();\r\n }}\r\n onDragOver={(e) => {\r\n e.preventDefault();\r\n setDragOver(true);\r\n }}\r\n onDragLeave={() => setDragOver(false)}\r\n onDrop={handleDrop}\r\n >\r\n <span>{placeholder}</span>\r\n </div>\r\n\r\n {/* HIDDEN INPUT */}\r\n <input\r\n ref={inputRef}\r\n type=\"file\"\r\n accept={accept}\r\n multiple={multiple}\r\n style={{ display: 'none' }}\r\n onChange={handleSelect}\r\n />\r\n\r\n {/* FILE LIST */}\r\n {files.length > 0 && (\r\n <ul className=\"ui-fileupload-list\">\r\n {files.map((file, i) => (\r\n <li key={i} className=\"ui-fileupload-item\">\r\n <span className=\"ui-fileupload-filename\">{file.name}</span>\r\n <button\r\n className=\"ui-fileupload-remove\"\r\n aria-label=\"Remove file\"\r\n onClick={() => removeFile(i)}\r\n >\r\n ×\r\n </button>\r\n </li>\r\n ))}\r\n </ul>\r\n )}\r\n </div>\r\n );\r\n}\r\n"],"names":["FileUploader","multiple","accept","onChange","className","placeholder","inputRef","useRef","files","setFiles","useState","dragOver","setDragOver","updateFiles","useCallback","newFiles","handleDrop","dropped","handleSelect","selected","removeFile","index","newList","_","i","jsxs","jsx","file"],"mappings":"0KAwBO,SAASA,EAAa,CAC3B,SAAAC,EAAW,GACX,OAAAC,EACA,SAAAC,EACA,UAAAC,EAAY,GACZ,YAAAC,EAAc,oCAChB,EAAsB,CACpB,MAAMC,EAAWC,EAAAA,OAAgC,IAAI,EAC/C,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAAiB,CAAA,CAAE,EACvC,CAACC,EAAUC,CAAW,EAAIF,EAAAA,SAAS,EAAK,EAExCG,EAAcC,EAAAA,YACjBC,GAAqB,CACpBN,EAASM,CAAQ,EACjBZ,IAAWY,CAAQ,CACrB,EACA,CAACZ,CAAQ,CAAA,EAGLa,EAAc,GAAiB,CACnC,EAAE,eAAA,EACFJ,EAAY,EAAK,EAEjB,MAAMK,EAAU,MAAM,KAAK,EAAE,aAAa,KAAK,EAE/C,GAAI,CAAChB,EAAU,CACbY,EAAY,CAACI,EAAQ,CAAC,CAAC,CAAC,EACxB,MACF,CAEAJ,EAAY,CAAC,GAAGL,EAAO,GAAGS,CAAO,CAAC,CACpC,EAEMC,EAAgB,GAAqC,CACzD,MAAMC,EAAW,EAAE,OAAO,MAAQ,MAAM,KAAK,EAAE,OAAO,KAAK,EAAI,CAAA,EAC/D,GAAI,CAAClB,EAAU,CACbY,EAAY,CAACM,EAAS,CAAC,CAAC,CAAC,EACzB,MACF,CACAN,EAAY,CAAC,GAAGL,EAAO,GAAGW,CAAQ,CAAC,CACrC,EAEMC,EAAcC,GAAkB,CACpC,MAAMC,EAAUd,EAAM,OAAO,CAACe,EAAGC,IAAMA,IAAMH,CAAK,EAClDR,EAAYS,CAAO,CACrB,EAEA,OACEG,EAAAA,KAAC,MAAA,CAAI,UAAW,iBAAiBrB,CAAS,GAExC,SAAA,CAAAsB,EAAAA,IAAC,MAAA,CACC,UAAW,0BAA0Bf,EAAW,WAAa,EAAE,GAC/D,SAAU,EACV,KAAK,SACL,aAAW,eACX,QAAS,IAAML,EAAS,SAAS,MAAA,EACjC,UAAY,GAAM,EACZ,EAAE,MAAQ,SAAW,EAAE,MAAQ,MAAKA,EAAS,SAAS,MAAA,CAC5D,EACA,WAAa,GAAM,CACjB,EAAE,eAAA,EACFM,EAAY,EAAI,CAClB,EACA,YAAa,IAAMA,EAAY,EAAK,EACpC,OAAQI,EAER,SAAAU,EAAAA,IAAC,QAAM,SAAArB,CAAA,CAAY,CAAA,CAAA,EAIrBqB,EAAAA,IAAC,QAAA,CACC,IAAKpB,EACL,KAAK,OACL,OAAAJ,EACA,SAAAD,EACA,MAAO,CAAE,QAAS,MAAA,EAClB,SAAUiB,CAAA,CAAA,EAIXV,EAAM,OAAS,GACdkB,EAAAA,IAAC,MAAG,UAAU,qBACX,SAAAlB,EAAM,IAAI,CAACmB,EAAMH,IAChBC,EAAAA,KAAC,KAAA,CAAW,UAAU,qBACpB,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,yBAA0B,SAAAC,EAAK,KAAK,EACpDD,EAAAA,IAAC,SAAA,CACC,UAAU,uBACV,aAAW,cACX,QAAS,IAAMN,EAAWI,CAAC,EAC5B,SAAA,GAAA,CAAA,CAED,CAAA,EAROA,CAST,CACD,CAAA,CACH,CAAA,EAEJ,CAEJ"}
|
|
1
|
+
{"version":3,"file":"FileUploader.cjs","sources":["../../../src/components/fileuploader/FileUploader.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useRef, useState, useCallback, DragEvent, ChangeEvent } from 'react';\nimport { cn } from '../../utils';\nimport './FileUploader.css';\n\n/* ============================================================\n * Helper\n * ============================================================ */\n\n/**\n * Formats a byte count into a human-readable string (e.g., 1.5 MB).\n */\nfunction formatBytes(bytes: number, decimals = 2) {\n if (!+bytes) return '0 Bytes';\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;\n}\n\n/* ============================================================\n * Types\n * ============================================================ */\n\nexport interface FileUploaderProps {\n /** Controlled state for the selected files */\n value?: File[];\n /** Uncontrolled initial state for the selected files */\n defaultValue?: File[];\n /** Callback fired when the list of selected files changes */\n onChange?: (files: File[]) => void;\n /** Whether to allow multiple files to be selected. Defaults to false. */\n multiple?: boolean;\n /** A comma-separated list of allowed file extensions or MIME types (e.g., '.jpg, .png, application/pdf') */\n accept?: string;\n /** Maximum allowed file size in bytes */\n maxSize?: number;\n /** Custom class name applied to the root container */\n className?: string;\n /** Custom text or element displayed inside the dropzone */\n placeholder?: React.ReactNode;\n /** Disables the dropzone and prevents file selection */\n disabled?: boolean;\n}\n\n/* ============================================================\n * Component\n * ============================================================ */\n\n/**\n * FileUploader Component\n * * A drag-and-drop zone for file uploads with built-in preview and file management.\n * * Follows WAI-ARIA guidelines by delegating keyboard interactions to a hidden native file input.\n */\nexport function FileUploader({\n value,\n defaultValue,\n onChange,\n multiple = false,\n accept,\n maxSize,\n className,\n placeholder = 'Drag & drop files here, or click to browse',\n disabled = false,\n}: FileUploaderProps) {\n const inputRef = useRef<HTMLInputElement | null>(null);\n \n const isControlled = value !== undefined;\n const [internalFiles, setInternalFiles] = useState<File[]>(defaultValue || []);\n const files = isControlled ? value : internalFiles;\n \n const [isDragOver, setIsDragOver] = useState(false);\n\n /* ----------------------------------------------------\n File Handlers\n ---------------------------------------------------- */\n const updateFiles = useCallback((newFiles: File[]) => {\n let validFiles = newFiles;\n\n // Filter by max size if provided\n if (maxSize) {\n validFiles = newFiles.filter(f => f.size <= maxSize);\n }\n\n const nextFiles = multiple ? [...files, ...validFiles] : [validFiles[0]].filter(Boolean);\n \n if (!isControlled) setInternalFiles(nextFiles);\n onChange?.(nextFiles);\n }, [files, multiple, maxSize, isControlled, onChange]);\n\n const removeFile = (fileToRemove: File) => {\n if (disabled) return;\n const nextFiles = files.filter(f => f !== fileToRemove);\n if (!isControlled) setInternalFiles(nextFiles);\n onChange?.(nextFiles);\n };\n\n /* ----------------------------------------------------\n Event Listeners\n ---------------------------------------------------- */\n const onDragOver = (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n if (!disabled) setIsDragOver(true);\n };\n\n const onDragLeave = (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n };\n\n const onDrop = (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n \n if (disabled) return;\n if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n updateFiles(Array.from(e.dataTransfer.files));\n }\n };\n\n const onFileSelect = (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n updateFiles(Array.from(e.target.files));\n }\n // Clear the native input value so the exact same file can be selected again if removed\n if (inputRef.current) inputRef.current.value = '';\n };\n\n /* ----------------------------------------------------\n Render\n ---------------------------------------------------- */\n return (\n <div className={cn(\"nui-file-uploader\", className)}>\n \n {/* DROP ZONE */}\n <div\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-label=\"Upload files\"\n aria-disabled={disabled}\n className={cn(\n \"nui-file-dropzone\",\n isDragOver && \"dragover\",\n disabled && \"disabled\"\n )}\n onClick={() => !disabled && inputRef.current?.click()}\n onKeyDown={(e) => {\n if (!disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n inputRef.current?.click();\n }\n }}\n onDragOver={onDragOver}\n onDragLeave={onDragLeave}\n onDrop={onDrop}\n >\n <svg className=\"nui-file-icon\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path>\n <polyline points=\"17 8 12 3 7 8\"></polyline>\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"></line>\n </svg>\n <span className=\"nui-file-placeholder\">{placeholder}</span>\n </div>\n\n {/* HIDDEN NATIVE INPUT */}\n <input\n ref={inputRef}\n type=\"file\"\n data-testid=\"nui-file-input\"\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n onChange={onFileSelect}\n className=\"nui-file-hidden-input\"\n tabIndex={-1}\n aria-hidden=\"true\"\n />\n\n {/* FILE LIST PREVIEW */}\n {files.length > 0 && (\n <ul className=\"nui-file-list\" aria-label=\"Selected files\">\n {files.map((file) => {\n // Create a stable key based on file properties\n const fileKey = `${file.name}-${file.size}-${file.lastModified}`;\n \n return (\n <li key={fileKey} className=\"nui-file-item\">\n <div className=\"nui-file-info\">\n <svg className=\"nui-file-item-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"></path>\n <polyline points=\"13 2 13 9 20 9\"></polyline>\n </svg>\n <div className=\"nui-file-text\">\n <span className=\"nui-file-name\">{file.name}</span>\n <span className=\"nui-file-size\">{formatBytes(file.size)}</span>\n </div>\n </div>\n \n <button\n type=\"button\"\n className=\"nui-file-remove\"\n aria-label={`Remove ${file.name}`}\n onClick={() => removeFile(file)}\n disabled={disabled}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}"],"names":["formatBytes","bytes","decimals","k","dm","sizes","i","FileUploader","value","defaultValue","onChange","multiple","accept","maxSize","className","placeholder","disabled","inputRef","useRef","isControlled","internalFiles","setInternalFiles","useState","files","isDragOver","setIsDragOver","updateFiles","useCallback","newFiles","validFiles","f","nextFiles","removeFile","fileToRemove","onDragOver","onDragLeave","onDrop","onFileSelect","cn","jsxs","jsx","file","fileKey"],"mappings":"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"}
|