@boxcustodia/library 2.0.0-alpha.10 → 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.cjs.js +70 -70
- package/dist/index.css +2 -0
- package/dist/index.d.ts +420 -272
- package/dist/index.es.js +34448 -27816
- package/dist/theme.css +1 -1
- package/package.json +11 -6
- 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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
eachDayOfInterval,
|
|
3
|
+
endOfMonth,
|
|
4
|
+
endOfWeek,
|
|
5
|
+
startOfWeek,
|
|
6
|
+
} from "date-fns";
|
|
7
|
+
import { useMemo } from "react";
|
|
8
|
+
import { ClassName } from "@/models";
|
|
9
|
+
import { Day, DayProps } from "./day";
|
|
10
|
+
import { WeekDays, WeekDaysProps } from "./week-days";
|
|
11
|
+
|
|
12
|
+
type MonthViewProps = {
|
|
13
|
+
navigationDate: Date;
|
|
14
|
+
disabled?: (date: Date) => boolean;
|
|
15
|
+
dayClassName?: ClassName;
|
|
16
|
+
dayProps?: DayProps;
|
|
17
|
+
weekDaysClassName?: ClassName;
|
|
18
|
+
weekDaysProps?: WeekDaysProps;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const MonthView = ({
|
|
22
|
+
navigationDate,
|
|
23
|
+
disabled,
|
|
24
|
+
weekDaysClassName,
|
|
25
|
+
weekDaysProps,
|
|
26
|
+
dayClassName,
|
|
27
|
+
dayProps,
|
|
28
|
+
}: MonthViewProps) => {
|
|
29
|
+
const getMonthInterval = (): Date[] =>
|
|
30
|
+
eachDayOfInterval({
|
|
31
|
+
start: startOfWeek(navigationDate, { weekStartsOn: 1 }),
|
|
32
|
+
end: endOfWeek(endOfMonth(navigationDate), { weekStartsOn: 1 }),
|
|
33
|
+
});
|
|
34
|
+
const days = useMemo(getMonthInterval, [navigationDate]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<WeekDays className={weekDaysClassName} {...weekDaysProps} />
|
|
39
|
+
<div
|
|
40
|
+
className="grid grid-cols-7 mt-2 text-sm"
|
|
41
|
+
data-slot="calendar-month-view"
|
|
42
|
+
>
|
|
43
|
+
{days.map((day: Date, index: number) => (
|
|
44
|
+
<Day
|
|
45
|
+
key={index}
|
|
46
|
+
day={day}
|
|
47
|
+
className={dayClassName}
|
|
48
|
+
{...dayProps}
|
|
49
|
+
navigationDate={navigationDate}
|
|
50
|
+
disabled={disabled?.(day)}
|
|
51
|
+
/>
|
|
52
|
+
))}
|
|
53
|
+
</div>
|
|
54
|
+
</>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export { MonthView, type MonthViewProps };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { at } from "lodash";
|
|
2
|
+
import { HTMLProps } from "react";
|
|
3
|
+
import { cn } from "../../../lib";
|
|
4
|
+
import { weeksDays } from "../calendar.model";
|
|
5
|
+
|
|
6
|
+
type WeekDaysProps = HTMLProps<HTMLDivElement>;
|
|
7
|
+
|
|
8
|
+
const WeekDays = (props: WeekDaysProps) => {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
{...props}
|
|
12
|
+
className={cn(
|
|
13
|
+
"grid grid-cols-7 font-semibold mt-2 text-xs leading-6 text-center py-1 bg-blue-bell/40 select-none",
|
|
14
|
+
props.className,
|
|
15
|
+
)}
|
|
16
|
+
data-slot="calendar-week-days"
|
|
17
|
+
>
|
|
18
|
+
{weeksDays.map((day: string) => (
|
|
19
|
+
<abbr key={day} aria-label={day} data-slot="calendar-week-day">
|
|
20
|
+
{at(day, 0)}
|
|
21
|
+
</abbr>
|
|
22
|
+
))}
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export { WeekDays, type WeekDaysProps };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { format, setMonth } from "date-fns";
|
|
2
|
+
import { Button } from "../../../components";
|
|
3
|
+
import { monthNames, ViewProps } from "../calendar.model";
|
|
4
|
+
|
|
5
|
+
const YearView = ({ value, onChange }: ViewProps) => {
|
|
6
|
+
const selectMonth = (month: number): void => {
|
|
7
|
+
const newDate = setMonth(value, month);
|
|
8
|
+
onChange(newDate);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="grid grid-cols-3 grow" data-slot="calendar-year-view">
|
|
13
|
+
{monthNames.map((month) => (
|
|
14
|
+
<Button
|
|
15
|
+
type="button"
|
|
16
|
+
className="h-full rounded"
|
|
17
|
+
onClick={() => selectMonth(monthNames.indexOf(month))}
|
|
18
|
+
key={month}
|
|
19
|
+
variant="ghost"
|
|
20
|
+
data-slot="calendar-year-view-month"
|
|
21
|
+
>
|
|
22
|
+
<abbr aria-label={`${month} ${format(value, "yyyy")}`}>{month}</abbr>
|
|
23
|
+
</Button>
|
|
24
|
+
))}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { YearView, type ViewProps as YearViewProps };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as useCalendar } from "./use-calendar";
|
|
2
|
+
export { default as useCalendarNavigation } from "./use-calendar-navigation";
|
|
3
|
+
export { default as useRangeCalendar } from "./use-range-calendar";
|
|
4
|
+
export { default as useSingleCalendar } from "./use-single-calendar";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { addMonths, addYears, format, parse, startOfToday } from "date-fns";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { DateSingle } from "../calendar.model";
|
|
4
|
+
|
|
5
|
+
function useCalendarNavigation(value: DateSingle = startOfToday()) {
|
|
6
|
+
const [date, setDate] = useState({
|
|
7
|
+
month: format(value || startOfToday(), "MM"),
|
|
8
|
+
year: format(value || startOfToday(), "yyyy"),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const navigationDate: Date = useMemo(
|
|
12
|
+
() => parse(`${date.month}-${date.year}`, "MM-yyyy", new Date()),
|
|
13
|
+
[date],
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const setMonth = (newDate: Date): void => {
|
|
17
|
+
setDate({
|
|
18
|
+
...date,
|
|
19
|
+
month: format(newDate, "MM"),
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const setYear = (newDate: Date): void => {
|
|
24
|
+
setDate({
|
|
25
|
+
...date,
|
|
26
|
+
year: format(newDate, "yyyy"),
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const previousMonth = (): void => {
|
|
31
|
+
const previousMonthDate = addMonths(navigationDate, -1);
|
|
32
|
+
setDate({
|
|
33
|
+
month: format(previousMonthDate, "MM"),
|
|
34
|
+
year: format(previousMonthDate, "yyyy"),
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const nextMonth = (): void => {
|
|
39
|
+
const nextMonthDate = addMonths(navigationDate, 1);
|
|
40
|
+
setDate({
|
|
41
|
+
month: format(nextMonthDate, "MM"),
|
|
42
|
+
year: format(nextMonthDate, "yyyy"),
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const previousYear = (): void => {
|
|
47
|
+
const firstDayPreviousYear = addYears(navigationDate, -1);
|
|
48
|
+
setYear(firstDayPreviousYear);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const nextYear = (): void => {
|
|
52
|
+
const firstDayNextYear = addYears(navigationDate, 1);
|
|
53
|
+
setYear(firstDayNextYear);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const previousDecade = (): void => {
|
|
57
|
+
const firstDayPreviousDecade = addYears(navigationDate, -10);
|
|
58
|
+
setYear(firstDayPreviousDecade);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const nextDecade = (): void => {
|
|
62
|
+
const firstDayNextDecade = addYears(navigationDate, 10);
|
|
63
|
+
setYear(firstDayNextDecade);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
navigationDate,
|
|
68
|
+
setMonth,
|
|
69
|
+
setYear,
|
|
70
|
+
previousMonth,
|
|
71
|
+
nextMonth,
|
|
72
|
+
previousYear,
|
|
73
|
+
nextYear,
|
|
74
|
+
previousDecade,
|
|
75
|
+
nextDecade,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default useCalendarNavigation;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
2
|
+
import { isDate } from "date-fns";
|
|
3
|
+
import { isArray } from "lodash";
|
|
4
|
+
import { createContext } from "react";
|
|
5
|
+
import {
|
|
6
|
+
CalendarModeProps,
|
|
7
|
+
CalendarState,
|
|
8
|
+
DateMatcher,
|
|
9
|
+
Mode,
|
|
10
|
+
} from "../calendar.model";
|
|
11
|
+
import { isDateRange } from "../utils/typeguards";
|
|
12
|
+
import useMultipleCalendar from "./use-multiple-calendar";
|
|
13
|
+
import useRangeCalendar from "./use-range-calendar";
|
|
14
|
+
import useSingleCalendar from "./use-single-calendar";
|
|
15
|
+
|
|
16
|
+
export const CalendarContext = createContext<CalendarState>({
|
|
17
|
+
defaultStartDate: new Date(),
|
|
18
|
+
mode: "single",
|
|
19
|
+
isSingleMode: false,
|
|
20
|
+
isRangeMode: false,
|
|
21
|
+
selected: null,
|
|
22
|
+
selectDate: () => {},
|
|
23
|
+
isSelected: () => false,
|
|
24
|
+
isFirstDayFromRange: () => false,
|
|
25
|
+
isLastDayFromRange: () => false,
|
|
26
|
+
isInRange: () => false,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function useCalendar<T extends Mode>(props: CalendarModeProps<T>) {
|
|
30
|
+
const { mode, value, defaultValue, onChange, disabled } = props;
|
|
31
|
+
const isSingleMode = mode === "single";
|
|
32
|
+
const isRangeMode = mode === "range";
|
|
33
|
+
const isMultipleMode = mode === "multiple";
|
|
34
|
+
|
|
35
|
+
const [selected = null, setSelected] = useControllableState<DateMatcher>({
|
|
36
|
+
prop: value,
|
|
37
|
+
onChange: onChange as any,
|
|
38
|
+
defaultProp: defaultValue as any,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const { selectSingleDate, isSingleSelected } = useSingleCalendar(
|
|
42
|
+
isDate(selected) ? selected : undefined,
|
|
43
|
+
setSelected,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const { selectRangeDate, isInRange, ...range } = useRangeCalendar(
|
|
47
|
+
isDateRange(selected) ? selected : undefined,
|
|
48
|
+
setSelected,
|
|
49
|
+
disabled,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const { selectMultipleDate, isMultipleSelected } = useMultipleCalendar(
|
|
53
|
+
isArray(selected) ? selected : undefined,
|
|
54
|
+
setSelected,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const selectDate = (date: Date): void => {
|
|
58
|
+
if (isSingleMode) return selectSingleDate(date);
|
|
59
|
+
if (isRangeMode) return selectRangeDate(date);
|
|
60
|
+
if (isMultipleMode) return selectMultipleDate(date);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const isSelected = (day: Date): boolean => {
|
|
64
|
+
if (isSingleMode) return isSingleSelected(day);
|
|
65
|
+
if (isRangeMode) return isInRange(day);
|
|
66
|
+
if (isMultipleMode) return isMultipleSelected(day);
|
|
67
|
+
return false;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const getDefaultStartDate = (): Date => {
|
|
71
|
+
if (isDate(selected)) return selected;
|
|
72
|
+
if (isArray(selected)) return selected[0];
|
|
73
|
+
if (isDateRange(selected) && selected.start) return selected.start;
|
|
74
|
+
return new Date();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
defaultStartDate: getDefaultStartDate(),
|
|
79
|
+
isSingleMode,
|
|
80
|
+
isRangeMode,
|
|
81
|
+
selected,
|
|
82
|
+
isSelected,
|
|
83
|
+
selectDate,
|
|
84
|
+
isInRange,
|
|
85
|
+
mode,
|
|
86
|
+
...range,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default useCalendar;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { isSameDay } from "date-fns";
|
|
2
|
+
import { findIndex, isArray } from "lodash";
|
|
3
|
+
import { DateMultiple } from "../calendar.model";
|
|
4
|
+
|
|
5
|
+
function useMultipleCalendar(
|
|
6
|
+
selected: DateMultiple | undefined,
|
|
7
|
+
setSelected: (dates: DateMultiple) => void,
|
|
8
|
+
) {
|
|
9
|
+
const selectMultipleDate = (date: Date): void => {
|
|
10
|
+
if (!selected) return setSelected([date]);
|
|
11
|
+
|
|
12
|
+
const index = findIndex(selected, (stateDate: Date) =>
|
|
13
|
+
isSameDay(stateDate, date),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (index === -1) return setSelected([...selected, date]);
|
|
17
|
+
|
|
18
|
+
const newSelected = [
|
|
19
|
+
...selected.slice(0, index),
|
|
20
|
+
...selected.slice(index + 1),
|
|
21
|
+
];
|
|
22
|
+
setSelected(newSelected);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const isMultipleSelected = (day: Date): boolean =>
|
|
26
|
+
isArray(selected) && selected.some((date: Date) => isSameDay(date, day));
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
selectMultipleDate,
|
|
30
|
+
isMultipleSelected,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default useMultipleCalendar;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
eachDayOfInterval,
|
|
3
|
+
isBefore,
|
|
4
|
+
isSameDay,
|
|
5
|
+
isWithinInterval,
|
|
6
|
+
startOfDay,
|
|
7
|
+
} from "date-fns";
|
|
8
|
+
import { DateRange, DateSingle } from "../calendar.model";
|
|
9
|
+
import { isDateRange } from "../utils/typeguards";
|
|
10
|
+
|
|
11
|
+
function useRangeCalendar(
|
|
12
|
+
selected: DateRange | undefined,
|
|
13
|
+
// FIX: remove any
|
|
14
|
+
setSelected: any,
|
|
15
|
+
disabled?: (date: Date) => boolean,
|
|
16
|
+
) {
|
|
17
|
+
const selectRangeDate = (date: Date): void => {
|
|
18
|
+
const firstDateSelected = selected?.start;
|
|
19
|
+
if (firstDateSelected) {
|
|
20
|
+
const { start, end } = selected;
|
|
21
|
+
const isEndBeforeStart = isBefore(date, start!);
|
|
22
|
+
const isNewRange = start && end;
|
|
23
|
+
|
|
24
|
+
if (isEndBeforeStart || isNewRange) {
|
|
25
|
+
setSelected({ start: date, end: undefined });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (hasDisabledDateInRange(start, date)) return;
|
|
30
|
+
|
|
31
|
+
setSelected({
|
|
32
|
+
start,
|
|
33
|
+
end: date,
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
setSelected({ start: date, end: undefined });
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const hasDisabledDateInRange = (
|
|
41
|
+
start: DateSingle,
|
|
42
|
+
end: DateSingle,
|
|
43
|
+
): boolean => {
|
|
44
|
+
if (!disabled) return false;
|
|
45
|
+
if (!start || !end) return false;
|
|
46
|
+
const interval = eachDayOfInterval({ start: startOfDay(start), end: end });
|
|
47
|
+
const hasDisabled = interval.some((date) => disabled(date));
|
|
48
|
+
return hasDisabled;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const isInRange = (day: Date): boolean => {
|
|
52
|
+
if (!isDateRange(selected)) return false;
|
|
53
|
+
if (!selected) return false;
|
|
54
|
+
|
|
55
|
+
const { start, end } = selected;
|
|
56
|
+
|
|
57
|
+
const isOnlyStartSelected = start && !end;
|
|
58
|
+
if (isOnlyStartSelected) {
|
|
59
|
+
return isSameDay(day, start);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!start || !end) return false;
|
|
63
|
+
return isWithinInterval(day, {
|
|
64
|
+
start: startOfDay(start),
|
|
65
|
+
end: startOfDay(end),
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const isFirstDayFromRange = (day: Date): boolean => {
|
|
70
|
+
if (!selected) return false;
|
|
71
|
+
if (!isDateRange(selected)) return false;
|
|
72
|
+
if (!selected.start) return false;
|
|
73
|
+
return isSameDay(day, selected.start);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const isLastDayFromRange = (day: Date): boolean => {
|
|
77
|
+
if (!selected) return false;
|
|
78
|
+
if (!isDateRange(selected)) return false;
|
|
79
|
+
if (!selected.end) return false;
|
|
80
|
+
return isSameDay(day, selected.end);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
selectRangeDate,
|
|
85
|
+
isInRange,
|
|
86
|
+
isFirstDayFromRange,
|
|
87
|
+
isLastDayFromRange,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default useRangeCalendar;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { isDate, isSameDay } from "date-fns";
|
|
2
|
+
import { DateSingle } from "../calendar.model";
|
|
3
|
+
|
|
4
|
+
function useSingleCalendar(selected: DateSingle | undefined, setSelected: any) {
|
|
5
|
+
const selectSingleDate = (date: Date): void => {
|
|
6
|
+
setSelected(date);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const isSingleSelected = (day: Date): boolean =>
|
|
10
|
+
isDate(selected) && isSameDay(day, selected);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
selectSingleDate,
|
|
14
|
+
isSingleSelected,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default useSingleCalendar;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./calendar";
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
3
|
+
import { ComponentType } from "react";
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Card,
|
|
7
|
+
CardContent,
|
|
8
|
+
CardDescription,
|
|
9
|
+
CardFooter,
|
|
10
|
+
CardHeader,
|
|
11
|
+
CardTitle,
|
|
12
|
+
} from "../../components";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* El componente Card es un contenedor versátil que permite organizar y presentar contenido
|
|
16
|
+
* de manera estructurada y visualmente atractiva.
|
|
17
|
+
*
|
|
18
|
+
* ### Características principales
|
|
19
|
+
* - Diseño modular y flexible
|
|
20
|
+
* - Soporte para encabezados, contenido y pie de página
|
|
21
|
+
* - Personalizable a través de className
|
|
22
|
+
* - Ideal para mostrar información, productos, artículos, etc.
|
|
23
|
+
*
|
|
24
|
+
* ### Estructura básica
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <Card>
|
|
27
|
+
* <CardHeader>
|
|
28
|
+
* <CardTitle>Título del Card</CardTitle>
|
|
29
|
+
* <CardDescription>Descripción opcional</CardDescription>
|
|
30
|
+
* </CardHeader>
|
|
31
|
+
* <CardContent>
|
|
32
|
+
* Contenido principal
|
|
33
|
+
* </CardContent>
|
|
34
|
+
* <CardFooter>
|
|
35
|
+
* Acciones o contenido adicional
|
|
36
|
+
* </CardFooter>
|
|
37
|
+
* </Card>
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
const meta: Meta<typeof Card> = {
|
|
41
|
+
title: "data display/Card",
|
|
42
|
+
component: Card,
|
|
43
|
+
tags: ["autodocs"],
|
|
44
|
+
subcomponents: {
|
|
45
|
+
CardHeader: CardHeader as ComponentType<unknown>,
|
|
46
|
+
CardTitle: CardTitle as ComponentType<unknown>,
|
|
47
|
+
CardDescription: CardDescription as ComponentType<unknown>,
|
|
48
|
+
CardContent: CardContent as ComponentType<unknown>,
|
|
49
|
+
CardFooter: CardFooter as ComponentType<unknown>,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default meta;
|
|
54
|
+
|
|
55
|
+
type Story = StoryObj<typeof Card>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Ejemplo básico de un Card con todos sus componentes.
|
|
59
|
+
* Muestra la estructura típica con encabezado, contenido y pie de página.
|
|
60
|
+
*/
|
|
61
|
+
export const Default: Story = {
|
|
62
|
+
render: () => (
|
|
63
|
+
<Card className="w-[350px] shadow-md rounded-lg">
|
|
64
|
+
<CardHeader className="p-4">
|
|
65
|
+
<CardTitle className="text-2xl">
|
|
66
|
+
How to Improve Your Productivity
|
|
67
|
+
</CardTitle>
|
|
68
|
+
<CardDescription className="text-sm">By Jane Doe</CardDescription>
|
|
69
|
+
</CardHeader>
|
|
70
|
+
<CardContent className="p-4">
|
|
71
|
+
<p className="text-gray-700 text-base">
|
|
72
|
+
Discover the best strategies and tools to boost your productivity in
|
|
73
|
+
work and life. Learn how to manage your time effectively and stay
|
|
74
|
+
focused on what really matters.
|
|
75
|
+
</p>
|
|
76
|
+
</CardContent>
|
|
77
|
+
<CardFooter className="px-4 py-3 flex justify-between">
|
|
78
|
+
<Button variant="outline">Read More</Button>
|
|
79
|
+
<Button className="bg-blue-600 text-white">Save</Button>
|
|
80
|
+
</CardFooter>
|
|
81
|
+
</Card>
|
|
82
|
+
),
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Ejemplo de Card con imagen y diseño de producto.
|
|
87
|
+
* Demuestra cómo integrar elementos multimedia y crear layouts más complejos.
|
|
88
|
+
*/
|
|
89
|
+
export const Media: Story = {
|
|
90
|
+
render: () => (
|
|
91
|
+
<Card className="w-[350px] shadow-lg rounded-lg overflow-hidden">
|
|
92
|
+
<img
|
|
93
|
+
src={faker.image.url()}
|
|
94
|
+
alt="Featured Product"
|
|
95
|
+
className="w-full h-[150px] object-cover"
|
|
96
|
+
/>
|
|
97
|
+
<CardContent className="p-4">
|
|
98
|
+
<CardTitle className="text-xl font-bold text-gray-900">
|
|
99
|
+
Villa Luxury
|
|
100
|
+
</CardTitle>
|
|
101
|
+
<CardDescription className="text-sm text-gray-600">
|
|
102
|
+
Escapa a esta luxuriosa aldea con vistas maravillosas del océano y
|
|
103
|
+
piscina privada.
|
|
104
|
+
</CardDescription>
|
|
105
|
+
<div className="flex items-center mt-4">
|
|
106
|
+
<span className="text-2xl font-semibold text-gray-900">$750</span>
|
|
107
|
+
<span className="ml-2 text-sm text-gray-500">/ noche</span>
|
|
108
|
+
</div>
|
|
109
|
+
</CardContent>
|
|
110
|
+
<CardFooter className="px-4 py-3 bg-gray-100 flex justify-between">
|
|
111
|
+
<Button variant="outline">Detalle</Button>
|
|
112
|
+
<Button className="bg-blue-600 text-white">Comprar</Button>
|
|
113
|
+
</CardFooter>
|
|
114
|
+
</Card>
|
|
115
|
+
),
|
|
116
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { cn } from "../../lib";
|
|
3
|
+
|
|
4
|
+
export const Card = ({
|
|
5
|
+
className,
|
|
6
|
+
...props
|
|
7
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
8
|
+
<div
|
|
9
|
+
className={cn(
|
|
10
|
+
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
11
|
+
className,
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
data-slot="card"
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export const CardHeader = ({
|
|
19
|
+
className,
|
|
20
|
+
...props
|
|
21
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
22
|
+
<div
|
|
23
|
+
className={cn("flex flex-col space-y-1 p-6", className)}
|
|
24
|
+
{...props}
|
|
25
|
+
data-slot="card-header"
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const CardTitle = ({
|
|
30
|
+
className,
|
|
31
|
+
...props
|
|
32
|
+
}: React.HTMLAttributes<HTMLHeadingElement>) => (
|
|
33
|
+
<h3
|
|
34
|
+
className={cn(
|
|
35
|
+
"text-2xl font-semibold leading-none tracking-tight",
|
|
36
|
+
className,
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
data-slot="card-title"
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export const CardDescription = ({
|
|
44
|
+
className,
|
|
45
|
+
...props
|
|
46
|
+
}: React.HTMLAttributes<HTMLParagraphElement>) => (
|
|
47
|
+
<p
|
|
48
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
49
|
+
{...props}
|
|
50
|
+
data-slot="card-description"
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export const CardContent = ({
|
|
55
|
+
className,
|
|
56
|
+
...props
|
|
57
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
58
|
+
<div
|
|
59
|
+
className={cn("p-6 pt-0", className)}
|
|
60
|
+
{...props}
|
|
61
|
+
data-slot="card-content"
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
export const CardFooter = ({
|
|
66
|
+
className,
|
|
67
|
+
...props
|
|
68
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
69
|
+
<div
|
|
70
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
71
|
+
{...props}
|
|
72
|
+
data-slot="card-footer"
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./card";
|