@boxcustodia/library 2.0.0-alpha.11 → 2.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +1 -1
- package/package.json +4 -3
- package/src/__doc__/Changelog.mdx +6 -0
- package/src/__doc__/Components.mdx +73 -0
- package/src/__doc__/Examples.tsx +69 -0
- package/src/__doc__/Icons.mdx +41 -0
- package/src/__doc__/Intro.mdx +138 -0
- package/src/__doc__/MCP.mdx +71 -0
- package/src/__doc__/Migration.mdx +475 -0
- package/src/__doc__/Theme.mdx +132 -0
- package/src/__doc__/Types.mdx +252 -0
- package/src/components/alert/alert.stories.tsx +142 -0
- package/src/components/alert/alert.tsx +109 -0
- package/src/components/alert/index.ts +7 -0
- package/src/components/alert-dialog/alert-dialog.stories.tsx +173 -0
- package/src/components/alert-dialog/alert-dialog.test.tsx +49 -0
- package/src/components/alert-dialog/alert-dialog.tsx +265 -0
- package/src/components/alert-dialog/index.ts +1 -0
- package/src/components/auto-complete/auto-complete-primitives.tsx +155 -0
- package/src/components/auto-complete/auto-complete.stories.tsx +241 -0
- package/src/components/auto-complete/auto-complete.tsx +82 -0
- package/src/components/auto-complete/index.ts +2 -0
- package/src/components/avatar/avatar.stories.tsx +84 -0
- package/src/components/avatar/avatar.test.tsx +61 -0
- package/src/components/avatar/avatar.tsx +104 -0
- package/src/components/avatar/index.ts +1 -0
- package/src/components/background-image/background-image.stories.tsx +21 -0
- package/src/components/background-image/background-image.test.tsx +29 -0
- package/src/components/background-image/background-image.tsx +23 -0
- package/src/components/background-image/index.ts +1 -0
- package/src/components/button/button.stories.tsx +396 -0
- package/src/components/button/button.test.tsx +58 -0
- package/src/components/button/button.tsx +31 -0
- package/src/components/button/button.variants.ts +44 -0
- package/src/components/button/components/base-button.tsx +86 -0
- package/src/components/button/components/loader-overlay.tsx +21 -0
- package/src/components/button/components/loading-icon.tsx +47 -0
- package/src/components/button/index.ts +3 -0
- package/src/components/calendar/calendar.model.ts +86 -0
- package/src/components/calendar/calendar.stories.tsx +155 -0
- package/src/components/calendar/calendar.test.tsx +12 -0
- package/src/components/calendar/calendar.tsx +185 -0
- package/src/components/calendar/components/calendar-navigation.tsx +141 -0
- package/src/components/calendar/components/day.tsx +61 -0
- package/src/components/calendar/components/decade-view.tsx +45 -0
- package/src/components/calendar/components/index.ts +6 -0
- package/src/components/calendar/components/month-view.tsx +58 -0
- package/src/components/calendar/components/week-days.tsx +27 -0
- package/src/components/calendar/components/year-view.tsx +29 -0
- package/src/components/calendar/hooks/index.ts +4 -0
- package/src/components/calendar/hooks/use-calendar-navigation.ts +79 -0
- package/src/components/calendar/hooks/use-calendar.ts +90 -0
- package/src/components/calendar/hooks/use-multiple-calendar.ts +34 -0
- package/src/components/calendar/hooks/use-range-calendar.ts +91 -0
- package/src/components/calendar/hooks/use-single-calendar.ts +18 -0
- package/src/components/calendar/index.ts +1 -0
- package/src/components/calendar/utils/typeguards.ts +7 -0
- package/src/components/card/card.stories.tsx +116 -0
- package/src/components/card/card.tsx +74 -0
- package/src/components/card/index.ts +1 -0
- package/src/components/center/center.stories.tsx +81 -0
- package/src/components/center/center.tsx +24 -0
- package/src/components/center/index.ts +1 -0
- package/src/components/checkbox/checkbox.stories.tsx +307 -0
- package/src/components/checkbox/checkbox.tsx +273 -0
- package/src/components/checkbox/index.ts +1 -0
- package/src/components/checkbox-group/checkbox-group.stories.tsx +104 -0
- package/src/components/checkbox-group/checkbox-group.tsx +16 -0
- package/src/components/checkbox-group/index.ts +1 -0
- package/src/components/combobox/combobox.stories.tsx +339 -0
- package/src/components/combobox/combobox.tsx +892 -0
- package/src/components/combobox/index.ts +1 -0
- package/src/components/date-picker/date-input.stories.tsx +158 -0
- package/src/components/date-picker/date-input.tsx +163 -0
- package/src/components/date-picker/date-picker.model.ts +90 -0
- package/src/components/date-picker/date-picker.stories.tsx +200 -0
- package/src/components/date-picker/date-picker.test.tsx +23 -0
- package/src/components/date-picker/date-picker.tsx +298 -0
- package/src/components/date-picker/date-picker.utils.ts +260 -0
- package/src/components/date-picker/index.ts +3 -0
- package/src/components/date-picker/use-date-input-popover.ts +48 -0
- package/src/components/date-picker/use-date-input.ts +125 -0
- package/src/components/dialog/dialog.stories.tsx +171 -0
- package/src/components/dialog/dialog.test.tsx +68 -0
- package/src/components/dialog/dialog.tsx +277 -0
- package/src/components/dialog/index.ts +1 -0
- package/src/components/divider/divider.stories.tsx +70 -0
- package/src/components/divider/divider.test.tsx +22 -0
- package/src/components/divider/divider.tsx +23 -0
- package/src/components/divider/index.ts +1 -0
- package/src/components/dropzone/dropzone.stories.tsx +210 -0
- package/src/components/dropzone/dropzone.tsx +154 -0
- package/src/components/dropzone/file-types.ts +64 -0
- package/src/components/dropzone/index.ts +3 -0
- package/src/components/dropzone/upload-primitives.tsx +310 -0
- package/src/components/dropzone/use-dropzone.ts +122 -0
- package/src/components/empty-state/empty-state.stories.tsx +56 -0
- package/src/components/empty-state/empty-state.tsx +39 -0
- package/src/components/empty-state/index.ts +1 -0
- package/src/components/field/field.stories.tsx +223 -0
- package/src/components/field/field.tsx +229 -0
- package/src/components/field/index.ts +1 -0
- package/src/components/form/form.stories.tsx +594 -0
- package/src/components/form/form.tsx +30 -0
- package/src/components/form/index.ts +1 -0
- package/src/components/heading/heading.stories.tsx +74 -0
- package/src/components/heading/heading.tsx +28 -0
- package/src/components/heading/heading.variants.ts +27 -0
- package/src/components/heading/index.ts +1 -0
- package/src/components/index.ts +46 -0
- package/src/components/input/index.ts +1 -0
- package/src/components/input/input.stories.tsx +104 -0
- package/src/components/input/input.tsx +75 -0
- package/src/components/kbd/index.ts +1 -0
- package/src/components/kbd/kbd.stories.tsx +40 -0
- package/src/components/kbd/kbd.tsx +31 -0
- package/src/components/kbd/kbd.variants.ts +26 -0
- package/src/components/label/index.ts +1 -0
- package/src/components/label/label.stories.tsx +68 -0
- package/src/components/label/label.test.tsx +61 -0
- package/src/components/label/label.tsx +62 -0
- package/src/components/loader/index.ts +1 -0
- package/src/components/loader/loader.stories.tsx +60 -0
- package/src/components/loader/loader.test.tsx +26 -0
- package/src/components/loader/loader.tsx +60 -0
- package/src/components/menu/index.ts +2 -0
- package/src/components/menu/menu-primitives.tsx +248 -0
- package/src/components/menu/menu.stories.tsx +203 -0
- package/src/components/menu/menu.tsx +100 -0
- package/src/components/menu/util/render-menu-item.tsx +54 -0
- package/src/components/multi-select/hooks/use-multi-select.ts +66 -0
- package/src/components/multi-select/index.ts +1 -0
- package/src/components/multi-select/multi-select.stories.tsx +294 -0
- package/src/components/multi-select/multi-select.tsx +300 -0
- package/src/components/multi-select/multi-select.variants.ts +22 -0
- package/src/components/number-input/index.ts +1 -0
- package/src/components/number-input/number-input.stories.tsx +209 -0
- package/src/components/number-input/number-input.test.tsx +87 -0
- package/src/components/number-input/number-input.tsx +230 -0
- package/src/components/pagination/components/pagination-option.tsx +27 -0
- package/src/components/pagination/index.ts +1 -0
- package/src/components/pagination/pagination.stories.tsx +80 -0
- package/src/components/pagination/pagination.test.tsx +76 -0
- package/src/components/pagination/pagination.tsx +102 -0
- package/src/components/password/index.ts +1 -0
- package/src/components/password/password.stories.tsx +104 -0
- package/src/components/password/password.tsx +71 -0
- package/src/components/popover/index.ts +1 -0
- package/src/components/popover/popover.stories.tsx +213 -0
- package/src/components/popover/popover.tsx +203 -0
- package/src/components/progress/index.ts +1 -0
- package/src/components/progress/progress.stories.tsx +124 -0
- package/src/components/progress/progress.test.tsx +25 -0
- package/src/components/progress/progress.tsx +124 -0
- package/src/components/scroll-area/index.ts +1 -0
- package/src/components/scroll-area/scroll-area.stories.tsx +166 -0
- package/src/components/scroll-area/scroll-area.tsx +64 -0
- package/src/components/select/index.ts +1 -0
- package/src/components/select/select.stories.tsx +253 -0
- package/src/components/select/select.tsx +430 -0
- package/src/components/show/index.ts +1 -0
- package/src/components/show/show.stories.tsx +197 -0
- package/src/components/show/show.test.tsx +41 -0
- package/src/components/show/show.tsx +16 -0
- package/src/components/skeleton/index.ts +1 -0
- package/src/components/skeleton/skeleton.stories.tsx +36 -0
- package/src/components/skeleton/skeleton.test.tsx +14 -0
- package/src/components/skeleton/skeleton.tsx +15 -0
- package/src/components/stack/index.ts +1 -0
- package/src/components/stack/stack.stories.tsx +194 -0
- package/src/components/stack/stack.tsx +52 -0
- package/src/components/stepper/Stepper.tsx +190 -0
- package/src/components/stepper/context/stepper-context.tsx +11 -0
- package/src/components/stepper/index.ts +1 -0
- package/src/components/stepper/stepper.stories.tsx +130 -0
- package/src/components/stepper/stepper.test.tsx +91 -0
- package/src/components/switch/index.ts +1 -0
- package/src/components/switch/switch.stories.tsx +122 -0
- package/src/components/switch/switch.test.tsx +30 -0
- package/src/components/switch/switch.tsx +86 -0
- package/src/components/table/index.ts +3 -0
- package/src/components/table/table-primitives.tsx +122 -0
- package/src/components/table/table.model.ts +20 -0
- package/src/components/table/table.stories.tsx +169 -0
- package/src/components/table/table.test.tsx +91 -0
- package/src/components/table/table.tsx +109 -0
- package/src/components/table-pagination/index.ts +2 -0
- package/src/components/table-pagination/table-pagination.model.ts +2 -0
- package/src/components/table-pagination/table-pagination.stories.tsx +23 -0
- package/src/components/table-pagination/table-pagination.test.tsx +32 -0
- package/src/components/table-pagination/table-pagination.tsx +108 -0
- package/src/components/tabs/context/tabs-context.tsx +14 -0
- package/src/components/tabs/index.ts +1 -0
- package/src/components/tabs/tabs.stories.tsx +182 -0
- package/src/components/tabs/tabs.test.tsx +61 -0
- package/src/components/tabs/tabs.tsx +175 -0
- package/src/components/tag/index.ts +2 -0
- package/src/components/tag/tag.stories.tsx +170 -0
- package/src/components/tag/tag.test.tsx +18 -0
- package/src/components/tag/tag.tsx +99 -0
- package/src/components/tag/tag.variants.ts +31 -0
- package/src/components/textarea/index.ts +1 -0
- package/src/components/textarea/textarea.stories.tsx +73 -0
- package/src/components/textarea/textarea.tsx +105 -0
- package/src/components/timeline/index.ts +1 -0
- package/src/components/timeline/timeline-status.ts +5 -0
- package/src/components/timeline/timeline.stories.tsx +84 -0
- package/src/components/timeline/timeline.tsx +147 -0
- package/src/components/toast/index.ts +1 -0
- package/src/components/toast/toast.stories.tsx +392 -0
- package/src/components/toast/toast.test.tsx +50 -0
- package/src/components/toast/toast.tsx +411 -0
- package/src/components/tooltip/index.ts +1 -0
- package/src/components/tooltip/tooltip.stories.tsx +226 -0
- package/src/components/tooltip/tooltip.test.tsx +46 -0
- package/src/components/tooltip/tooltip.tsx +171 -0
- package/src/components/tree/hooks/use-controllable-tree-state.ts +80 -0
- package/src/components/tree/index.ts +2 -0
- package/src/components/tree/tree-primitives.tsx +126 -0
- package/src/components/tree/tree.stories.tsx +468 -0
- package/src/components/tree/tree.tsx +42 -0
- package/src/hooks/index.ts +26 -0
- package/src/hooks/useArray/__doc__/useArray.stories.tsx +100 -0
- package/src/hooks/useArray/__test__/useArray.test.tsx +88 -0
- package/src/hooks/useArray/index.ts +1 -0
- package/src/hooks/useArray/useArray.ts +76 -0
- package/src/hooks/useAsync/__doc__/useAsync.stories.tsx +149 -0
- package/src/hooks/useAsync/__test__/useAsync.test.tsx +68 -0
- package/src/hooks/useAsync/index.ts +1 -0
- package/src/hooks/useAsync/useAsync.ts +58 -0
- package/src/hooks/useClickOutside/__doc__/useClickOutside.stories.tsx +40 -0
- package/src/hooks/useClickOutside/__test__/useClickOutside.test.tsx +33 -0
- package/src/hooks/useClickOutside/index.ts +1 -0
- package/src/hooks/useClickOutside/useClickOutside.ts +26 -0
- package/src/hooks/useClipboard/__doc__/useClipboard.stories.tsx +45 -0
- package/src/hooks/useClipboard/__test__/useClipboard.test.tsx +19 -0
- package/src/hooks/useClipboard/index.ts +1 -0
- package/src/hooks/useClipboard/useClipboard.tsx +28 -0
- package/src/hooks/useDebounceCallback/__doc__/useDebouncedCallback.stories.tsx +84 -0
- package/src/hooks/useDebounceCallback/index.ts +1 -0
- package/src/hooks/useDebounceCallback/useDebouncedCallback.ts +23 -0
- package/src/hooks/useDebounceValue/__doc__/useDebouncedValue.stories.tsx +75 -0
- package/src/hooks/useDebounceValue/index.ts +1 -0
- package/src/hooks/useDebounceValue/useDebouncedValue.ts +17 -0
- package/src/hooks/useDisclosure/__doc__/useDisclosure.stories.tsx +39 -0
- package/src/hooks/useDisclosure/__test__/useDisclosure.test.ts +43 -0
- package/src/hooks/useDisclosure/index.ts +1 -0
- package/src/hooks/useDisclosure/useDisclosure.ts +37 -0
- package/src/hooks/useDocumentTitle/__doc__/useDocumentTitle.stories.tsx +26 -0
- package/src/hooks/useDocumentTitle/index.ts +1 -0
- package/src/hooks/useDocumentTitle/useDocumentTitle.tsx +11 -0
- package/src/hooks/useEventListener/__doc__/useEventListener.stories.tsx +28 -0
- package/src/hooks/useEventListener/__test__/useEventListener.test.tsx +26 -0
- package/src/hooks/useEventListener/index.ts +1 -0
- package/src/hooks/useEventListener/useEventListener.ts +25 -0
- package/src/hooks/useFocusTrap/__doc__/useFocusTrap.stories.tsx +37 -0
- package/src/hooks/useFocusTrap/index.ts +1 -0
- package/src/hooks/useFocusTrap/scopeTab.ts +38 -0
- package/src/hooks/useFocusTrap/tabbable.ts +70 -0
- package/src/hooks/useFocusTrap/useFocusTrap.ts +78 -0
- package/src/hooks/useHotkey/__docs__/useHotkey.stories.tsx +116 -0
- package/src/hooks/useHotkey/__test__/useHotkey.test.tsx +105 -0
- package/src/hooks/useHotkey/__utils__/create-hotkey-listener.ts +25 -0
- package/src/hooks/useHotkey/__utils__/index.ts +3 -0
- package/src/hooks/useHotkey/__utils__/is-input-field.ts +14 -0
- package/src/hooks/useHotkey/__utils__/match-key-modifiers.ts +25 -0
- package/src/hooks/useHotkey/index.ts +1 -0
- package/src/hooks/useHotkey/useHotkey.ts +34 -0
- package/src/hooks/useHover/__doc__/useHover.stories.tsx +41 -0
- package/src/hooks/useHover/__test__/useHover.test.tsx +45 -0
- package/src/hooks/useHover/index.ts +1 -0
- package/src/hooks/useHover/useHover.tsx +40 -0
- package/src/hooks/useIsVisible/__doc__/useIsVisible.stories.tsx +60 -0
- package/src/hooks/useIsVisible/index.ts +1 -0
- package/src/hooks/useIsVisible/useIsVisible.tsx +50 -0
- package/src/hooks/useLocalStorage/__doc__/useLocalStorage.stories.tsx +86 -0
- package/src/hooks/useLocalStorage/__test__/useLocalStorage.test.ts +85 -0
- package/src/hooks/useLocalStorage/index.ts +1 -0
- package/src/hooks/useLocalStorage/useLocalStorage.ts +57 -0
- package/src/hooks/useMediaQuery/__doc__/useMediaQuery.stories.tsx +39 -0
- package/src/hooks/useMediaQuery/index.ts +1 -0
- package/src/hooks/useMediaQuery/useMediaQuery.ts +22 -0
- package/src/hooks/useMemoizedFn/index.ts +1 -0
- package/src/hooks/useMemoizedFn/useMemoizedFn.ts +32 -0
- package/src/hooks/useMutation/__doc__/useMutation.stories.tsx +111 -0
- package/src/hooks/useMutation/__test__/useMutation.test.tsx +83 -0
- package/src/hooks/useMutation/index.ts +1 -0
- package/src/hooks/useMutation/useMutation.tsx +60 -0
- package/src/hooks/useObject/__doc__/useObject.stories.tsx +119 -0
- package/src/hooks/useObject/__test__/useObject.test.tsx +87 -0
- package/src/hooks/useObject/index.ts +1 -0
- package/src/hooks/useObject/useObject.tsx +48 -0
- package/src/hooks/usePagination/__doc__/usePagination.stories.tsx +72 -0
- package/src/hooks/usePagination/__test__/usePagination.test.tsx +98 -0
- package/src/hooks/usePagination/index.ts +2 -0
- package/src/hooks/usePagination/usePagination.tsx +74 -0
- package/src/hooks/usePortal/__doc__/usePortal.stories.tsx +19 -0
- package/src/hooks/usePortal/__test__/usePortal.test.tsx +20 -0
- package/src/hooks/usePortal/index.ts +1 -0
- package/src/hooks/usePortal/usePortal.ts +40 -0
- package/src/hooks/usePreventCloseWindow/__doc__/usePreventCloseWindow.stories.tsx +32 -0
- package/src/hooks/usePreventCloseWindow/index.ts +1 -0
- package/src/hooks/usePreventCloseWindow/usePreventCloseWindow.ts +33 -0
- package/src/hooks/useRangePagination/__test__/useRangePagination.test.tsx +63 -0
- package/src/hooks/useRangePagination/index.ts +2 -0
- package/src/hooks/useRangePagination/useRangePagination.tsx +72 -0
- package/src/hooks/useSelection/__doc__/useSelection.stories.tsx +140 -0
- package/src/hooks/useSelection/__test__/useSelection.test.tsx +57 -0
- package/src/hooks/useSelection/index.ts +1 -0
- package/src/hooks/useSelection/useSelection.ts +121 -0
- package/src/hooks/useStep/__doc__/useStep.stories.tsx +98 -0
- package/src/hooks/useStep/__test__/useStep.test.ts +51 -0
- package/src/hooks/useStep/index.ts +1 -0
- package/src/hooks/useStep/useStep.ts +57 -0
- package/src/hooks/useToggle/__doc__/useToggle.stories.tsx +25 -0
- package/src/hooks/useToggle/__test__/useToggle.test.tsx +43 -0
- package/src/hooks/useToggle/index.ts +1 -0
- package/src/hooks/useToggle/useToggle.ts +16 -0
- package/src/index.ts +6 -0
- package/src/lib/cn.ts +8 -0
- package/src/lib/index.ts +1 -0
- package/src/models/Generic.model.ts +67 -0
- package/src/models/index.ts +1 -0
- package/src/providers/index.ts +2 -0
- package/src/providers/library-provider.tsx +44 -0
- package/src/providers/theme/ThemeProvider.tsx +25 -0
- package/src/providers/theme/index.ts +3 -0
- package/src/providers/theme/types.ts +11 -0
- package/src/providers/theme/useThemeProps.ts +25 -0
- package/src/stores/theme.store.ts +31 -0
- package/src/styles/components.css +4 -0
- package/src/styles/index.css +2 -0
- package/src/styles/library.css +2 -0
- package/src/styles/theme.css +232 -0
- package/src/utils/dates/parseDateRange.utility.ts +39 -0
- package/src/utils/form.tsx +91 -0
- package/src/utils/functions/createSafeContext.ts +17 -0
- package/src/utils/functions/ensureReactElement.tsx +30 -0
- package/src/utils/functions/getFormData.ts +19 -0
- package/src/utils/functions/index.ts +4 -0
- package/src/utils/functions/mergeRefs.ts +18 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/strings/extractInitials.utility.ts +10 -0
- package/src/utils/strings/index.ts +1 -0
- package/src/utils/tests/click.ts +3 -0
- package/src/utils/tests/index.ts +2 -0
- package/src/utils/tests/keyboard.ts +21 -0
- package/src/utils/tests/type.ts +6 -0
- package/dist/components.css +0 -2
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Checkbox } from "../checkbox";
|
|
4
|
+
import { CheckboxGroup } from "./checkbox-group";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* CheckboxGroup manages a set of `Checkbox` components as a single value
|
|
8
|
+
* (`string[]`). Each child `Checkbox` must receive a `value` prop to be
|
|
9
|
+
* tracked by the group.
|
|
10
|
+
*
|
|
11
|
+
* Use `defaultValue` for uncontrolled mode or `value` + `onValueChange` for
|
|
12
|
+
* controlled mode. Pass `allValues` to enable the parent checkbox pattern:
|
|
13
|
+
* a `Checkbox` with `parent` will automatically toggle between checked,
|
|
14
|
+
* unchecked, and indeterminate based on how many items are selected — no manual
|
|
15
|
+
* state needed.
|
|
16
|
+
*/
|
|
17
|
+
const meta: Meta<typeof CheckboxGroup> = {
|
|
18
|
+
title: "Components/CheckboxGroup",
|
|
19
|
+
component: CheckboxGroup,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof CheckboxGroup>;
|
|
24
|
+
|
|
25
|
+
const NOTIFICATIONS = [
|
|
26
|
+
{ label: "Comments on my posts", value: "comments" },
|
|
27
|
+
{ label: "Mentions", value: "mentions" },
|
|
28
|
+
{ label: "Direct messages", value: "messages" },
|
|
29
|
+
{ label: "System updates", value: "system" },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
export const Default: Story = {
|
|
33
|
+
render: () => (
|
|
34
|
+
<CheckboxGroup defaultValue={["comments"]}>
|
|
35
|
+
{NOTIFICATIONS.map(({ label, value }) => (
|
|
36
|
+
<Checkbox.Item key={value} value={value} label={label} />
|
|
37
|
+
))}
|
|
38
|
+
</CheckboxGroup>
|
|
39
|
+
),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `value` + `onValueChange` for controlled mode. `onValueChange` receives the
|
|
44
|
+
* updated array of selected values.
|
|
45
|
+
*/
|
|
46
|
+
export const Controlled: Story = {
|
|
47
|
+
render: () => {
|
|
48
|
+
const [value, setValue] = useState<string[]>(["comments", "mentions"]);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="space-y-4">
|
|
52
|
+
<CheckboxGroup value={value} onValueChange={setValue}>
|
|
53
|
+
{NOTIFICATIONS.map(({ label, value: v }) => (
|
|
54
|
+
<Checkbox.Item key={v} value={v} label={label} />
|
|
55
|
+
))}
|
|
56
|
+
</CheckboxGroup>
|
|
57
|
+
<p className="text-sm text-muted-foreground">
|
|
58
|
+
Active: {value.length > 0 ? value.join(", ") : "none"}
|
|
59
|
+
</p>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* `allValues` enables the parent checkbox pattern. The `Checkbox` with `parent`
|
|
67
|
+
* computes its state automatically: checked when all items are selected,
|
|
68
|
+
* unchecked when none, indeterminate on partial selection — no manual state
|
|
69
|
+
* needed.
|
|
70
|
+
*/
|
|
71
|
+
export const WithParent: Story = {
|
|
72
|
+
render: () => {
|
|
73
|
+
const allValues = NOTIFICATIONS.map((n) => n.value);
|
|
74
|
+
const [value, setValue] = useState<string[]>(["comments"]);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<CheckboxGroup
|
|
78
|
+
value={value}
|
|
79
|
+
onValueChange={setValue}
|
|
80
|
+
allValues={allValues}
|
|
81
|
+
>
|
|
82
|
+
<div className="flex items-center gap-2">
|
|
83
|
+
<Checkbox parent />
|
|
84
|
+
<span className="text-sm select-none">Enable all notifications</span>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="ml-6 flex flex-col gap-3 border-l-2 pl-4">
|
|
87
|
+
{NOTIFICATIONS.map(({ label, value: v }) => (
|
|
88
|
+
<Checkbox.Item key={v} value={v} label={label} />
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
</CheckboxGroup>
|
|
92
|
+
);
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const Disabled: Story = {
|
|
97
|
+
render: () => (
|
|
98
|
+
<CheckboxGroup defaultValue={["comments"]} disabled>
|
|
99
|
+
{NOTIFICATIONS.map(({ label, value }) => (
|
|
100
|
+
<Checkbox.Item key={value} value={value} label={label} />
|
|
101
|
+
))}
|
|
102
|
+
</CheckboxGroup>
|
|
103
|
+
),
|
|
104
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CheckboxGroup as CheckboxGroupPrimitive } from "@base-ui/react/checkbox-group";
|
|
2
|
+
import type * as React from "react";
|
|
3
|
+
import { cn } from "../../lib";
|
|
4
|
+
|
|
5
|
+
export function CheckboxGroup({
|
|
6
|
+
className,
|
|
7
|
+
...props
|
|
8
|
+
}: CheckboxGroupPrimitive.Props): React.ReactElement {
|
|
9
|
+
return (
|
|
10
|
+
<CheckboxGroupPrimitive
|
|
11
|
+
className={cn("flex flex-col items-start gap-3", className)}
|
|
12
|
+
data-slot="checkbox-group"
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./checkbox-group";
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Button } from "../button";
|
|
4
|
+
import { Field } from "../field";
|
|
5
|
+
import { Form } from "../form";
|
|
6
|
+
import {
|
|
7
|
+
Combobox,
|
|
8
|
+
ComboboxChip,
|
|
9
|
+
ComboboxChips,
|
|
10
|
+
ComboboxChipsInput,
|
|
11
|
+
ComboboxEmpty,
|
|
12
|
+
ComboboxInput,
|
|
13
|
+
ComboboxItem,
|
|
14
|
+
ComboboxList,
|
|
15
|
+
ComboboxPopup,
|
|
16
|
+
ComboboxRoot,
|
|
17
|
+
ComboboxValue,
|
|
18
|
+
} from "./combobox";
|
|
19
|
+
|
|
20
|
+
interface Item {
|
|
21
|
+
label: string;
|
|
22
|
+
value: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const items: Item[] = [
|
|
26
|
+
{ label: "Apple", value: "apple" },
|
|
27
|
+
{ label: "Banana", value: "banana" },
|
|
28
|
+
{ label: "Orange", value: "orange" },
|
|
29
|
+
{ label: "Grape", value: "grape" },
|
|
30
|
+
{ label: "Strawberry", value: "strawberry" },
|
|
31
|
+
{ label: "Mango", value: "mango" },
|
|
32
|
+
{ label: "Pineapple", value: "pineapple" },
|
|
33
|
+
{ label: "Kiwi", value: "kiwi" },
|
|
34
|
+
{ label: "Peach", value: "peach" },
|
|
35
|
+
{ label: "Pear", value: "pear" },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Composite combobox supporting single and multiple selection, built on Base UI.
|
|
40
|
+
*
|
|
41
|
+
* Renders a text input as the trigger. `multiple` mode renders a chip input that
|
|
42
|
+
* fits as many chips as the container allows — extras show as "+N más". Items shaped
|
|
43
|
+
* as `{ label, value }` or plain strings/numbers need no extra props; provide
|
|
44
|
+
* `getLabel` / `getValue` for other shapes.
|
|
45
|
+
*
|
|
46
|
+
* `showClear` (default `true`) shows a clear button when a value is selected —
|
|
47
|
+
* in single mode the chevron switches to X; in multiple mode only X appears.
|
|
48
|
+
*
|
|
49
|
+
* `renderItem` customizes the content inside each dropdown item — the checkmark
|
|
50
|
+
* indicator is always rendered by the item wrapper.
|
|
51
|
+
*
|
|
52
|
+
* Exposes `onChange` instead of Base UI's `onValueChange`. For controlled usage,
|
|
53
|
+
* pass `value` + `onChange` together. Use `ComboboxRoot` + primitives for full
|
|
54
|
+
* structural control beyond what escape-hatch props (`inputProps`, `popupProps`,
|
|
55
|
+
* etc.) offer.
|
|
56
|
+
*
|
|
57
|
+
* Reference: [Combobox – Base UI](https://base-ui.com/react/components/combobox)
|
|
58
|
+
*/
|
|
59
|
+
const meta: Meta<typeof Combobox> = {
|
|
60
|
+
title: "Components/Combobox",
|
|
61
|
+
component: Combobox,
|
|
62
|
+
parameters: { layout: "centered" },
|
|
63
|
+
decorators: [
|
|
64
|
+
(Story) => (
|
|
65
|
+
<div className="w-84">
|
|
66
|
+
<Story />
|
|
67
|
+
</div>
|
|
68
|
+
),
|
|
69
|
+
],
|
|
70
|
+
argTypes: {
|
|
71
|
+
onChange: { control: false },
|
|
72
|
+
onOpenChange: { control: false },
|
|
73
|
+
onInputValueChange: { control: false },
|
|
74
|
+
onItemHighlighted: { control: false },
|
|
75
|
+
getLabel: { control: false },
|
|
76
|
+
getValue: { control: false },
|
|
77
|
+
renderItem: { control: false },
|
|
78
|
+
inputProps: { control: false },
|
|
79
|
+
chipsProps: { control: false },
|
|
80
|
+
chipsInputProps: { control: false },
|
|
81
|
+
popupProps: { control: false },
|
|
82
|
+
itemProps: { control: false },
|
|
83
|
+
listProps: { control: false },
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default meta;
|
|
88
|
+
type Story = StoryObj<typeof Combobox>;
|
|
89
|
+
|
|
90
|
+
// ─── Composite stories ────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
export const Default: Story = {
|
|
93
|
+
render: () => <Combobox<Item> items={items} placeholder="Select a fruit…" />,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Fully controlled: selection state lives outside the component.
|
|
98
|
+
* Omitting `onChange` while providing `value` locks the selection.
|
|
99
|
+
*/
|
|
100
|
+
export const Controlled: Story = {
|
|
101
|
+
render: () => {
|
|
102
|
+
const [value, setValue] = useState<Item | null>(null);
|
|
103
|
+
return (
|
|
104
|
+
<div className="flex flex-col gap-4">
|
|
105
|
+
<Combobox<Item>
|
|
106
|
+
items={items}
|
|
107
|
+
placeholder="Select a fruit…"
|
|
108
|
+
value={value}
|
|
109
|
+
onChange={setValue}
|
|
110
|
+
/>
|
|
111
|
+
<p className="text-sm text-muted-foreground">
|
|
112
|
+
Selected: {value ? value.label : "none"}
|
|
113
|
+
</p>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const Multiple: Story = {
|
|
120
|
+
render: () => (
|
|
121
|
+
<Combobox<Item> items={items} multiple placeholder="Select fruits…" />
|
|
122
|
+
),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
interface TechItem {
|
|
126
|
+
label: string;
|
|
127
|
+
value: string;
|
|
128
|
+
emoji: string;
|
|
129
|
+
description: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const TECH_ITEMS: TechItem[] = [
|
|
133
|
+
{
|
|
134
|
+
label: "TypeScript",
|
|
135
|
+
value: "typescript",
|
|
136
|
+
emoji: "🔷",
|
|
137
|
+
description: "Typed JavaScript superset",
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
label: "Python",
|
|
141
|
+
value: "python",
|
|
142
|
+
emoji: "🐍",
|
|
143
|
+
description: "General-purpose scripting",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
label: "Rust",
|
|
147
|
+
value: "rust",
|
|
148
|
+
emoji: "⚙",
|
|
149
|
+
description: "Memory-safe systems language",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
label: "Go",
|
|
153
|
+
value: "go",
|
|
154
|
+
emoji: "🔵",
|
|
155
|
+
description: "Concurrent, cloud-native",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
label: "Swift",
|
|
159
|
+
value: "swift",
|
|
160
|
+
emoji: "🧡",
|
|
161
|
+
description: "Apple platforms",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
label: "Kotlin",
|
|
165
|
+
value: "kotlin",
|
|
166
|
+
emoji: "🟣",
|
|
167
|
+
description: "JVM + Android",
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* `renderItem` controls the content **inside** each `ComboboxItem` — the
|
|
173
|
+
* checkmark indicator is always rendered by the item wrapper. Use it to show
|
|
174
|
+
* rich content: icons, subtitles, badges, or avatars alongside the label.
|
|
175
|
+
*/
|
|
176
|
+
export const WithRenderItem: Story = {
|
|
177
|
+
render: () => (
|
|
178
|
+
<Combobox<TechItem>
|
|
179
|
+
items={TECH_ITEMS}
|
|
180
|
+
placeholder="Select a language…"
|
|
181
|
+
renderItem={(item) => (
|
|
182
|
+
<span className="flex items-center gap-2.5 py-0.5">
|
|
183
|
+
<span className="text-base leading-none">{item.emoji}</span>
|
|
184
|
+
<span className="flex flex-col gap-0.5">
|
|
185
|
+
<span className="text-sm font-medium leading-none">
|
|
186
|
+
{item.label}
|
|
187
|
+
</span>
|
|
188
|
+
<span className="text-xs leading-none text-muted-foreground">
|
|
189
|
+
{item.description}
|
|
190
|
+
</span>
|
|
191
|
+
</span>
|
|
192
|
+
</span>
|
|
193
|
+
)}
|
|
194
|
+
/>
|
|
195
|
+
),
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Plain strings require no extra props — `getLabel` and `getValue` default to
|
|
200
|
+
* `String(item)` when items are primitives.
|
|
201
|
+
*/
|
|
202
|
+
export const StringItems: Story = {
|
|
203
|
+
render: () => (
|
|
204
|
+
<Combobox
|
|
205
|
+
items={["Apple", "Banana", "Orange", "Grape", "Strawberry"]}
|
|
206
|
+
placeholder="Select a fruit…"
|
|
207
|
+
/>
|
|
208
|
+
),
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export const LibraryForm: Story = {
|
|
212
|
+
name: "Form",
|
|
213
|
+
render: () => {
|
|
214
|
+
return (
|
|
215
|
+
<Form className="space-y-1" onSubmit={console.log}>
|
|
216
|
+
<Field name="fruit" label="Fruits">
|
|
217
|
+
<Combobox items={items} required />
|
|
218
|
+
</Field>
|
|
219
|
+
<Button type="submit">Submit</Button>
|
|
220
|
+
</Form>
|
|
221
|
+
);
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// ─── Primitive stories ────────────────────────────────────────────────────────
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Fully controlled single selection using primitives. Use this pattern when
|
|
229
|
+
* composite escape-hatch props (`inputProps`, `popupProps`, etc.) are not
|
|
230
|
+
* enough — for example to insert custom elements between parts, swap the input
|
|
231
|
+
* for a select-style trigger (`ComboboxSelectTrigger`), or add a search input
|
|
232
|
+
* inside the popup (`ComboboxSearchInput`).
|
|
233
|
+
*
|
|
234
|
+
* `ComboboxRoot` requires `items` so Base UI can manage the hidden form input
|
|
235
|
+
* and built-in filtering. `itemToStringLabel` / `itemToStringValue` are
|
|
236
|
+
* inferred automatically for `{ label, value }` shapes.
|
|
237
|
+
*
|
|
238
|
+
* ```tsx
|
|
239
|
+
* <ComboboxRoot items={items} value={value} onChange={setValue}>
|
|
240
|
+
* <ComboboxInput placeholder="…" />
|
|
241
|
+
* <ComboboxPopup>
|
|
242
|
+
* <ComboboxEmpty>No items found.</ComboboxEmpty>
|
|
243
|
+
* <ComboboxList>
|
|
244
|
+
* {(item) => (
|
|
245
|
+
* <ComboboxItem key={item.value} value={item}>
|
|
246
|
+
* {item.label}
|
|
247
|
+
* </ComboboxItem>
|
|
248
|
+
* )}
|
|
249
|
+
* </ComboboxList>
|
|
250
|
+
* </ComboboxPopup>
|
|
251
|
+
* </ComboboxRoot>
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
export const PrimitiveControlled: Story = {
|
|
255
|
+
render: () => {
|
|
256
|
+
const [value, setValue] = useState<Item | null>(null);
|
|
257
|
+
return (
|
|
258
|
+
<div className="flex flex-col gap-4">
|
|
259
|
+
<ComboboxRoot items={items} value={value} onChange={setValue}>
|
|
260
|
+
<ComboboxInput
|
|
261
|
+
aria-label="Select a fruit"
|
|
262
|
+
placeholder="Select a fruit…"
|
|
263
|
+
/>
|
|
264
|
+
<ComboboxPopup>
|
|
265
|
+
<ComboboxEmpty>No items found.</ComboboxEmpty>
|
|
266
|
+
<ComboboxList>
|
|
267
|
+
{(item: Item) => (
|
|
268
|
+
<ComboboxItem key={item.value} value={item}>
|
|
269
|
+
{item.label}
|
|
270
|
+
</ComboboxItem>
|
|
271
|
+
)}
|
|
272
|
+
</ComboboxList>
|
|
273
|
+
</ComboboxPopup>
|
|
274
|
+
</ComboboxRoot>
|
|
275
|
+
<p className="text-sm text-muted-foreground">
|
|
276
|
+
Selected: {value ? value.label : "none"}
|
|
277
|
+
</p>
|
|
278
|
+
</div>
|
|
279
|
+
);
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Multiple selection using primitives. `ComboboxChipsInput` must be placed
|
|
285
|
+
* inside the `ComboboxValue` render function so it always sits after the last chip.
|
|
286
|
+
*
|
|
287
|
+
* ```tsx
|
|
288
|
+
* <ComboboxRoot items={items} multiple>
|
|
289
|
+
* <ComboboxChips>
|
|
290
|
+
* <ComboboxValue>
|
|
291
|
+
* {(value: Item[]) => (
|
|
292
|
+
* <>
|
|
293
|
+
* {value.map((item) => (
|
|
294
|
+
* <ComboboxChip key={item.value} aria-label={item.label}>
|
|
295
|
+
* {item.label}
|
|
296
|
+
* </ComboboxChip>
|
|
297
|
+
* ))}
|
|
298
|
+
* <ComboboxChipsInput placeholder={value.length === 0 ? "Select..." : undefined} />
|
|
299
|
+
* </>
|
|
300
|
+
* )}
|
|
301
|
+
* </ComboboxValue>
|
|
302
|
+
* </ComboboxChips>
|
|
303
|
+
* <ComboboxPopup>...</ComboboxPopup>
|
|
304
|
+
* </ComboboxRoot>
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
export const PrimitiveMultiple: Story = {
|
|
308
|
+
render: () => (
|
|
309
|
+
<ComboboxRoot items={items} multiple loopFocus>
|
|
310
|
+
<ComboboxChips>
|
|
311
|
+
<ComboboxValue>
|
|
312
|
+
{(value: Item[]) => (
|
|
313
|
+
<>
|
|
314
|
+
{value.map((item) => (
|
|
315
|
+
<ComboboxChip aria-label={item.label} key={item.value}>
|
|
316
|
+
{item.label}
|
|
317
|
+
</ComboboxChip>
|
|
318
|
+
))}
|
|
319
|
+
<ComboboxChipsInput
|
|
320
|
+
aria-label="Select a fruit"
|
|
321
|
+
placeholder={value.length > 0 ? undefined : "Select a fruit…"}
|
|
322
|
+
/>
|
|
323
|
+
</>
|
|
324
|
+
)}
|
|
325
|
+
</ComboboxValue>
|
|
326
|
+
</ComboboxChips>
|
|
327
|
+
<ComboboxPopup>
|
|
328
|
+
<ComboboxEmpty>No items found.</ComboboxEmpty>
|
|
329
|
+
<ComboboxList>
|
|
330
|
+
{(item: Item) => (
|
|
331
|
+
<ComboboxItem key={item.value} value={item}>
|
|
332
|
+
{item.label}
|
|
333
|
+
</ComboboxItem>
|
|
334
|
+
)}
|
|
335
|
+
</ComboboxList>
|
|
336
|
+
</ComboboxPopup>
|
|
337
|
+
</ComboboxRoot>
|
|
338
|
+
),
|
|
339
|
+
};
|