@boxcustodia/library 2.0.0-alpha.11 → 2.0.0-alpha.13
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.cjs.js +38 -38
- package/dist/index.css +1 -1
- package/dist/index.d.ts +28 -29
- package/dist/index.es.js +6804 -6792
- 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 +451 -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 +898 -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 +139 -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 +232 -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 +75 -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,139 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Divider } from "../../components";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Visual separator between sections or inline elements.
|
|
6
|
+
*
|
|
7
|
+
* Built on the Base UI `Separator` primitive. Supports `orientation` (`horizontal` | `vertical`)
|
|
8
|
+
* and a `render` prop for polymorphic composition. The DOM element receives `data-orientation`
|
|
9
|
+
* which can be used as a CSS selector for conditional styles.
|
|
10
|
+
*/
|
|
11
|
+
const meta: Meta<typeof Divider> = {
|
|
12
|
+
title: "Components/Divider",
|
|
13
|
+
component: Divider,
|
|
14
|
+
args: {
|
|
15
|
+
orientation: "horizontal",
|
|
16
|
+
},
|
|
17
|
+
parameters: {
|
|
18
|
+
layout: "centered",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof Divider>;
|
|
24
|
+
|
|
25
|
+
export const Default: Story = {
|
|
26
|
+
render: () => (
|
|
27
|
+
<div className="w-72 rounded-lg border p-4 text-sm">
|
|
28
|
+
<div className="flex items-center justify-between">
|
|
29
|
+
<span className="font-medium">Deployment #847</span>
|
|
30
|
+
<span className="text-xs text-green-500">● Live</span>
|
|
31
|
+
</div>
|
|
32
|
+
<Divider className="my-3" />
|
|
33
|
+
<div className="space-y-1.5 text-muted-foreground">
|
|
34
|
+
<div className="flex justify-between">
|
|
35
|
+
<span>Triggered by</span>
|
|
36
|
+
<span className="text-foreground">fbaigorria</span>
|
|
37
|
+
</div>
|
|
38
|
+
<div className="flex justify-between">
|
|
39
|
+
<span>Branch</span>
|
|
40
|
+
<span className="text-foreground">develop</span>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="flex justify-between">
|
|
43
|
+
<span>Duration</span>
|
|
44
|
+
<span className="text-foreground">1m 43s</span>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<Divider className="my-3" />
|
|
48
|
+
<div className="flex items-center justify-center gap-4 text-muted-foreground">
|
|
49
|
+
<span>2 warnings</span>
|
|
50
|
+
<Divider orientation="vertical" className="h-4" />
|
|
51
|
+
<span>0 errors</span>
|
|
52
|
+
<Divider orientation="vertical" className="h-4" />
|
|
53
|
+
<span>127 tests</span>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Default orientation. Renders a full-width 1px horizontal line via `data-[orientation=horizontal]`.
|
|
61
|
+
* Commonly used to separate named sections inside a panel or card.
|
|
62
|
+
*/
|
|
63
|
+
export const Horizontal: Story = {
|
|
64
|
+
render: () => (
|
|
65
|
+
<div className="w-72 rounded-lg border p-4 space-y-4">
|
|
66
|
+
<div>
|
|
67
|
+
<p className="text-sm font-medium">Profile</p>
|
|
68
|
+
<p className="text-xs text-muted-foreground">Franco Baigorria</p>
|
|
69
|
+
</div>
|
|
70
|
+
<Divider />
|
|
71
|
+
<div>
|
|
72
|
+
<p className="text-sm font-medium">Team</p>
|
|
73
|
+
<p className="text-xs text-muted-foreground">Engineering</p>
|
|
74
|
+
</div>
|
|
75
|
+
<Divider />
|
|
76
|
+
<div>
|
|
77
|
+
<p className="text-sm font-medium">Role</p>
|
|
78
|
+
<p className="text-xs text-muted-foreground">Frontend Architect</p>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* In vertical orientation the component uses `self-stretch` to fill the full height of
|
|
86
|
+
* the flex container. Wrapping in a `div` with `flex` and a defined height is the expected pattern.
|
|
87
|
+
*/
|
|
88
|
+
export const Vertical: Story = {
|
|
89
|
+
args: {
|
|
90
|
+
orientation: "vertical",
|
|
91
|
+
},
|
|
92
|
+
render: (args) => (
|
|
93
|
+
<div className="flex h-10 items-center gap-4">
|
|
94
|
+
<span className="text-sm">Section A</span>
|
|
95
|
+
<Divider {...args} />
|
|
96
|
+
<span className="text-sm">Section B</span>
|
|
97
|
+
<Divider {...args} />
|
|
98
|
+
<span className="text-sm">Section C</span>
|
|
99
|
+
</div>
|
|
100
|
+
),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The `render` prop replaces the rendered DOM element. Useful for swapping semantics
|
|
105
|
+
* to `<hr>` or any other element without losing component styles.
|
|
106
|
+
*
|
|
107
|
+
* ```tsx
|
|
108
|
+
* <Divider render={<hr />} />
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export const Render: Story = {
|
|
112
|
+
render: (args) => (
|
|
113
|
+
<div className="w-64">
|
|
114
|
+
<Divider {...args} render={<hr />} />
|
|
115
|
+
</div>
|
|
116
|
+
),
|
|
117
|
+
parameters: {
|
|
118
|
+
docs: {
|
|
119
|
+
source: {
|
|
120
|
+
code: `<Divider render={<hr />} />`,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* `className` accepts Tailwind classes to override color, thickness, or spacing.
|
|
128
|
+
* `data-[orientation=horizontal]` and `data-[orientation=vertical]` are available
|
|
129
|
+
* as CSS selectors for advanced conditional styles.
|
|
130
|
+
*/
|
|
131
|
+
export const Custom: Story = {
|
|
132
|
+
render: () => (
|
|
133
|
+
<div className="space-y-4 w-64">
|
|
134
|
+
<Divider className="bg-primary" />
|
|
135
|
+
<Divider className="bg-error" />
|
|
136
|
+
<Divider className="border-t border-dashed border-input bg-transparent" />
|
|
137
|
+
</div>
|
|
138
|
+
),
|
|
139
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { Divider } from "../../components";
|
|
4
|
+
|
|
5
|
+
describe("Divider component", () => {
|
|
6
|
+
const testId = "divider";
|
|
7
|
+
it("should render correctly", () => {
|
|
8
|
+
render(<Divider data-testid={testId} />);
|
|
9
|
+
const divider = screen.getByTestId(testId);
|
|
10
|
+
|
|
11
|
+
expect(divider).toBeInTheDocument();
|
|
12
|
+
expect(divider).toHaveAttribute("aria-orientation", "horizontal");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should accept vertical orientation", () => {
|
|
16
|
+
render(<Divider orientation="vertical" data-testid={testId} />);
|
|
17
|
+
const divider = screen.getByTestId(testId);
|
|
18
|
+
|
|
19
|
+
expect(divider).toBeInTheDocument();
|
|
20
|
+
expect(divider).toHaveAttribute("aria-orientation", "vertical");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Separator as SeparatorPrimitive } from "@base-ui/react/separator";
|
|
2
|
+
import type React from "react";
|
|
3
|
+
import { cn } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
export function Divider({
|
|
6
|
+
className,
|
|
7
|
+
orientation = "horizontal",
|
|
8
|
+
...props
|
|
9
|
+
}: SeparatorPrimitive.Props): React.ReactElement {
|
|
10
|
+
return (
|
|
11
|
+
<SeparatorPrimitive
|
|
12
|
+
className={cn(
|
|
13
|
+
"shrink-0 bg-input data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:not-[[class^='h-']]:not-[[class*='_h-']]:self-stretch",
|
|
14
|
+
className,
|
|
15
|
+
)}
|
|
16
|
+
data-slot="separator"
|
|
17
|
+
orientation={orientation}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { SeparatorPrimitive };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./divider";
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Camera, File, FileArchive, ImageIcon, Trash } from "lucide-react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Button } from "../../components/button";
|
|
5
|
+
import { Dropzone } from ".";
|
|
6
|
+
import { FileType, FileTypeGroups, FileTypeValue } from "./file-types";
|
|
7
|
+
import {
|
|
8
|
+
UploadAcceptedFiles,
|
|
9
|
+
UploadContent,
|
|
10
|
+
UploadRejectedFiles,
|
|
11
|
+
UploadRoot,
|
|
12
|
+
UploadTrigger,
|
|
13
|
+
} from "./upload-primitives";
|
|
14
|
+
import { FileError } from "./use-dropzone";
|
|
15
|
+
|
|
16
|
+
const meta: Meta<typeof Dropzone> = {
|
|
17
|
+
title: "data entry/Dropzone",
|
|
18
|
+
component: Dropzone,
|
|
19
|
+
subcomponents: {
|
|
20
|
+
UploadRoot: UploadRoot as React.ComponentType<unknown>,
|
|
21
|
+
UploadTrigger: UploadTrigger as React.ComponentType<unknown>,
|
|
22
|
+
UploadContent: UploadContent as React.ComponentType<unknown>,
|
|
23
|
+
UploadAcceptedFiles: UploadAcceptedFiles as React.ComponentType<unknown>,
|
|
24
|
+
UploadRejectedFiles: UploadRejectedFiles as React.ComponentType<unknown>,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<typeof Dropzone>;
|
|
30
|
+
|
|
31
|
+
export const Default: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
allowedExtensions: [...FileTypeGroups.IMAGES, FileType.PDF],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const WithCustomIcon: Story = {
|
|
38
|
+
args: {
|
|
39
|
+
allowedExtensions: FileTypeGroups.IMAGES,
|
|
40
|
+
icon: ImageIcon,
|
|
41
|
+
iconSize: 48,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const FileUploader: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
allowedExtensions: [FileType.PDF, FileType.ZIP],
|
|
48
|
+
icon: FileArchive,
|
|
49
|
+
iconSize: 48,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const MultipleFiles: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
multiple: true,
|
|
56
|
+
maxFiles: 3,
|
|
57
|
+
allowedExtensions: [...FileTypeGroups.IMAGES, FileType.PDF],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* El callback `onError` te permite manejar errores cuando se rechazan archivos durante la validación.
|
|
63
|
+
*
|
|
64
|
+
* ### Interfaz FileError
|
|
65
|
+
* ```typescript
|
|
66
|
+
* type FileError = {
|
|
67
|
+
* file: File; // El archivo que causó el error
|
|
68
|
+
* errorMessage: string; // Mensaje de error genérico
|
|
69
|
+
* errorCode: FileErrorCode; // Código para identificar el tipo de error
|
|
70
|
+
* };
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* ### Códigos de Error Disponibles
|
|
74
|
+
* - `'INVALID_EXTENSION'`: El archivo no tiene una extensión permitida
|
|
75
|
+
* - `'FILE_TOO_LARGE'`: El archivo excede el tamaño máximo permitido
|
|
76
|
+
* - `'MAX_FILES_EXCEEDED'`: Se ha alcanzado el límite máximo de archivos
|
|
77
|
+
*
|
|
78
|
+
* ### Ejemplo de Uso
|
|
79
|
+
* ```typescript
|
|
80
|
+
* onError: (fileErrors) => {
|
|
81
|
+
* fileErrors.forEach(({ file, errorCode }) => {
|
|
82
|
+
* switch (errorCode) {
|
|
83
|
+
* case 'INVALID_EXTENSION':
|
|
84
|
+
* toast.error(`${file.name} no es un tipo válido`);
|
|
85
|
+
* break;
|
|
86
|
+
* case 'FILE_TOO_LARGE':
|
|
87
|
+
* toast.error(`${file.name} es muy grande`);
|
|
88
|
+
* break;
|
|
89
|
+
* case 'MAX_FILES_EXCEEDED':
|
|
90
|
+
* toast.error('Demasiados archivos');
|
|
91
|
+
* break;
|
|
92
|
+
* }
|
|
93
|
+
* });
|
|
94
|
+
* };
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* ### Notas Importantes
|
|
98
|
+
* - El `onError` se ejecuta automáticamente cada vez que `validateFiles` encuentra errores
|
|
99
|
+
* - Puedes acceder al archivo original para mostrar información personalizada
|
|
100
|
+
* - Los mensajes de error son genéricos, puedes crear los tuyos propios basándote en el `errorCode`
|
|
101
|
+
*/
|
|
102
|
+
export const WithErrorHandling: Story = {
|
|
103
|
+
args: {
|
|
104
|
+
multiple: true,
|
|
105
|
+
maxFiles: 2,
|
|
106
|
+
maxFileSize: 2 * 1024 * 1024, // 2MB
|
|
107
|
+
allowedExtensions: [...FileTypeGroups.IMAGES, FileType.PDF],
|
|
108
|
+
onError: (fileErrors: FileError[]) => {
|
|
109
|
+
console.log("Errores de archivos:", fileErrors);
|
|
110
|
+
alert(
|
|
111
|
+
fileErrors
|
|
112
|
+
.map(
|
|
113
|
+
({ file, errorMessage, errorCode }) =>
|
|
114
|
+
`${file.name}: ${errorMessage} (${errorCode})`,
|
|
115
|
+
)
|
|
116
|
+
.join("\n"),
|
|
117
|
+
);
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const CustomFilePreview: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
multiple: true,
|
|
125
|
+
allowedExtensions: [...FileTypeGroups.IMAGES, FileType.PDF],
|
|
126
|
+
showRejected: true,
|
|
127
|
+
renderAcceptedFile: (file, removeItem) => (
|
|
128
|
+
<div className="flex items-center gap-2 p-2 bg-muted rounded-lg">
|
|
129
|
+
{FileTypeGroups.IMAGES.includes(file.type as FileTypeValue) ? (
|
|
130
|
+
<img
|
|
131
|
+
src={URL.createObjectURL(file)}
|
|
132
|
+
alt={file.name}
|
|
133
|
+
className="h-12 w-12 rounded object-cover"
|
|
134
|
+
/>
|
|
135
|
+
) : (
|
|
136
|
+
<File className="h-12 w-12" />
|
|
137
|
+
)}
|
|
138
|
+
<div className="flex flex-col">
|
|
139
|
+
<span className="font-medium">{file.name}</span>
|
|
140
|
+
<span className="text-sm text-muted-foreground">
|
|
141
|
+
{Math.round(file.size / 1024)}KB
|
|
142
|
+
</span>
|
|
143
|
+
</div>
|
|
144
|
+
<Button
|
|
145
|
+
variant="ghost"
|
|
146
|
+
size="icon"
|
|
147
|
+
className="ml-auto"
|
|
148
|
+
onClick={removeItem}
|
|
149
|
+
>
|
|
150
|
+
<Trash className="h-4 w-4" />
|
|
151
|
+
</Button>
|
|
152
|
+
</div>
|
|
153
|
+
),
|
|
154
|
+
renderRejectedFile: (file, removeItem) => (
|
|
155
|
+
<div className="flex items-center gap-2 p-2 bg-destructive/10 rounded-lg">
|
|
156
|
+
<File className="h-12 w-12" />
|
|
157
|
+
<div className="flex flex-col">
|
|
158
|
+
<span className="font-medium">{file.name}</span>
|
|
159
|
+
<span className="text-sm text-muted-foreground">
|
|
160
|
+
Archivo rechazado
|
|
161
|
+
</span>
|
|
162
|
+
</div>
|
|
163
|
+
<Button
|
|
164
|
+
variant="ghost"
|
|
165
|
+
size="icon"
|
|
166
|
+
className="ml-auto"
|
|
167
|
+
onClick={removeItem}
|
|
168
|
+
>
|
|
169
|
+
<Trash className="h-4 w-4" />
|
|
170
|
+
</Button>
|
|
171
|
+
</div>
|
|
172
|
+
),
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* El componente Dropzone está compuesto por los componentes primitivos UploadRoot, UploadTrigger, UploadContent, UploadAcceptedFiles y UploadRejectedFiles.
|
|
178
|
+
*
|
|
179
|
+
* Este ejemplo muestra como armar el componente Dropzone usando los componentes primitivos.
|
|
180
|
+
*
|
|
181
|
+
* ##### Estructura
|
|
182
|
+
* ```tsx
|
|
183
|
+
* <UploadRoot>
|
|
184
|
+
* <UploadTrigger>
|
|
185
|
+
* ...
|
|
186
|
+
* </UploadTrigger>
|
|
187
|
+
* <UploadContent>
|
|
188
|
+
* <UploadAcceptedFiles />
|
|
189
|
+
* <UploadRejectedFiles />
|
|
190
|
+
* </UploadContent>
|
|
191
|
+
* </UploadRoot>
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export const Primitives: Story = {
|
|
195
|
+
render: () => {
|
|
196
|
+
return (
|
|
197
|
+
<UploadRoot>
|
|
198
|
+
<UploadTrigger asChild>
|
|
199
|
+
<Button>
|
|
200
|
+
<Camera /> Upload
|
|
201
|
+
</Button>
|
|
202
|
+
</UploadTrigger>
|
|
203
|
+
<UploadContent>
|
|
204
|
+
<UploadAcceptedFiles />
|
|
205
|
+
<UploadRejectedFiles />
|
|
206
|
+
</UploadContent>
|
|
207
|
+
</UploadRoot>
|
|
208
|
+
);
|
|
209
|
+
},
|
|
210
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { LucideIcon, UploadCloud } from "lucide-react";
|
|
2
|
+
import { ComponentPropsWithoutRef, useMemo } from "react";
|
|
3
|
+
import { cn } from "../../lib";
|
|
4
|
+
import { FileTypeValue } from "./file-types";
|
|
5
|
+
import {
|
|
6
|
+
UploadAcceptedFiles,
|
|
7
|
+
UploadContent,
|
|
8
|
+
UploadRejectedFiles,
|
|
9
|
+
UploadRoot,
|
|
10
|
+
UploadTrigger,
|
|
11
|
+
} from "./upload-primitives";
|
|
12
|
+
import { FileError } from "./use-dropzone";
|
|
13
|
+
|
|
14
|
+
export type DropzoneProps = {
|
|
15
|
+
/**
|
|
16
|
+
* Función que se ejecuta cuando se agregan archivos
|
|
17
|
+
*/
|
|
18
|
+
onFileAdd?: (files: File[]) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Función que se ejecuta cuando se elimina un archivo
|
|
21
|
+
*/
|
|
22
|
+
onFileRemove?: (index: number, type: "accepted" | "rejected") => void;
|
|
23
|
+
/**
|
|
24
|
+
* Evento que captura cambios en lista de archivos
|
|
25
|
+
* @default () => {}
|
|
26
|
+
*/
|
|
27
|
+
onChangeFiles?: (files: File[]) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Lista de archivos
|
|
30
|
+
* @default []
|
|
31
|
+
*/
|
|
32
|
+
files?: File[];
|
|
33
|
+
/**
|
|
34
|
+
* Número máximo de archivos permitidos
|
|
35
|
+
* @default 1
|
|
36
|
+
*/
|
|
37
|
+
maxFiles?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Lista de extensiones permitidas (e.j. ["image/jpeg", "image/png"])
|
|
40
|
+
* @default []
|
|
41
|
+
*/
|
|
42
|
+
allowedExtensions?: FileTypeValue[];
|
|
43
|
+
/**
|
|
44
|
+
* Tamaño máximo de archivo en bytes
|
|
45
|
+
* @default 5MB
|
|
46
|
+
*/
|
|
47
|
+
maxFileSize?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Permite seleccionar múltiples archivos
|
|
50
|
+
*/
|
|
51
|
+
multiple?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Función para renderizar cada archivo aceptado
|
|
54
|
+
*/
|
|
55
|
+
renderAcceptedFile?: (file: File, removeItem: () => void) => React.ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* Función para renderizar cada archivo rechazado
|
|
58
|
+
*/
|
|
59
|
+
renderRejectedFile?: (file: File, removeItem: () => void) => React.ReactNode;
|
|
60
|
+
/**
|
|
61
|
+
* Mostrar archivos rechazados
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
showRejected?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Clase CSS para el contenedor
|
|
67
|
+
*/
|
|
68
|
+
className?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Icono personalizado para el dropzone
|
|
71
|
+
* @default UploadCloud
|
|
72
|
+
*/
|
|
73
|
+
icon?: LucideIcon;
|
|
74
|
+
/**
|
|
75
|
+
* Tamaño del icono
|
|
76
|
+
* @default 40
|
|
77
|
+
*/
|
|
78
|
+
iconSize?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Función que se ejecuta cuando se rechazan archivos
|
|
81
|
+
*/
|
|
82
|
+
onError?: (fileErrors: FileError[]) => void;
|
|
83
|
+
} & Omit<ComponentPropsWithoutRef<"div">, "onDrop" | "onError">;
|
|
84
|
+
|
|
85
|
+
export const Dropzone = ({
|
|
86
|
+
onFileAdd,
|
|
87
|
+
onFileRemove,
|
|
88
|
+
onChangeFiles = () => {},
|
|
89
|
+
files,
|
|
90
|
+
maxFiles = 1,
|
|
91
|
+
allowedExtensions = [],
|
|
92
|
+
maxFileSize = 5 * 1024 * 1024,
|
|
93
|
+
multiple,
|
|
94
|
+
renderAcceptedFile,
|
|
95
|
+
renderRejectedFile,
|
|
96
|
+
showRejected = false,
|
|
97
|
+
className,
|
|
98
|
+
icon: Icon = UploadCloud,
|
|
99
|
+
iconSize = 40,
|
|
100
|
+
onError,
|
|
101
|
+
...props
|
|
102
|
+
}: DropzoneProps) => {
|
|
103
|
+
const allowedLabels = useMemo(() => {
|
|
104
|
+
return allowedExtensions.map((ext) => ext.split("/")?.[1]).join(", ");
|
|
105
|
+
}, [allowedExtensions]);
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<UploadRoot
|
|
109
|
+
onFileAdd={onFileAdd}
|
|
110
|
+
onFileRemove={onFileRemove}
|
|
111
|
+
files={files}
|
|
112
|
+
onChangeFiles={onChangeFiles}
|
|
113
|
+
maxFiles={maxFiles}
|
|
114
|
+
allowedExtensions={allowedExtensions}
|
|
115
|
+
maxFileSize={maxFileSize}
|
|
116
|
+
multiple={multiple ? true : undefined}
|
|
117
|
+
className={cn("w-full", className)}
|
|
118
|
+
onError={onError}
|
|
119
|
+
{...props}
|
|
120
|
+
>
|
|
121
|
+
<UploadTrigger asChild>
|
|
122
|
+
<div
|
|
123
|
+
className={cn(
|
|
124
|
+
"w-full min-h-[150px] border-2 border-dashed rounded-lg border-muted p-4",
|
|
125
|
+
"hover:bg-muted/50 data-[drag-active=true]:border-primary data-[drag-active=true]:bg-primary/10",
|
|
126
|
+
"transition-colors flex flex-col items-center justify-center gap-4",
|
|
127
|
+
"pointer-events-auto",
|
|
128
|
+
)}
|
|
129
|
+
>
|
|
130
|
+
<Icon
|
|
131
|
+
className="text-muted-foreground pointer-events-none"
|
|
132
|
+
style={{ width: iconSize, height: iconSize }}
|
|
133
|
+
/>
|
|
134
|
+
<div className="text-center text-muted-foreground pointer-events-none">
|
|
135
|
+
<p>Arrastra y suelta archivos aquí o haz clic para seleccionar</p>
|
|
136
|
+
{allowedExtensions.length > 0 && (
|
|
137
|
+
<p className="text-sm">Tipos permitidos: {allowedLabels}</p>
|
|
138
|
+
)}
|
|
139
|
+
<p className="text-sm">
|
|
140
|
+
Tamaño máximo: {Math.floor(maxFileSize / 1024 / 1024)}MB
|
|
141
|
+
</p>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</UploadTrigger>
|
|
145
|
+
|
|
146
|
+
<UploadContent>
|
|
147
|
+
<UploadAcceptedFiles renderFile={renderAcceptedFile} />
|
|
148
|
+
{showRejected && (
|
|
149
|
+
<UploadRejectedFiles renderFile={renderRejectedFile} />
|
|
150
|
+
)}
|
|
151
|
+
</UploadContent>
|
|
152
|
+
</UploadRoot>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export const FileType = {
|
|
2
|
+
// Imágenes
|
|
3
|
+
JPEG: "image/jpeg",
|
|
4
|
+
JPG: "image/jpg",
|
|
5
|
+
PNG: "image/png",
|
|
6
|
+
GIF: "image/gif",
|
|
7
|
+
WEBP: "image/webp",
|
|
8
|
+
SVG: "image/svg+xml",
|
|
9
|
+
|
|
10
|
+
// Documentos
|
|
11
|
+
PDF: "application/pdf",
|
|
12
|
+
DOC: "application/msword",
|
|
13
|
+
DOCX: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
14
|
+
XLS: "application/vnd.ms-excel",
|
|
15
|
+
XLSX: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
16
|
+
PPT: "application/vnd.ms-powerpoint",
|
|
17
|
+
PPTX: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
18
|
+
|
|
19
|
+
// Archivos de texto
|
|
20
|
+
TXT: "text/plain",
|
|
21
|
+
CSV: "text/csv",
|
|
22
|
+
|
|
23
|
+
// Archivos comprimidos
|
|
24
|
+
ZIP: "application/zip",
|
|
25
|
+
RAR: "application/x-rar-compressed",
|
|
26
|
+
|
|
27
|
+
// Audio
|
|
28
|
+
MP3: "audio/mpeg",
|
|
29
|
+
WAV: "audio/wav",
|
|
30
|
+
|
|
31
|
+
// Video
|
|
32
|
+
MP4: "video/mp4",
|
|
33
|
+
WEBM: "video/webm",
|
|
34
|
+
|
|
35
|
+
// Otros
|
|
36
|
+
JSON: "application/json",
|
|
37
|
+
XML: "application/xml",
|
|
38
|
+
} as const;
|
|
39
|
+
|
|
40
|
+
export type FileTypeValue = (typeof FileType)[keyof typeof FileType];
|
|
41
|
+
|
|
42
|
+
// Grupos comunes de tipos de archivo
|
|
43
|
+
export const FileTypeGroups: Record<string, FileTypeValue[]> = {
|
|
44
|
+
IMAGES: [
|
|
45
|
+
FileType.JPEG,
|
|
46
|
+
FileType.JPG,
|
|
47
|
+
FileType.PNG,
|
|
48
|
+
FileType.GIF,
|
|
49
|
+
FileType.WEBP,
|
|
50
|
+
FileType.SVG,
|
|
51
|
+
],
|
|
52
|
+
DOCUMENTS: [
|
|
53
|
+
FileType.PDF,
|
|
54
|
+
FileType.DOC,
|
|
55
|
+
FileType.DOCX,
|
|
56
|
+
FileType.XLS,
|
|
57
|
+
FileType.XLSX,
|
|
58
|
+
FileType.PPT,
|
|
59
|
+
FileType.PPTX,
|
|
60
|
+
],
|
|
61
|
+
COMPRESSED: [FileType.ZIP, FileType.RAR],
|
|
62
|
+
AUDIO: [FileType.MP3, FileType.WAV],
|
|
63
|
+
VIDEO: [FileType.MP4, FileType.WEBM],
|
|
64
|
+
} as const;
|