@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,84 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Settings, UserCheck } from "lucide-react";
|
|
3
|
+
import { Timeline } from ".";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Timeline> = {
|
|
6
|
+
title: "Data display/Timeline",
|
|
7
|
+
component: Timeline,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof Timeline>;
|
|
13
|
+
|
|
14
|
+
export const Default: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
items: [
|
|
17
|
+
{
|
|
18
|
+
content: "First",
|
|
19
|
+
color: "green",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
content: "Second",
|
|
23
|
+
icon: <UserCheck />,
|
|
24
|
+
status: "done",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
content: "Third",
|
|
28
|
+
icon: <Settings />,
|
|
29
|
+
status: "pending",
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const OnlyRight: Story = {
|
|
36
|
+
args: {
|
|
37
|
+
items: [
|
|
38
|
+
{
|
|
39
|
+
content: (
|
|
40
|
+
<div>
|
|
41
|
+
<time className="text-gray-400 text-sm">12/12/2022</time>
|
|
42
|
+
<p>Argentina Campeón Mundial</p>
|
|
43
|
+
<p>El dibu héroe de un país</p>
|
|
44
|
+
<p>Messi mejor jugador del mundo</p>
|
|
45
|
+
<p>Mejor país del mundo</p>
|
|
46
|
+
</div>
|
|
47
|
+
),
|
|
48
|
+
status: "done",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
content: (
|
|
52
|
+
<div>
|
|
53
|
+
<time className="text-gray-400 text-sm">10/12/2023</time>
|
|
54
|
+
<p>Milei electo</p>
|
|
55
|
+
</div>
|
|
56
|
+
),
|
|
57
|
+
status: "done",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
content: (
|
|
61
|
+
<div>
|
|
62
|
+
<time className="text-gray-400 text-sm">14/10/2024</time>
|
|
63
|
+
<p>Año de recuperación del país</p>
|
|
64
|
+
</div>
|
|
65
|
+
),
|
|
66
|
+
status: "done",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
content: (
|
|
70
|
+
<div>
|
|
71
|
+
<time className="text-gray-400 text-sm">1/1/2025</time>
|
|
72
|
+
<p>Nuevo año</p>
|
|
73
|
+
</div>
|
|
74
|
+
),
|
|
75
|
+
status: "pending",
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
render: (args) => (
|
|
80
|
+
<div className="w-[400px]">
|
|
81
|
+
<Timeline {...args} />
|
|
82
|
+
</div>
|
|
83
|
+
),
|
|
84
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { HTMLProps, ReactNode } from "react";
|
|
2
|
+
import { cn } from "../../lib";
|
|
3
|
+
import { TimelineStatus } from "./timeline-status";
|
|
4
|
+
|
|
5
|
+
interface ItemTimeline {
|
|
6
|
+
content?: ReactNode;
|
|
7
|
+
icon?: ReactNode;
|
|
8
|
+
status?: "done" | "pending" | "error";
|
|
9
|
+
color?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface TimelineProps {
|
|
13
|
+
items: ItemTimeline[];
|
|
14
|
+
itemsProps?: HTMLProps<HTMLDivElement>;
|
|
15
|
+
containerProps?: HTMLProps<HTMLUListElement>;
|
|
16
|
+
classNameContainer?: string;
|
|
17
|
+
classNameItem?: string;
|
|
18
|
+
classNameItemDot?: string;
|
|
19
|
+
classNameItemContainerDot?: string;
|
|
20
|
+
classNameItemContent?: string;
|
|
21
|
+
}
|
|
22
|
+
export const Timeline = ({
|
|
23
|
+
items,
|
|
24
|
+
classNameContainer,
|
|
25
|
+
containerProps,
|
|
26
|
+
...itemsProps
|
|
27
|
+
}: TimelineProps) => {
|
|
28
|
+
return (
|
|
29
|
+
<TimelineRoot className={classNameContainer} {...containerProps}>
|
|
30
|
+
{items.map((item: ItemTimeline, i) => (
|
|
31
|
+
<TimelineListItem
|
|
32
|
+
key={i}
|
|
33
|
+
icon={item.icon}
|
|
34
|
+
color={item.color}
|
|
35
|
+
status={item.status}
|
|
36
|
+
{...itemsProps}
|
|
37
|
+
>
|
|
38
|
+
{item.content}
|
|
39
|
+
</TimelineListItem>
|
|
40
|
+
))}
|
|
41
|
+
</TimelineRoot>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const TimelineRoot = (props: HTMLProps<HTMLUListElement>) => {
|
|
46
|
+
return (
|
|
47
|
+
<ul
|
|
48
|
+
data-slot="timeline"
|
|
49
|
+
{...props}
|
|
50
|
+
className={cn(
|
|
51
|
+
"relative flex justify-center flex-col border-input",
|
|
52
|
+
props.className,
|
|
53
|
+
)}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
interface TimelineListItemProps extends HTMLProps<HTMLLIElement> {
|
|
59
|
+
icon?: ReactNode;
|
|
60
|
+
status?: "done" | "pending" | "error";
|
|
61
|
+
color?: string;
|
|
62
|
+
itemsProps?: HTMLProps<HTMLDivElement>;
|
|
63
|
+
classNameContainer?: string;
|
|
64
|
+
classNameItemDot?: string;
|
|
65
|
+
classNameItemContainerDot?: string;
|
|
66
|
+
classNameItemContent?: string;
|
|
67
|
+
}
|
|
68
|
+
export const TimelineListItem = ({
|
|
69
|
+
icon,
|
|
70
|
+
status,
|
|
71
|
+
color,
|
|
72
|
+
classNameItemDot,
|
|
73
|
+
classNameItemContainerDot,
|
|
74
|
+
classNameItemContent,
|
|
75
|
+
itemsProps,
|
|
76
|
+
children,
|
|
77
|
+
...props
|
|
78
|
+
}: TimelineListItemProps) => {
|
|
79
|
+
return (
|
|
80
|
+
<li
|
|
81
|
+
data-slot="timeline-item"
|
|
82
|
+
className={cn(
|
|
83
|
+
"rounded-lg w-full px-2 gap-1 grid hover:bg-muted transition-colors ease-in grid-cols-[minmax(auto,20px)_1fr]",
|
|
84
|
+
props.className,
|
|
85
|
+
)}
|
|
86
|
+
{...props}
|
|
87
|
+
>
|
|
88
|
+
<TimelineItemDot
|
|
89
|
+
icon={icon}
|
|
90
|
+
status={status}
|
|
91
|
+
color={color}
|
|
92
|
+
classNameDot={classNameItemDot}
|
|
93
|
+
classNameContainerDot={classNameItemContainerDot}
|
|
94
|
+
/>
|
|
95
|
+
<TimelineItemContent className={classNameItemContent} {...itemsProps}>
|
|
96
|
+
{children}
|
|
97
|
+
</TimelineItemContent>
|
|
98
|
+
</li>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
interface TimelineItemDotProps {
|
|
103
|
+
icon?: ReactNode;
|
|
104
|
+
status?: "done" | "pending" | "error";
|
|
105
|
+
color?: string;
|
|
106
|
+
classNameDot?: string;
|
|
107
|
+
classNameContainerDot?: string;
|
|
108
|
+
}
|
|
109
|
+
export const TimelineItemDot = ({
|
|
110
|
+
icon,
|
|
111
|
+
status = "pending",
|
|
112
|
+
color,
|
|
113
|
+
classNameDot,
|
|
114
|
+
classNameContainerDot,
|
|
115
|
+
}: TimelineItemDotProps) => {
|
|
116
|
+
return (
|
|
117
|
+
<div
|
|
118
|
+
data-slot="timeline-item-dot"
|
|
119
|
+
className={cn(
|
|
120
|
+
"relative pb-6 last:after:hidden after:absolute after:top-0 after:bottom-0 after:left-1/2 after:w-px after:-translate-x-1/2 after:bg-gray-200",
|
|
121
|
+
classNameContainerDot,
|
|
122
|
+
)}
|
|
123
|
+
>
|
|
124
|
+
<div
|
|
125
|
+
data-slot="timeline-item-dot-icon"
|
|
126
|
+
className={cn(
|
|
127
|
+
"relative z-10 flex text-white items-center justify-center rounded-full left-1/2 -translate-x-1/2",
|
|
128
|
+
icon ? "aspect-square p-1.5 min-h-7 min-w-7 top-2" : "size-2 top-4",
|
|
129
|
+
classNameDot,
|
|
130
|
+
)}
|
|
131
|
+
style={{ backgroundColor: color || TimelineStatus?.[status] }}
|
|
132
|
+
>
|
|
133
|
+
{icon}
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const TimelineItemContent = (props: HTMLProps<HTMLDivElement>) => {
|
|
140
|
+
return (
|
|
141
|
+
<div
|
|
142
|
+
data-slot="timeline-item-content"
|
|
143
|
+
{...props}
|
|
144
|
+
className={cn("grow px-2 pb-4 pt-2", props.className)}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./toast";
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { LibraryProvider } from "../../providers";
|
|
3
|
+
import { Button } from "../button";
|
|
4
|
+
import {
|
|
5
|
+
createToastManager,
|
|
6
|
+
ToastProvider,
|
|
7
|
+
toast,
|
|
8
|
+
useToastManager,
|
|
9
|
+
} from "./toast";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Imperative toast notification system built on `@base-ui/react/toast`.
|
|
13
|
+
* Toasts stack in the bottom-right corner with enter/exit animations,
|
|
14
|
+
* swipe-to-dismiss, and expand-on-hover.
|
|
15
|
+
*
|
|
16
|
+
* ## Usage
|
|
17
|
+
*
|
|
18
|
+
* Call `toast` or `toast.*` from anywhere — components, services, stores, event handlers.
|
|
19
|
+
* A `string` renders as the prominent title; an object accepts:
|
|
20
|
+
*
|
|
21
|
+
* | Prop | Type | Description |
|
|
22
|
+
* |------|------|-------------|
|
|
23
|
+
* | `variant` | `"default" \| "success" \| "error" \| "warning" \| "info"` | Color and icon |
|
|
24
|
+
* | `title` | `string` | Primary text (`font-medium`) |
|
|
25
|
+
* | `description` | `string \| ReactNode` | Secondary text (muted) |
|
|
26
|
+
* | `content` | `ReactNode` | Replaces the entire toast layout |
|
|
27
|
+
* | `actions` | `ButtonProps[]` | Action buttons below the message |
|
|
28
|
+
* | `id` | `string` | Stable ID — prevents duplicates, triggers bump animation |
|
|
29
|
+
* | `timeout` | `number \| null` | Duration in ms. `null` = persistent |
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* toast("Notification"); // default — no variant or color
|
|
33
|
+
* toast.success("Changes saved");
|
|
34
|
+
* toast.error("Something went wrong");
|
|
35
|
+
* toast.warning({ title: "Warning", description: "File exceeds maximum size" });
|
|
36
|
+
* toast.info("Update available");
|
|
37
|
+
*
|
|
38
|
+
* toast.promise(saveData(), {
|
|
39
|
+
* loading: { description: "Saving..." },
|
|
40
|
+
* success: () => ({ variant: "success", description: "Saved" }),
|
|
41
|
+
* error: (e) => ({ variant: "error", description: e.message }),
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* ## Setup
|
|
46
|
+
*
|
|
47
|
+
* **Requires `<LibraryProvider>` at the app root.** It includes `ToastProvider` automatically — no
|
|
48
|
+
* extra wrapping needed:
|
|
49
|
+
*
|
|
50
|
+
* ```tsx
|
|
51
|
+
* // app.tsx
|
|
52
|
+
* import { LibraryProvider } from "@boxcustodia/library";
|
|
53
|
+
*
|
|
54
|
+
* export function App() {
|
|
55
|
+
* return (
|
|
56
|
+
* <LibraryProvider>
|
|
57
|
+
* <Router />
|
|
58
|
+
* </LibraryProvider>
|
|
59
|
+
* );
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
const meta: Meta<typeof ToastProvider> = {
|
|
64
|
+
title: "Components/Toast",
|
|
65
|
+
component: ToastProvider,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default meta;
|
|
69
|
+
type Story = StoryObj<typeof meta>;
|
|
70
|
+
|
|
71
|
+
// ─── Basic ────────────────────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
export const Default: Story = {
|
|
74
|
+
render: () => (
|
|
75
|
+
<Button
|
|
76
|
+
variant="outline"
|
|
77
|
+
onClick={() => toast("Notification without variant.")}
|
|
78
|
+
>
|
|
79
|
+
Default
|
|
80
|
+
</Button>
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const TitleOnly: Story = {
|
|
85
|
+
render: () => (
|
|
86
|
+
<Button variant="outline" onClick={() => toast({ title: "Title only" })}>
|
|
87
|
+
Title only
|
|
88
|
+
</Button>
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const DescriptionOnly: Story = {
|
|
93
|
+
render: () => (
|
|
94
|
+
<Button
|
|
95
|
+
variant="outline"
|
|
96
|
+
onClick={() => toast({ description: "Description only, no title." })}
|
|
97
|
+
>
|
|
98
|
+
Description only
|
|
99
|
+
</Button>
|
|
100
|
+
),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// ─── Variants ─────────────────────────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
export const Success: Story = {
|
|
106
|
+
render: () => (
|
|
107
|
+
<Button
|
|
108
|
+
variant="outline"
|
|
109
|
+
onClick={() => toast.success("Changes saved successfully.")}
|
|
110
|
+
>
|
|
111
|
+
Success
|
|
112
|
+
</Button>
|
|
113
|
+
),
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const Error: Story = {
|
|
117
|
+
render: () => (
|
|
118
|
+
<Button
|
|
119
|
+
variant="outline"
|
|
120
|
+
onClick={() => toast.error("Could not complete the operation.")}
|
|
121
|
+
>
|
|
122
|
+
Error
|
|
123
|
+
</Button>
|
|
124
|
+
),
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const Warning: Story = {
|
|
128
|
+
render: () => (
|
|
129
|
+
<Button
|
|
130
|
+
variant="outline"
|
|
131
|
+
onClick={() =>
|
|
132
|
+
toast.warning({
|
|
133
|
+
title: "Warning",
|
|
134
|
+
description: "File exceeds the maximum allowed size.",
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
>
|
|
138
|
+
Warning
|
|
139
|
+
</Button>
|
|
140
|
+
),
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const Info: Story = {
|
|
144
|
+
render: () => (
|
|
145
|
+
<Button
|
|
146
|
+
variant="outline"
|
|
147
|
+
onClick={() =>
|
|
148
|
+
toast.info({
|
|
149
|
+
title: "Update available",
|
|
150
|
+
description: "v2.4.0 is ready to install.",
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
>
|
|
154
|
+
Info
|
|
155
|
+
</Button>
|
|
156
|
+
),
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// ─── Composition ──────────────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* `content` replaces the entire toast layout — useful for custom layouts,
|
|
163
|
+
* image previews, or any arbitrary JSX inside the toast container.
|
|
164
|
+
*/
|
|
165
|
+
export const CustomContent: Story = {
|
|
166
|
+
render: () => (
|
|
167
|
+
<Button
|
|
168
|
+
variant="outline"
|
|
169
|
+
onClick={() =>
|
|
170
|
+
toast.info({
|
|
171
|
+
content: (
|
|
172
|
+
<div className="flex flex-col gap-1 pr-6">
|
|
173
|
+
<span className="text-[0.975rem] font-medium leading-5">
|
|
174
|
+
Custom layout
|
|
175
|
+
</span>
|
|
176
|
+
<span className="text-[0.925rem] leading-5 text-muted-foreground">
|
|
177
|
+
Any JSX can go inside the toast.
|
|
178
|
+
</span>
|
|
179
|
+
<code className="mt-1 rounded bg-muted px-1.5 py-0.5 text-xs">
|
|
180
|
+
content: ReactNode
|
|
181
|
+
</code>
|
|
182
|
+
</div>
|
|
183
|
+
),
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
>
|
|
187
|
+
Custom content
|
|
188
|
+
</Button>
|
|
189
|
+
),
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* `actions` renders buttons below the message. Accepts the same API as `<Button>`.
|
|
194
|
+
* Useful for inline confirmations without opening a dialog.
|
|
195
|
+
*
|
|
196
|
+
* To dismiss the toast from an action, capture the ID returned by `add()` and call `remove(id)`:
|
|
197
|
+
*
|
|
198
|
+
* ```tsx
|
|
199
|
+
* const { add, close } = useToastManager();
|
|
200
|
+
*
|
|
201
|
+
* let id: string;
|
|
202
|
+
* id = add({
|
|
203
|
+
* variant: "warning",
|
|
204
|
+
* title: "Unsaved changes",
|
|
205
|
+
* actions: [
|
|
206
|
+
* { children: "Discard", onClick: () => close(id) },
|
|
207
|
+
* { children: "Save", onClick: () => { save(); close(id); } },
|
|
208
|
+
* ],
|
|
209
|
+
* });
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
export const WithActions: Story = {
|
|
213
|
+
render: () => {
|
|
214
|
+
const { add, close } = useToastManager();
|
|
215
|
+
return (
|
|
216
|
+
<Button
|
|
217
|
+
variant="outline"
|
|
218
|
+
onClick={() => {
|
|
219
|
+
let id: string;
|
|
220
|
+
id = add({
|
|
221
|
+
variant: "warning",
|
|
222
|
+
title: "Unsaved changes",
|
|
223
|
+
description: "They will be lost if you leave this page.",
|
|
224
|
+
actions: [
|
|
225
|
+
{
|
|
226
|
+
children: "Discard",
|
|
227
|
+
variant: "outline",
|
|
228
|
+
size: "sm",
|
|
229
|
+
onClick: () => close(id),
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
children: "Save",
|
|
233
|
+
variant: "default",
|
|
234
|
+
size: "sm",
|
|
235
|
+
onClick: () => close(id),
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
});
|
|
239
|
+
}}
|
|
240
|
+
>
|
|
241
|
+
With actions
|
|
242
|
+
</Button>
|
|
243
|
+
);
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* `toast.promise()` handles all three promise states automatically:
|
|
249
|
+
* shows a loading toast while pending, then transitions to success or error on settle.
|
|
250
|
+
*/
|
|
251
|
+
const Deferred = globalThis.Promise;
|
|
252
|
+
const NativeError = globalThis.Error;
|
|
253
|
+
|
|
254
|
+
const mockPurchaseSuccess = () =>
|
|
255
|
+
new Deferred<{ message: string }>((resolve) =>
|
|
256
|
+
setTimeout(
|
|
257
|
+
() =>
|
|
258
|
+
resolve({
|
|
259
|
+
message:
|
|
260
|
+
"Order #4821 confirmed. A summary has been sent to your email.",
|
|
261
|
+
}),
|
|
262
|
+
2000,
|
|
263
|
+
),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const mockPurchaseError = () =>
|
|
267
|
+
new Deferred<{ message: string }>((_, reject) =>
|
|
268
|
+
setTimeout(
|
|
269
|
+
() => reject(new NativeError("Insufficient funds on the card.")),
|
|
270
|
+
2000,
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
export const PromiseToast: Story = {
|
|
275
|
+
render: () => (
|
|
276
|
+
<div className="flex gap-2">
|
|
277
|
+
<Button
|
|
278
|
+
variant="outline"
|
|
279
|
+
onClick={() =>
|
|
280
|
+
toast.promise(mockPurchaseSuccess(), {
|
|
281
|
+
loading: { description: "Processing payment..." },
|
|
282
|
+
success: (data: any) => ({
|
|
283
|
+
variant: "success",
|
|
284
|
+
title: "Purchase complete",
|
|
285
|
+
description: data.message,
|
|
286
|
+
}),
|
|
287
|
+
error: (err: Error) => ({
|
|
288
|
+
variant: "error",
|
|
289
|
+
title: "Payment failed",
|
|
290
|
+
description: err.message,
|
|
291
|
+
}),
|
|
292
|
+
})
|
|
293
|
+
}
|
|
294
|
+
>
|
|
295
|
+
Confirm purchase
|
|
296
|
+
</Button>
|
|
297
|
+
<Button
|
|
298
|
+
variant="outline"
|
|
299
|
+
onClick={() =>
|
|
300
|
+
toast.promise(mockPurchaseError(), {
|
|
301
|
+
loading: { description: "Processing payment..." },
|
|
302
|
+
success: (data: any) => ({
|
|
303
|
+
variant: "success",
|
|
304
|
+
title: "Purchase complete",
|
|
305
|
+
description: data.message,
|
|
306
|
+
}),
|
|
307
|
+
error: (err: Error) => ({
|
|
308
|
+
variant: "error",
|
|
309
|
+
title: "Payment failed",
|
|
310
|
+
description: err.message,
|
|
311
|
+
}),
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
>
|
|
315
|
+
Pay (insufficient funds)
|
|
316
|
+
</Button>
|
|
317
|
+
</div>
|
|
318
|
+
),
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// ─── Advanced ─────────────────────────────────────────────────────────────────
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* `useToastManager()` exposes the full manager inside a component.
|
|
325
|
+
* Useful when you need access to `update()`, `toasts[]`, or `promise()` with local state.
|
|
326
|
+
* For most cases, the `toast.*` singleton is enough.
|
|
327
|
+
*/
|
|
328
|
+
export const WithHook: Story = {
|
|
329
|
+
render: () => {
|
|
330
|
+
const { add, toasts } = useToastManager();
|
|
331
|
+
return (
|
|
332
|
+
<div className="flex items-center gap-3">
|
|
333
|
+
<Button
|
|
334
|
+
variant="outline"
|
|
335
|
+
onClick={() =>
|
|
336
|
+
add({
|
|
337
|
+
variant: "info",
|
|
338
|
+
title: "From the hook",
|
|
339
|
+
description:
|
|
340
|
+
"useToastManager() gives full access to the manager.",
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
>
|
|
344
|
+
Add toast
|
|
345
|
+
</Button>
|
|
346
|
+
<span className="text-sm text-muted-foreground">
|
|
347
|
+
{toasts.length} active
|
|
348
|
+
</span>
|
|
349
|
+
</div>
|
|
350
|
+
);
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* `createToastManager()` creates an isolated manager instance — useful in tests
|
|
356
|
+
* or microfrontends that need a separate toast stack from the global singleton.
|
|
357
|
+
*
|
|
358
|
+
* ```tsx
|
|
359
|
+
* const myManager = createToastManager();
|
|
360
|
+
*
|
|
361
|
+
* <ToastProvider toastManager={myManager}>
|
|
362
|
+
* <App />
|
|
363
|
+
* </ToastProvider>
|
|
364
|
+
*
|
|
365
|
+
* myManager.add({ variant: "success", title: "Isolated instance" });
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
const isolatedManager = createToastManager();
|
|
369
|
+
|
|
370
|
+
export const IsolatedManager: Story = {
|
|
371
|
+
decorators: [
|
|
372
|
+
(Story) => (
|
|
373
|
+
<LibraryProvider toastManager={isolatedManager}>
|
|
374
|
+
<Story />
|
|
375
|
+
</LibraryProvider>
|
|
376
|
+
),
|
|
377
|
+
],
|
|
378
|
+
render: () => (
|
|
379
|
+
<Button
|
|
380
|
+
variant="outline"
|
|
381
|
+
onClick={() =>
|
|
382
|
+
isolatedManager.add({
|
|
383
|
+
variant: "info",
|
|
384
|
+
title: "Isolated manager",
|
|
385
|
+
description: "Independent instance from the global singleton.",
|
|
386
|
+
})
|
|
387
|
+
}
|
|
388
|
+
>
|
|
389
|
+
Trigger isolated
|
|
390
|
+
</Button>
|
|
391
|
+
),
|
|
392
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { ToastProvider, useToastManager } from "../toast";
|
|
5
|
+
|
|
6
|
+
function ToastTrigger({
|
|
7
|
+
variant,
|
|
8
|
+
title,
|
|
9
|
+
description,
|
|
10
|
+
}: {
|
|
11
|
+
variant?: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}) {
|
|
15
|
+
const manager = useToastManager();
|
|
16
|
+
return (
|
|
17
|
+
<button
|
|
18
|
+
onClick={() =>
|
|
19
|
+
manager.add({ variant: variant as any, title, description })
|
|
20
|
+
}
|
|
21
|
+
>
|
|
22
|
+
Show toast
|
|
23
|
+
</button>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function renderWithProvider(ui: React.ReactNode) {
|
|
28
|
+
return render(<ToastProvider>{ui}</ToastProvider>);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe("Toast component", () => {
|
|
32
|
+
it("should render description", async () => {
|
|
33
|
+
renderWithProvider(<ToastTrigger description="test" />);
|
|
34
|
+
await userEvent.click(screen.getByText("Show toast"));
|
|
35
|
+
expect(await screen.findByText("test")).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should render title", async () => {
|
|
39
|
+
renderWithProvider(<ToastTrigger title="title" description="test" />);
|
|
40
|
+
await userEvent.click(screen.getByText("Show toast"));
|
|
41
|
+
expect(await screen.findByText("title")).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should render with success variant ring", async () => {
|
|
45
|
+
renderWithProvider(<ToastTrigger variant="success" description="test" />);
|
|
46
|
+
await userEvent.click(screen.getByText("Show toast"));
|
|
47
|
+
const toast = await screen.findByRole("status");
|
|
48
|
+
expect(toast.className).toContain("ring-success");
|
|
49
|
+
});
|
|
50
|
+
});
|