@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,76 @@
|
|
|
1
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { Pagination } from "../../components";
|
|
4
|
+
import { DOTS } from "../../hooks";
|
|
5
|
+
import { click } from "../../utils";
|
|
6
|
+
|
|
7
|
+
describe("Pagination component", () => {
|
|
8
|
+
it("should render correctly", () => {
|
|
9
|
+
render(<Pagination pageSize={10} totalItems={100} />);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should navigate to page", async () => {
|
|
13
|
+
render(<Pagination pageSize={10} totalItems={100} />);
|
|
14
|
+
|
|
15
|
+
const page = screen.getByText(/Ir a la página 3/i).parentElement!;
|
|
16
|
+
click(page);
|
|
17
|
+
|
|
18
|
+
waitFor(() => {
|
|
19
|
+
expect(page).toHaveAttribute("active", "true");
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should navigate to first page", async () => {
|
|
24
|
+
render(<Pagination pageSize={10} totalItems={100} />);
|
|
25
|
+
|
|
26
|
+
const page = screen.getByText(/Ir a primera página/i);
|
|
27
|
+
click(page);
|
|
28
|
+
|
|
29
|
+
waitFor(() => {
|
|
30
|
+
expect(page).toHaveAttribute("active", "true");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should navigate to previous page", async () => {
|
|
35
|
+
render(<Pagination pageSize={10} totalItems={100} />);
|
|
36
|
+
|
|
37
|
+
const page = screen.getByText(/Ir a página anterior/i);
|
|
38
|
+
click(page);
|
|
39
|
+
|
|
40
|
+
waitFor(() => {
|
|
41
|
+
expect(page).toHaveAttribute("active", "true");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should navigate to next page", async () => {
|
|
46
|
+
render(<Pagination pageSize={10} totalItems={100} />);
|
|
47
|
+
|
|
48
|
+
const page = screen.getByText(/Ir a próxima página/i);
|
|
49
|
+
click(page);
|
|
50
|
+
|
|
51
|
+
waitFor(() => {
|
|
52
|
+
expect(page).toHaveAttribute("active", "true");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should navigate to last page", async () => {
|
|
57
|
+
render(<Pagination pageSize={10} totalItems={100} />);
|
|
58
|
+
|
|
59
|
+
const page = screen.getByText(/Ir a última página/i);
|
|
60
|
+
click(page);
|
|
61
|
+
|
|
62
|
+
waitFor(() => {
|
|
63
|
+
expect(page).toHaveAttribute("active", "true");
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should render dots", async () => {
|
|
68
|
+
render(<Pagination pageSize={10} totalItems={100} />);
|
|
69
|
+
const dots = screen.getByText(DOTS);
|
|
70
|
+
|
|
71
|
+
waitFor(() => {
|
|
72
|
+
expect(dots).toBeInTheDocument();
|
|
73
|
+
expect(dots).toHaveAttribute("dots", "true");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChevronLeft,
|
|
3
|
+
ChevronRight,
|
|
4
|
+
ChevronsLeft,
|
|
5
|
+
ChevronsRight,
|
|
6
|
+
} from "lucide-react";
|
|
7
|
+
import { HTMLProps } from "react";
|
|
8
|
+
import { DOTS, useRangePagination, useRangePaginationProps } from "../../hooks";
|
|
9
|
+
import { cn } from "../../lib";
|
|
10
|
+
import {
|
|
11
|
+
PaginationOption as Option,
|
|
12
|
+
PaginationOptionProps,
|
|
13
|
+
} from "./components/pagination-option";
|
|
14
|
+
|
|
15
|
+
interface Props extends useRangePaginationProps {
|
|
16
|
+
optionProps?: PaginationOptionProps;
|
|
17
|
+
className?: string;
|
|
18
|
+
containerProps?: HTMLProps<HTMLDivElement>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const Pagination = ({
|
|
22
|
+
optionProps,
|
|
23
|
+
className,
|
|
24
|
+
containerProps,
|
|
25
|
+
...rangeProps
|
|
26
|
+
}: Props) => {
|
|
27
|
+
const {
|
|
28
|
+
paginationRange,
|
|
29
|
+
currentPage,
|
|
30
|
+
goTo,
|
|
31
|
+
maxPage,
|
|
32
|
+
next,
|
|
33
|
+
prev,
|
|
34
|
+
isLastPage,
|
|
35
|
+
isFirstPage,
|
|
36
|
+
} = useRangePagination(rangeProps);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
{...containerProps}
|
|
41
|
+
className={cn(
|
|
42
|
+
"flex items-end select-none h-10",
|
|
43
|
+
containerProps?.className,
|
|
44
|
+
className,
|
|
45
|
+
)}
|
|
46
|
+
data-slot="pagination"
|
|
47
|
+
>
|
|
48
|
+
<Option
|
|
49
|
+
{...optionProps}
|
|
50
|
+
disabled={isFirstPage}
|
|
51
|
+
onClick={() => goTo(1)}
|
|
52
|
+
className={cn("rounded-l-md", optionProps?.className)}
|
|
53
|
+
>
|
|
54
|
+
<ChevronsLeft data-slot="pagination-option-icon" />
|
|
55
|
+
<span className="sr-only">Ir a primera página</span>
|
|
56
|
+
</Option>
|
|
57
|
+
|
|
58
|
+
<Option {...optionProps} onClick={prev} disabled={isFirstPage}>
|
|
59
|
+
<ChevronLeft data-slot="pagination-option-icon" />
|
|
60
|
+
<span className="sr-only">Ir a página anterior</span>
|
|
61
|
+
</Option>
|
|
62
|
+
|
|
63
|
+
{paginationRange.map((pageNumber) => (
|
|
64
|
+
<>
|
|
65
|
+
{pageNumber === DOTS ? (
|
|
66
|
+
<Option
|
|
67
|
+
key={pageNumber}
|
|
68
|
+
className={cn("pointer-events-none", optionProps?.className)}
|
|
69
|
+
>
|
|
70
|
+
{DOTS}
|
|
71
|
+
</Option>
|
|
72
|
+
) : (
|
|
73
|
+
<Option
|
|
74
|
+
{...optionProps}
|
|
75
|
+
isActive={pageNumber === currentPage}
|
|
76
|
+
onClick={() => goTo(pageNumber as number)}
|
|
77
|
+
key={pageNumber}
|
|
78
|
+
>
|
|
79
|
+
{pageNumber}
|
|
80
|
+
<span className="sr-only">Ir a la página {pageNumber}</span>
|
|
81
|
+
</Option>
|
|
82
|
+
)}
|
|
83
|
+
</>
|
|
84
|
+
))}
|
|
85
|
+
|
|
86
|
+
<Option {...optionProps} onClick={next} disabled={isLastPage}>
|
|
87
|
+
<ChevronRight data-slot="pagination-option-icon" />
|
|
88
|
+
<span className="sr-only">Ir a próxima página</span>
|
|
89
|
+
</Option>
|
|
90
|
+
|
|
91
|
+
<Option
|
|
92
|
+
{...optionProps}
|
|
93
|
+
disabled={isLastPage}
|
|
94
|
+
onClick={() => goTo(maxPage)}
|
|
95
|
+
className={cn("rounded-r-md", optionProps?.className)}
|
|
96
|
+
>
|
|
97
|
+
<ChevronsRight data-slot="pagination-option-icon" />
|
|
98
|
+
<span className="sr-only">Ir a última página</span>
|
|
99
|
+
</Option>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./password";
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Lock, Unlock } from "lucide-react";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { createToastManager, ToastProvider } from "../toast";
|
|
5
|
+
import { Password } from "./password";
|
|
6
|
+
|
|
7
|
+
const toastManager = createToastManager();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Password input with a visibility toggle button. `aria-invalid` drives error
|
|
11
|
+
* styling — no Field wrapper needed.
|
|
12
|
+
*
|
|
13
|
+
* The toggle button is always rendered; `toggleable={false}` disables it
|
|
14
|
+
* without removing it from the DOM, keeping the layout consistent.
|
|
15
|
+
*
|
|
16
|
+
* `onShow` fires when the password becomes visible; `onHide` fires when
|
|
17
|
+
* it's hidden again — both after the internal state has changed.
|
|
18
|
+
*/
|
|
19
|
+
const meta: Meta<typeof Password> = {
|
|
20
|
+
title: "Components/Password",
|
|
21
|
+
component: Password,
|
|
22
|
+
parameters: { layout: "centered" },
|
|
23
|
+
args: {
|
|
24
|
+
placeholder: "Enter your password",
|
|
25
|
+
},
|
|
26
|
+
argTypes: {
|
|
27
|
+
showIcon: { control: false },
|
|
28
|
+
hideIcon: { control: false },
|
|
29
|
+
onShow: { control: false },
|
|
30
|
+
onHide: { control: false },
|
|
31
|
+
onChange: { control: false },
|
|
32
|
+
},
|
|
33
|
+
decorators: [
|
|
34
|
+
(Story) => (
|
|
35
|
+
<ToastProvider toastManager={toastManager}>
|
|
36
|
+
<Story />
|
|
37
|
+
</ToastProvider>
|
|
38
|
+
),
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default meta;
|
|
43
|
+
type Story = StoryObj<typeof Password>;
|
|
44
|
+
|
|
45
|
+
export const Default: Story = {};
|
|
46
|
+
|
|
47
|
+
export const Disabled: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
disabled: true,
|
|
50
|
+
defaultValue: "my-secret-password",
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `aria-invalid="true"` applies error border and ring — no Field wrapper needed.
|
|
56
|
+
*/
|
|
57
|
+
export const Invalid: Story = {
|
|
58
|
+
args: { "aria-invalid": "true" },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* `toggleable={false}` disables the button without removing it from the DOM.
|
|
63
|
+
* Use this when you want to prevent the user from revealing the password
|
|
64
|
+
* while keeping the visual layout consistent.
|
|
65
|
+
*/
|
|
66
|
+
export const NonToggleable: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
toggleable: false,
|
|
69
|
+
defaultValue: "my-secret-password",
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* `onChange` receives the string value as first argument, so no
|
|
75
|
+
* `event.target.value` needed.
|
|
76
|
+
*/
|
|
77
|
+
export const Controlled: Story = {
|
|
78
|
+
render: () => {
|
|
79
|
+
const [value, setValue] = useState("");
|
|
80
|
+
return (
|
|
81
|
+
<Password
|
|
82
|
+
placeholder="Enter your password"
|
|
83
|
+
value={value}
|
|
84
|
+
onChange={(val) => setValue(val)}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const CustomIcons: Story = {
|
|
91
|
+
args: {
|
|
92
|
+
showIcon: <Lock className="h-4 w-4" />,
|
|
93
|
+
hideIcon: <Unlock className="h-4 w-4" />,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const WithCallbacks: Story = {
|
|
98
|
+
args: {
|
|
99
|
+
onShow: () =>
|
|
100
|
+
toastManager.add({ variant: "success", description: "Password visible" }),
|
|
101
|
+
onHide: () =>
|
|
102
|
+
toastManager.add({ variant: "success", description: "Password hidden" }),
|
|
103
|
+
},
|
|
104
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Eye, EyeOff } from "lucide-react";
|
|
2
|
+
import { type ChangeEvent, type ReactNode } from "react";
|
|
3
|
+
import { useToggle } from "../../hooks";
|
|
4
|
+
import { cn } from "../../lib";
|
|
5
|
+
import { InputPrimitive, type InputProps } from "../input/input";
|
|
6
|
+
|
|
7
|
+
export type PasswordProps = Omit<InputProps, "unstyled" | "nativeInput"> & {
|
|
8
|
+
showIcon?: ReactNode;
|
|
9
|
+
hideIcon?: ReactNode;
|
|
10
|
+
onShow?: () => void;
|
|
11
|
+
onHide?: () => void;
|
|
12
|
+
toggleable?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function Password({
|
|
16
|
+
className,
|
|
17
|
+
showIcon = <Eye className="h-4 w-4" />,
|
|
18
|
+
hideIcon = <EyeOff className="h-4 w-4" />,
|
|
19
|
+
onShow,
|
|
20
|
+
onHide,
|
|
21
|
+
toggleable = true,
|
|
22
|
+
onChange,
|
|
23
|
+
...rest
|
|
24
|
+
}: PasswordProps) {
|
|
25
|
+
const [showPassword, toggleShowPassword] = useToggle(false);
|
|
26
|
+
|
|
27
|
+
const handleToggle = () => {
|
|
28
|
+
toggleShowPassword();
|
|
29
|
+
showPassword ? onHide?.() : onShow?.();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const handleChange = onChange
|
|
33
|
+
? (event: ChangeEvent<HTMLInputElement>) =>
|
|
34
|
+
onChange(event.target.value, event)
|
|
35
|
+
: undefined;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
className={cn(
|
|
40
|
+
"relative inline-flex w-full rounded-md border border-input bg-background",
|
|
41
|
+
"text-sm transition-shadow",
|
|
42
|
+
"has-focus-visible:border-ring",
|
|
43
|
+
"has-aria-invalid:border-error has-focus-visible:has-aria-invalid:ring-error/20",
|
|
44
|
+
"has-disabled:cursor-not-allowed has-disabled:opacity-50",
|
|
45
|
+
className,
|
|
46
|
+
)}
|
|
47
|
+
data-slot="password"
|
|
48
|
+
>
|
|
49
|
+
<InputPrimitive
|
|
50
|
+
{...rest}
|
|
51
|
+
onChange={handleChange}
|
|
52
|
+
type={showPassword ? "text" : "password"}
|
|
53
|
+
className="w-full min-w-0 rounded-[inherit] bg-transparent py-2 pl-3 pr-10 text-sm outline-none placeholder:text-muted-foreground [&::-ms-clear]:hidden [&::-ms-reveal]:hidden"
|
|
54
|
+
/>
|
|
55
|
+
<button
|
|
56
|
+
data-slot="password-toggle"
|
|
57
|
+
type="button"
|
|
58
|
+
onClick={handleToggle}
|
|
59
|
+
disabled={!toggleable}
|
|
60
|
+
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
61
|
+
>
|
|
62
|
+
{showPassword ? hideIcon : showIcon}
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── Backward-compat alias ─────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
export { Password as PasswordRoot };
|
|
71
|
+
export type { PasswordProps as PasswordRootProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./popover";
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { XIcon } from "lucide-react";
|
|
3
|
+
import { useState } from "storybook/preview-api";
|
|
4
|
+
import { Button, Input, Label } from "../../components";
|
|
5
|
+
import {
|
|
6
|
+
Popover,
|
|
7
|
+
PopoverClose,
|
|
8
|
+
PopoverDescription,
|
|
9
|
+
PopoverPopup,
|
|
10
|
+
PopoverRoot,
|
|
11
|
+
PopoverTitle,
|
|
12
|
+
PopoverTrigger,
|
|
13
|
+
} from ".";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Floating panel anchored to a trigger element. Built on
|
|
17
|
+
* [Base UI Popover](https://base-ui.com/react/components/popover.md).
|
|
18
|
+
*
|
|
19
|
+
* Provides two APIs: `Popover` (composite, single-component) and primitives
|
|
20
|
+
* (`PopoverRoot` + `PopoverTrigger` + `PopoverPopup`) for full layout control.
|
|
21
|
+
*
|
|
22
|
+
* `trigger` accepts a `ReactElement` passed as the `render` prop of `PopoverTrigger` — no
|
|
23
|
+
* wrapper is added. Use `popupClassName` to style the popup without going through `popupProps`.
|
|
24
|
+
* `title` and `description` render `PopoverTitle` / `PopoverDescription` with automatic ARIA
|
|
25
|
+
* wiring. Supports controlled state via `open` / `onOpenChange` and imperative control via
|
|
26
|
+
* `PopoverCreateHandle`.
|
|
27
|
+
*/
|
|
28
|
+
const meta: Meta<typeof Popover> = {
|
|
29
|
+
title: "Components/Popover",
|
|
30
|
+
component: Popover,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default meta;
|
|
34
|
+
type Story = StoryObj<typeof Popover>;
|
|
35
|
+
|
|
36
|
+
export const Default: Story = {
|
|
37
|
+
render: (args) => (
|
|
38
|
+
<Popover {...args} trigger={<Button variant="outline">Open</Button>}>
|
|
39
|
+
Lorem Ipsum es simplemente el texto de relleno de las imprentas y archivos
|
|
40
|
+
de texto. Lorem Ipsum ha sido el texto de relleno estándar de las
|
|
41
|
+
industrias desde el año 1500.
|
|
42
|
+
</Popover>
|
|
43
|
+
),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `tooltipStyle` renders the popup compact — smaller padding, `rounded-md`, and `w-fit`.
|
|
48
|
+
* Intended for brief contextual hints that don't need a full panel.
|
|
49
|
+
*/
|
|
50
|
+
export const TooltipStyle: Story = {
|
|
51
|
+
render: () => (
|
|
52
|
+
<Popover trigger={<Button variant="outline">Hint</Button>} tooltipStyle>
|
|
53
|
+
Contextual tooltip content
|
|
54
|
+
</Popover>
|
|
55
|
+
),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* `side` and `align` control popup placement relative to the trigger.
|
|
60
|
+
* `sideOffset` and `alignOffset` fine-tune the gap and shift in pixels.
|
|
61
|
+
*/
|
|
62
|
+
export const Positioning: Story = {
|
|
63
|
+
render: () => (
|
|
64
|
+
<div className="flex gap-4">
|
|
65
|
+
{(["top", "bottom", "left", "right"] as const).map((side) => (
|
|
66
|
+
<Popover
|
|
67
|
+
key={side}
|
|
68
|
+
side={side}
|
|
69
|
+
trigger={<Button variant="outline">{side}</Button>}
|
|
70
|
+
>
|
|
71
|
+
Anchored to {side}
|
|
72
|
+
</Popover>
|
|
73
|
+
))}
|
|
74
|
+
</div>
|
|
75
|
+
),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const WithTitleAndDescription: Story = {
|
|
79
|
+
render: () => (
|
|
80
|
+
<Popover
|
|
81
|
+
trigger={<Button variant="outline">Update Profile</Button>}
|
|
82
|
+
title="Update Profile"
|
|
83
|
+
description="Edit your profile details below."
|
|
84
|
+
>
|
|
85
|
+
<div className="space-y-3">
|
|
86
|
+
<div className="grid grid-cols-3 items-center gap-4">
|
|
87
|
+
<Label htmlFor="firstName">First Name</Label>
|
|
88
|
+
<Input
|
|
89
|
+
id="firstName"
|
|
90
|
+
defaultValue="John"
|
|
91
|
+
className="col-span-2 h-8"
|
|
92
|
+
/>
|
|
93
|
+
</div>
|
|
94
|
+
<div className="grid grid-cols-3 items-center gap-4">
|
|
95
|
+
<Label htmlFor="lastName">Last Name</Label>
|
|
96
|
+
<Input id="lastName" defaultValue="Doe" className="col-span-2 h-8" />
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</Popover>
|
|
100
|
+
),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* `open` and `onOpenChange` enable external state control. Use when another element
|
|
105
|
+
* drives the popover's visibility without the trigger being part of the popover itself.
|
|
106
|
+
*/
|
|
107
|
+
export const Controlled: Story = {
|
|
108
|
+
render: function Render(args) {
|
|
109
|
+
const [open, setOpen] = useState(false);
|
|
110
|
+
return (
|
|
111
|
+
<Popover
|
|
112
|
+
{...args}
|
|
113
|
+
open={open}
|
|
114
|
+
onOpenChange={(value: boolean) => setOpen(value)}
|
|
115
|
+
trigger={<Button variant="outline">Open</Button>}
|
|
116
|
+
>
|
|
117
|
+
This popover is controlled externally via <code>open</code> /{" "}
|
|
118
|
+
<code>onOpenChange</code>.
|
|
119
|
+
</Popover>
|
|
120
|
+
);
|
|
121
|
+
},
|
|
122
|
+
args: {
|
|
123
|
+
open: false,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* `matchTriggerWidth` makes the popup as wide as its trigger using Base UI's
|
|
129
|
+
* `--anchor-width` CSS variable on the positioner. The trigger width drives the
|
|
130
|
+
* popup width — widening or narrowing the trigger changes the popup accordingly.
|
|
131
|
+
*
|
|
132
|
+
* Useful for dropdowns or comboboxes where content should visually align with the
|
|
133
|
+
* field it belongs to. Incompatible with `tooltipStyle` (which forces `w-fit`).
|
|
134
|
+
*/
|
|
135
|
+
export const MatchTriggerWidth: Story = {
|
|
136
|
+
render: () => (
|
|
137
|
+
<div className="flex flex-col items-start gap-6">
|
|
138
|
+
<Popover
|
|
139
|
+
matchTriggerWidth
|
|
140
|
+
trigger={
|
|
141
|
+
<Button variant="outline" className="w-40">
|
|
142
|
+
Narrow
|
|
143
|
+
</Button>
|
|
144
|
+
}
|
|
145
|
+
>
|
|
146
|
+
This popup matches the trigger width.
|
|
147
|
+
</Popover>
|
|
148
|
+
<Popover
|
|
149
|
+
matchTriggerWidth
|
|
150
|
+
trigger={
|
|
151
|
+
<Button variant="outline" className="w-80">
|
|
152
|
+
Wide
|
|
153
|
+
</Button>
|
|
154
|
+
}
|
|
155
|
+
>
|
|
156
|
+
This popup also matches its trigger width.
|
|
157
|
+
</Popover>
|
|
158
|
+
</div>
|
|
159
|
+
),
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Compose primitives directly for full layout and slot control.
|
|
164
|
+
*
|
|
165
|
+
* `PopoverTrigger` and `PopoverClose` accept a `render` prop to replace the default `<button>`.
|
|
166
|
+
* `PopoverTitle` and `PopoverDescription` wire `aria-labelledby` / `aria-describedby` on the
|
|
167
|
+
* popup automatically.
|
|
168
|
+
*
|
|
169
|
+
* ```tsx
|
|
170
|
+
* <PopoverRoot>
|
|
171
|
+
* <PopoverTrigger render={<Button variant="outline" />}>Open</PopoverTrigger>
|
|
172
|
+
* <PopoverPopup className="w-80">
|
|
173
|
+
* <PopoverClose
|
|
174
|
+
* aria-label="Close"
|
|
175
|
+
* className="absolute end-2 top-2"
|
|
176
|
+
* render={<Button size="icon" variant="ghost"><XIcon /></Button>}
|
|
177
|
+
* />
|
|
178
|
+
* <PopoverTitle>Title</PopoverTitle>
|
|
179
|
+
* <PopoverDescription>Description</PopoverDescription>
|
|
180
|
+
* <PopoverClose render={<Button variant="outline" />}>Dismiss</PopoverClose>
|
|
181
|
+
* </PopoverPopup>
|
|
182
|
+
* </PopoverRoot>
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export const Primitive: Story = {
|
|
186
|
+
render: () => (
|
|
187
|
+
<PopoverRoot>
|
|
188
|
+
<PopoverTrigger render={<Button variant="outline" />}>
|
|
189
|
+
Open Popover
|
|
190
|
+
</PopoverTrigger>
|
|
191
|
+
<PopoverPopup className="w-80">
|
|
192
|
+
<PopoverClose
|
|
193
|
+
aria-label="Close"
|
|
194
|
+
className="absolute end-2 top-2"
|
|
195
|
+
render={
|
|
196
|
+
<Button size="icon" variant="ghost">
|
|
197
|
+
<XIcon />
|
|
198
|
+
</Button>
|
|
199
|
+
}
|
|
200
|
+
/>
|
|
201
|
+
<div className="mb-2">
|
|
202
|
+
<PopoverTitle className="text-base">Notifications</PopoverTitle>
|
|
203
|
+
<PopoverDescription>
|
|
204
|
+
You are all caught up. Good job!
|
|
205
|
+
</PopoverDescription>
|
|
206
|
+
</div>
|
|
207
|
+
<PopoverClose render={<Button variant="outline" />}>
|
|
208
|
+
Dismiss
|
|
209
|
+
</PopoverClose>
|
|
210
|
+
</PopoverPopup>
|
|
211
|
+
</PopoverRoot>
|
|
212
|
+
),
|
|
213
|
+
};
|