@soyfri/shared-library 2.0.0-beta.2 → 2.0.0-beta.4

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.
Files changed (187) hide show
  1. package/.dockerignore +8 -0
  2. package/.github/workflows/publish.yml +107 -0
  3. package/.prettierrc +3 -0
  4. package/.storybook/main.ts +19 -0
  5. package/.storybook/preview.ts +14 -0
  6. package/.storybook/vitest.setup.ts +9 -0
  7. package/Dockerfile +37 -0
  8. package/build.js +102 -0
  9. package/chromatic.config.json +5 -0
  10. package/cleanDirectories.js +40 -0
  11. package/dist/README.md +243 -0
  12. package/dist/components/Icon/Icon.js +1 -1
  13. package/dist/components/Table/Table.js +1 -1
  14. package/dist/index.cjs +24 -0
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +7 -1
  17. package/dist/mui.d.ts +1 -0
  18. package/dist/package.json +197 -0
  19. package/package.json +4 -32
  20. package/rollup.config.cjs +87 -0
  21. package/src/components/ActionMenu/ActionMenu.stories.tsx +230 -0
  22. package/src/components/ActionMenu/ActionMenu.tsx +174 -0
  23. package/src/components/ActionMenu/index.ts +2 -0
  24. package/src/components/AppBar/AppBar.stories.tsx +272 -0
  25. package/src/components/AppBar/AppBar.sx.ts +32 -0
  26. package/src/components/AppBar/AppBar.tsx +123 -0
  27. package/src/components/AppBar/AppBarBrand.tsx +120 -0
  28. package/src/components/AppBar/AppBarContext.ts +25 -0
  29. package/src/components/AppBar/AppBarMenuToggle.tsx +90 -0
  30. package/src/components/AppBar/AppBarUserMenu.tsx +217 -0
  31. package/src/components/AppBar/index.ts +25 -0
  32. package/src/components/Autocomplete/Autocomplete.definitions.ts +477 -0
  33. package/src/components/Autocomplete/Autocomplete.helpers.ts +60 -0
  34. package/src/components/Autocomplete/Autocomplete.stories.tsx +748 -0
  35. package/src/components/Autocomplete/Autocomplete.sx.ts +30 -0
  36. package/src/components/Autocomplete/Autocomplete.tsx +361 -0
  37. package/src/components/Autocomplete/Autocomplete.types.ts +13 -0
  38. package/src/components/Autocomplete/_parts/AutocompleteChips.tsx +55 -0
  39. package/src/components/Autocomplete/_parts/AutocompleteLoader.tsx +17 -0
  40. package/src/components/Autocomplete/_parts/AutocompleteOption.tsx +31 -0
  41. package/src/components/Autocomplete/index.ts +12 -0
  42. package/src/components/Avatar/Avatar.definitions.ts +162 -0
  43. package/src/components/Avatar/Avatar.stories.tsx +258 -0
  44. package/src/components/Avatar/Avatar.tsx +206 -0
  45. package/src/components/Avatar/index.ts +1 -0
  46. package/src/components/Button/Button.definition.ts +97 -0
  47. package/src/components/Button/Button.stories.tsx +285 -0
  48. package/src/components/Button/Button.tsx +67 -0
  49. package/src/components/Button/index.ts +1 -0
  50. package/src/components/Card/Card.definition.ts +5 -0
  51. package/src/components/Card/Card.stories.tsx +221 -0
  52. package/src/components/Card/Card.sx.ts +104 -0
  53. package/src/components/Card/Card.tsx +200 -0
  54. package/src/components/Card/index.ts +9 -0
  55. package/src/components/Chip/Chip.definitions.ts +167 -0
  56. package/src/components/Chip/Chip.stories.tsx +265 -0
  57. package/src/components/Chip/Chip.tsx +61 -0
  58. package/src/components/Chip/index.ts +1 -0
  59. package/src/components/Column/Column.tsx +29 -0
  60. package/src/components/Column/index.ts +1 -0
  61. package/src/components/DatePicker/DatePicker.definitions.ts +228 -0
  62. package/src/components/DatePicker/DatePicker.helpers.ts +24 -0
  63. package/src/components/DatePicker/DatePicker.stories.tsx +309 -0
  64. package/src/components/DatePicker/DatePicker.sx.ts +33 -0
  65. package/src/components/DatePicker/DatePicker.tsx +189 -0
  66. package/src/components/DatePicker/DatePicker.types.ts +10 -0
  67. package/src/components/DatePicker/index.ts +9 -0
  68. package/src/components/DateRangePicker/DateRangePicker.definitions.ts +191 -0
  69. package/src/components/DateRangePicker/DateRangePicker.stories.tsx +252 -0
  70. package/src/components/DateRangePicker/DateRangePicker.tsx +56 -0
  71. package/src/components/DateRangePicker/index.ts +1 -0
  72. package/src/components/DateTimePicker/DateTimePicker.definitions.ts +256 -0
  73. package/src/components/DateTimePicker/DateTimePicker.helpers.ts +38 -0
  74. package/src/components/DateTimePicker/DateTimePicker.stories.tsx +418 -0
  75. package/src/components/DateTimePicker/DateTimePicker.sx.ts +30 -0
  76. package/src/components/DateTimePicker/DateTimePicker.tsx +225 -0
  77. package/src/components/DateTimePicker/DateTimePicker.types.ts +10 -0
  78. package/src/components/DateTimePicker/index.ts +9 -0
  79. package/src/components/Drawer/Drawer.stories.tsx +270 -0
  80. package/src/components/Drawer/Drawer.sx.ts +106 -0
  81. package/src/components/Drawer/Drawer.tsx +214 -0
  82. package/src/components/Drawer/DrawerContext.ts +26 -0
  83. package/src/components/Drawer/DrawerItem.tsx +110 -0
  84. package/src/components/Drawer/index.ts +10 -0
  85. package/src/components/Flyout/Flyout.stories.tsx +282 -0
  86. package/src/components/Flyout/Flyout.tsx +122 -0
  87. package/src/components/Flyout/index.ts +1 -0
  88. package/src/components/Gallery/Gallery.definition.tsx +37 -0
  89. package/src/components/Gallery/Gallery.stories.tsx +82 -0
  90. package/src/components/Gallery/Gallery.tsx +118 -0
  91. package/src/components/Gallery/GalleryLightbox.tsx +170 -0
  92. package/src/components/Gallery/GalleryMain.tsx +84 -0
  93. package/src/components/Gallery/GalleryThumbnails.tsx +106 -0
  94. package/src/components/Gallery/index.ts +1 -0
  95. package/src/components/Icon/Icon.stories.tsx +121 -0
  96. package/src/components/Icon/Icon.tsx +175 -0
  97. package/src/components/Icon/index.ts +2 -0
  98. package/src/components/Input/Input.definitions.ts +324 -0
  99. package/src/components/Input/Input.helpers.ts +49 -0
  100. package/src/components/Input/Input.stories.tsx +499 -0
  101. package/src/components/Input/Input.sx.ts +42 -0
  102. package/src/components/Input/Input.tsx +141 -0
  103. package/src/components/Input/Input.types.ts +10 -0
  104. package/src/components/Input/index.ts +9 -0
  105. package/src/components/InputGroup/InputGroup.definitions.ts +158 -0
  106. package/src/components/InputGroup/InputGroup.stories.tsx +267 -0
  107. package/src/components/InputGroup/InputGroup.tsx +179 -0
  108. package/src/components/InputGroup/index.ts +1 -0
  109. package/src/components/MenuButton/MenuButton.stories.tsx +197 -0
  110. package/src/components/MenuButton/MenuButton.tsx +100 -0
  111. package/src/components/MenuButton/index.ts +1 -0
  112. package/src/components/Modal/Modal.stories.tsx +721 -0
  113. package/src/components/Modal/Modal.tsx +355 -0
  114. package/src/components/Modal/ModalBody.tsx +16 -0
  115. package/src/components/Modal/ModalFooter.tsx +71 -0
  116. package/src/components/Modal/ModalHeader.tsx +18 -0
  117. package/src/components/Modal/index.ts +6 -0
  118. package/src/components/PageLoader/PageLoader.stories.tsx +217 -0
  119. package/src/components/PageLoader/PageLoader.tsx +96 -0
  120. package/src/components/PageLoader/index.ts +2 -0
  121. package/src/components/ScrollTopButton/ScrollTopButton.stories.tsx +158 -0
  122. package/src/components/ScrollTopButton/ScrollTopButton.tsx +135 -0
  123. package/src/components/ScrollTopButton/index.ts +8 -0
  124. package/src/components/ScrollTopButton/scrollToTop.ts +37 -0
  125. package/src/components/Select/Select.definitions.ts +602 -0
  126. package/src/components/Select/Select.helpers.ts +71 -0
  127. package/src/components/Select/Select.stories.tsx +687 -0
  128. package/src/components/Select/Select.sx.ts +14 -0
  129. package/src/components/Select/Select.tsx +429 -0
  130. package/src/components/Select/Select.types.ts +15 -0
  131. package/src/components/Select/_parts/SelectMenuItem.tsx +40 -0
  132. package/src/components/Select/_parts/SelectSearchHeader.tsx +51 -0
  133. package/src/components/Select/_parts/SelectValue.tsx +96 -0
  134. package/src/components/Select/index.ts +14 -0
  135. package/src/components/Stat/Stat.stories.tsx +85 -0
  136. package/src/components/Stat/Stat.tsx +117 -0
  137. package/src/components/Stat/index.ts +2 -0
  138. package/src/components/StatusMessage/StatusMessage.stories.tsx +130 -0
  139. package/src/components/StatusMessage/StatusMessage.tsx +162 -0
  140. package/src/components/StatusMessage/index.ts +2 -0
  141. package/src/components/Stepper/Step.tsx +21 -0
  142. package/src/components/Stepper/Stepper.definition.ts +75 -0
  143. package/src/components/Stepper/Stepper.stories.tsx +122 -0
  144. package/src/components/Stepper/Stepper.tsx +75 -0
  145. package/src/components/Stepper/index.ts +2 -0
  146. package/src/components/Table/EmptyTable.png +0 -0
  147. package/src/components/Table/Table.definition.ts +580 -0
  148. package/src/components/Table/Table.stories.tsx +853 -0
  149. package/src/components/Table/Table.tsx +495 -0
  150. package/src/components/Table/data.ts +134 -0
  151. package/src/components/Table/exportsUtils.ts +195 -0
  152. package/src/components/Table/index.ts +3 -0
  153. package/src/components/Table/types.ts +34 -0
  154. package/src/components/Tabs/Tab.definition.ts +53 -0
  155. package/src/components/Tabs/Tab.tsx +19 -0
  156. package/src/components/Tabs/Tabs.stories.tsx +118 -0
  157. package/src/components/Tabs/Tabs.tsx +99 -0
  158. package/src/components/Tabs/_tabUtils.tsx +4 -0
  159. package/src/components/Tabs/index.ts +2 -0
  160. package/src/components/Timeline/Timeline.definition.ts +43 -0
  161. package/src/components/Timeline/Timeline.stories.tsx +108 -0
  162. package/src/components/Timeline/Timeline.tsx +49 -0
  163. package/src/components/Timeline/TimelineItem.tsx +31 -0
  164. package/src/components/Timeline/index.ts +2 -0
  165. package/src/components/Tooltip/Tooltip.stories.tsx +129 -0
  166. package/src/components/Tooltip/Tooltip.tsx +58 -0
  167. package/src/components/Tooltip/index.ts +1 -0
  168. package/src/components/_shared/formField.sx.ts +118 -0
  169. package/src/components/_shared/resolvePreset.ts +35 -0
  170. package/src/hooks/ClipBoard/ClipBoard.stories.tsx +168 -0
  171. package/src/hooks/ClipBoard/ClipBoard.tsx +131 -0
  172. package/src/hooks/ClipBoard/ClipboardUnifiedDemo.tsx +111 -0
  173. package/src/hooks/ClipBoard/index.ts +1 -0
  174. package/src/hooks/Wizard/Wizard.stories.tsx +301 -0
  175. package/src/hooks/Wizard/WizardContext.tsx +166 -0
  176. package/src/hooks/Wizard/index.ts +6 -0
  177. package/src/hooks/Wizard/useWizard.ts +13 -0
  178. package/src/index.ts +17 -0
  179. package/src/mui.ts +54 -0
  180. package/src/styles.css +3 -0
  181. package/src/theme/componentStyles.ts +47 -0
  182. package/src/theme/tokens.ts +43 -0
  183. package/tailwind.config.js +10 -0
  184. package/tsconfig.json +48 -0
  185. package/tsup.config.js +41 -0
  186. package/vite.config.js +132 -0
  187. package/vitest.config.ts +35 -0
@@ -0,0 +1,189 @@
1
+ import React, { useMemo } from 'react';
2
+ import type { SxProps, Theme } from '@mui/material';
3
+ import { useTheme } from '@mui/material/styles';
4
+ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
5
+ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
6
+ import {
7
+ DatePicker as MuiDatePicker,
8
+ type DatePickerProps as MuiDatePickerProps,
9
+ } from '@mui/x-date-pickers/DatePicker';
10
+ import { DateValidationError } from '@mui/x-date-pickers/models';
11
+ import { Dayjs } from 'dayjs';
12
+ import { Controller, type Control, type RegisterOptions } from 'react-hook-form';
13
+ import 'dayjs/locale/en-gb';
14
+
15
+ import { buildDatePickerSx } from './DatePicker.sx';
16
+ import { getDateValidationMessage } from './DatePicker.helpers';
17
+ import { resolvePreset } from '../_shared/resolvePreset';
18
+
19
+ // ── Tipos de dominio ─────────────────────────────────────────────────────
20
+ export type LabelPosition = 'outside' | 'floating';
21
+ export type DatePickerSize = 'small' | 'medium';
22
+
23
+ // ── Props base ───────────────────────────────────────────────────────────
24
+ export interface BaseDatePickerProps
25
+ extends Omit<MuiDatePickerProps, 'value' | 'onChange' | 'slotProps'> {
26
+ label?: string;
27
+ minDate?: Dayjs;
28
+ maxDate?: Dayjs;
29
+ disabled?: boolean;
30
+ readOnly?: boolean;
31
+ /** Border radius del input. Default: 10 */
32
+ borderRadius?: number | string;
33
+ /** "outside" = label arriba del campo (default). "floating" = label clásico MUI dentro del borde */
34
+ labelPosition?: LabelPosition;
35
+ /** Tamaño del TextField renderizado. Default: 'small' */
36
+ size?: DatePickerSize;
37
+ /** helperText pasado al TextField (se sobrescribe por el error de validación si hay). */
38
+ helperText?: string;
39
+ /** Error external override. */
40
+ error?: boolean;
41
+ /** sx que se mergea al TextField interno del picker. */
42
+ sx?: SxProps<Theme>;
43
+ className?: string;
44
+ /**
45
+ * Nombre del preset de estilo registrado en `theme.styles.DatePicker`.
46
+ * - `"default"` (o ausente) = estilo built-in del paquete.
47
+ * - Cualquier otro string = mergea el preset encima del estilo built-in.
48
+ */
49
+ preset?: string;
50
+ /** Locale para el adaptador dayjs. Default: 'en-gb'. */
51
+ adapterLocale?: string;
52
+ /** Passthrough a slotProps.textField. */
53
+ textFieldProps?: Record<string, any>;
54
+ /** Passthrough completo a slotProps del MuiDatePicker. */
55
+ slotProps?: MuiDatePickerProps['slotProps'];
56
+ }
57
+
58
+ // ── Variantes discriminadas (RHF vs controlado) ──────────────────────────
59
+ export interface RHFDatePickerProps extends BaseDatePickerProps {
60
+ name: string;
61
+ control: Control<any>;
62
+ validation?: RegisterOptions;
63
+ selectedDate?: never;
64
+ onDateChange?: never;
65
+ }
66
+
67
+ export interface ControlledDatePickerProps extends BaseDatePickerProps {
68
+ name?: string;
69
+ control?: never;
70
+ validation?: never;
71
+ selectedDate: Dayjs | null;
72
+ onDateChange: (date: Dayjs | null) => void;
73
+ }
74
+
75
+ // ── API pública final ────────────────────────────────────────────────────
76
+ export type DatePickerProps = RHFDatePickerProps | ControlledDatePickerProps;
77
+
78
+ export const DatePicker: React.FC<DatePickerProps> = (props) => {
79
+ const {
80
+ label,
81
+ minDate,
82
+ maxDate,
83
+ disabled,
84
+ readOnly,
85
+ borderRadius = 10,
86
+ labelPosition = 'outside',
87
+ size = 'small',
88
+ helperText,
89
+ error: errorProp,
90
+ sx,
91
+ className,
92
+ preset,
93
+ adapterLocale = 'en-gb',
94
+ textFieldProps,
95
+ slotProps: slotPropsProp,
96
+ ...rest
97
+ } = props as ControlledDatePickerProps & {
98
+ control?: Control<any>;
99
+ validation?: RegisterOptions;
100
+ };
101
+
102
+ const [validationError, setValidationError] = React.useState<DateValidationError | null>(null);
103
+
104
+ const validationErrorMessage = useMemo(
105
+ () => getDateValidationMessage(validationError),
106
+ [validationError],
107
+ );
108
+
109
+ const theme = useTheme();
110
+ const presetSx = resolvePreset('DatePicker', preset, theme);
111
+
112
+ const mergedSx = [
113
+ buildDatePickerSx(borderRadius, labelPosition),
114
+ ...(presetSx ? [presetSx] : []),
115
+ ...(Array.isArray(sx) ? sx : [sx]),
116
+ ];
117
+
118
+ const renderPicker = (
119
+ value: Dayjs | null,
120
+ onChange: (date: Dayjs | null) => void,
121
+ onBlur?: () => void,
122
+ inputRef?: React.Ref<any>,
123
+ rhfError?: boolean,
124
+ rhfHelperText?: string,
125
+ ) => {
126
+ const finalError = rhfError || !!validationErrorMessage || !!errorProp;
127
+ const finalHelperText = rhfHelperText || validationErrorMessage || helperText;
128
+
129
+ return (
130
+ <LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale={adapterLocale}>
131
+ <MuiDatePicker
132
+ label={label}
133
+ value={value}
134
+ onChange={onChange}
135
+ minDate={minDate}
136
+ maxDate={maxDate}
137
+ onError={setValidationError}
138
+ disabled={disabled}
139
+ readOnly={readOnly}
140
+ className={className}
141
+ sx={mergedSx}
142
+ slotProps={{
143
+ ...slotPropsProp,
144
+ textField: {
145
+ fullWidth: true,
146
+ size,
147
+ variant: 'outlined',
148
+ onBlur,
149
+ inputRef,
150
+ error: !!finalError,
151
+ helperText: finalHelperText,
152
+ ...(slotPropsProp?.textField as Record<string, any> | undefined),
153
+ ...textFieldProps,
154
+ } as any,
155
+ }}
156
+ {...(rest as any)}
157
+ />
158
+ </LocalizationProvider>
159
+ );
160
+ };
161
+
162
+ // --- RHF mode ---
163
+ if ('control' in props && props.control) {
164
+ const { name, control, validation } = props as RHFDatePickerProps;
165
+ return (
166
+ <Controller
167
+ name={name}
168
+ control={control}
169
+ rules={validation}
170
+ render={({ field, fieldState: { error: fieldError } }) =>
171
+ renderPicker(
172
+ field.value ?? null,
173
+ field.onChange,
174
+ field.onBlur,
175
+ field.ref,
176
+ !!fieldError,
177
+ fieldError?.message,
178
+ )
179
+ }
180
+ />
181
+ );
182
+ }
183
+
184
+ // --- Controlado ---
185
+ const { selectedDate, onDateChange } = props as ControlledDatePickerProps;
186
+ return renderPicker(selectedDate, onDateChange);
187
+ };
188
+
189
+ export default DatePicker;
@@ -0,0 +1,10 @@
1
+ // Re-export barrel para compatibilidad con imports antiguos.
2
+ // Los tipos ahora viven dentro de DatePicker.tsx.
3
+ export type {
4
+ LabelPosition,
5
+ DatePickerSize,
6
+ BaseDatePickerProps,
7
+ RHFDatePickerProps,
8
+ ControlledDatePickerProps,
9
+ DatePickerProps,
10
+ } from './DatePicker';
@@ -0,0 +1,9 @@
1
+ export { DatePicker, default } from './DatePicker';
2
+ export type {
3
+ DatePickerProps,
4
+ BaseDatePickerProps,
5
+ RHFDatePickerProps,
6
+ ControlledDatePickerProps,
7
+ LabelPosition,
8
+ DatePickerSize,
9
+ } from './DatePicker.types';
@@ -0,0 +1,191 @@
1
+ export const BasicDateRangePickerDefinition = `
2
+ import React, { useState } from 'react';
3
+ import { DateRangePicker } from './DateRangePicker'; // Ajusta la ruta si es necesario
4
+ import dayjs from 'dayjs';
5
+ import { Box, Typography } from '@mui/material';
6
+
7
+ export const BasicDateRangePickerExample = () => {
8
+ const [startDate, setStartDate] = useState(dayjs('2023-01-01'));
9
+ const [endDate, setEndDate] = useState(dayjs('2023-01-31'));
10
+
11
+ const handleDateRangeChange = (start, end) => {
12
+ setStartDate(start);
13
+ setEndDate(end);
14
+ };
15
+
16
+ return (
17
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
18
+ <DateRangePicker
19
+ label="Seleccionar Rango"
20
+ startDate={startDate}
21
+ endDate={endDate}
22
+ onDateRangeChange={handleDateRangeChange}
23
+ />
24
+ <Typography sx={{ mt: 2 }}>
25
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
26
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
27
+ </Typography>
28
+ </Box>
29
+ );
30
+ };
31
+ `;
32
+
33
+ export const DateRangePickerWithMinMaxDefinition = `
34
+ import React, { useState } from 'react';
35
+ import { DateRangePicker } from './DateRangePicker'; // Ajusta la ruta si es necesario
36
+ import dayjs from 'dayjs';
37
+ import { Box, Typography } from '@mui/material';
38
+
39
+ export const DateRangePickerWithMinMaxExample = () => {
40
+ const [startDate, setStartDate] = useState(dayjs('2023-06-10'));
41
+ const [endDate, setEndDate] = useState(dayjs('2023-06-20'));
42
+ const minDate = dayjs('2023-06-01');
43
+ const maxDate = dayjs('2023-06-30');
44
+
45
+ const handleDateRangeChange = (start, end) => {
46
+ setStartDate(start);
47
+ setEndDate(end);
48
+ };
49
+
50
+ return (
51
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
52
+ <DateRangePicker
53
+ label="Rango de Junio"
54
+ startDate={startDate}
55
+ endDate={endDate}
56
+ onDateRangeChange={handleDateRangeChange}
57
+ minDate={minDate}
58
+ maxDate={maxDate}
59
+ />
60
+ <Typography sx={{ mt: 2 }}>
61
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
62
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
63
+ </Typography>
64
+ <Typography variant="caption" color="text.secondary">
65
+ (Rango permitido: \${minDate.format('YYYY-MM-DD')} a \${maxDate.format('YYYY-MM-DD')})
66
+ </Typography>
67
+ </Box>
68
+ );
69
+ };
70
+ `;
71
+
72
+ export const DateRangePickerDisabledDefinition = `
73
+ import React, { useState } from 'react';
74
+ import { DateRangePicker } from './DateRangePicker'; // Ajusta la ruta si es necesario
75
+ import dayjs from 'dayjs';
76
+ import { Box, Typography } from '@mui/material';
77
+
78
+ export const DateRangePickerDisabledExample = () => {
79
+ const [startDate, setStartDate] = useState(dayjs('2023-01-01'));
80
+ const [endDate, setEndDate] = useState(dayjs('2023-01-31'));
81
+
82
+ return (
83
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
84
+ <DateRangePicker
85
+ label="Rango Deshabilitado"
86
+ startDate={startDate}
87
+ endDate={endDate}
88
+ onDateRangeChange={() => {}}
89
+ disabled
90
+ />
91
+ <Typography sx={{ mt: 2 }}>
92
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
93
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
94
+ </Typography>
95
+ </Box>
96
+ );
97
+ };
98
+ `;
99
+
100
+ export const DateRangePickerReadOnlyDefinition = `
101
+ import React, { useState } from 'react';
102
+ import { DateRangePicker } from './DateRangePicker'; // Ajusta la ruta si es necesario
103
+ import dayjs from 'dayjs';
104
+ import { Box, Typography } from '@mui/material';
105
+
106
+ export const DateRangePickerReadOnlyExample = () => {
107
+ const [startDate, setStartDate] = useState(dayjs('2024-07-01'));
108
+ const [endDate, setEndDate] = useState(dayjs('2024-07-15'));
109
+
110
+ return (
111
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
112
+ <DateRangePicker
113
+ label="Rango Solo Lectura"
114
+ startDate={startDate}
115
+ endDate={endDate}
116
+ onDateRangeChange={() => {}}
117
+ readOnly
118
+ />
119
+ <Typography sx={{ mt: 2 }}>
120
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
121
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
122
+ </Typography>
123
+ </Box>
124
+ );
125
+ };
126
+ `;
127
+
128
+ export const DateRangePickerWithInitialNullDefinition = `
129
+ import React, { useState } from 'react';
130
+ import { DateRangePicker } from './DateRangePicker'; // Ajusta la ruta si es necesario
131
+ import dayjs from 'dayjs';
132
+ import { Box, Typography } from '@mui/material';
133
+
134
+ export const DateRangePickerWithInitialNullExample = () => {
135
+ const [startDate, setStartDate] = useState(null);
136
+ const [endDate, setEndDate] = useState(null);
137
+
138
+ const handleDateRangeChange = (start, end) => {
139
+ setStartDate(start);
140
+ setEndDate(end);
141
+ };
142
+
143
+ return (
144
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
145
+ <DateRangePicker
146
+ label="Rango Sin Selección Inicial"
147
+ startDate={startDate}
148
+ endDate={endDate}
149
+ onDateRangeChange={handleDateRangeChange}
150
+ />
151
+ <Typography sx={{ mt: 2 }}>
152
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
153
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
154
+ </Typography>
155
+ </Box>
156
+ );
157
+ };
158
+ `;
159
+
160
+ export const DateRangePickerWithSizeDefinition = `
161
+ import React, { useState } from 'react';
162
+ import { DateRangePicker } from './DateRangePicker'; // Adjust path if necessary
163
+ import dayjs from 'dayjs';
164
+ import { Box, Typography } from '@mui/material';
165
+
166
+ export const DateRangePickerWithSizeExample = () => {
167
+ const [startDate, setStartDate] = useState(dayjs('2023-01-01'));
168
+ const [endDate, setEndDate] = useState(dayjs('2023-01-31'));
169
+
170
+ const handleDateRangeChange = (start, end) => {
171
+ setStartDate(start);
172
+ setEndDate(end);
173
+ };
174
+
175
+ return (
176
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
177
+ <DateRangePicker
178
+ label="Rango de Fechas (Tamaño Pequeño)"
179
+ startDate={startDate}
180
+ endDate={endDate}
181
+ onDateRangeChange={handleDateRangeChange}
182
+ slotProps={{ textField: { size: 'small' } }}
183
+ />
184
+ <Typography sx={{ mt: 2 }}>
185
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
186
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
187
+ </Typography>
188
+ </Box>
189
+ );
190
+ };
191
+ `;
@@ -0,0 +1,252 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React, { useState } from 'react';
3
+ import { Box, Typography } from '@mui/material';
4
+ import { Dayjs } from 'dayjs';
5
+ import dayjs from 'dayjs';
6
+
7
+ import DateRangePicker from "./DateRangePicker";
8
+ import { BasicDateRangePickerDefinition, DateRangePickerWithMinMaxDefinition, DateRangePickerDisabledDefinition, DateRangePickerReadOnlyDefinition, DateRangePickerWithInitialNullDefinition, DateRangePickerWithSizeDefinition } from './DateRangePicker.definitions';
9
+
10
+ // =============================================================================
11
+ const meta: Meta<typeof DateRangePicker> = {
12
+ title: 'Components/DateRangePicker',
13
+ component: DateRangePicker,
14
+ tags: ['autodocs'],
15
+ parameters: {
16
+ layout: 'centered',
17
+ docs: {
18
+ description: {
19
+ component: 'Un componente `DateRangePicker` personalizado que permite seleccionar un rango de fechas con un solo campo de entrada (visualmente dos inputs interconectados) y gestiona las fechas de inicio y fin.',
20
+ },
21
+ },
22
+ },
23
+ argTypes: {
24
+ label: { control: 'text', description: 'Etiqueta para el campo de entrada del rango de fechas.' },
25
+ startDate: { control: 'object', description: 'La fecha de inicio del rango.', type: { name: 'object', required: false, value: {} } },
26
+ endDate: { control: 'object', description: 'La fecha de fin del rango.', type: { name: 'object', required: false, value: {} } },
27
+ onDateRangeChange: { action: 'dateRangeChanged', description: 'Callback que se dispara cuando el rango de fechas cambia.' },
28
+ minDate: { control: 'object', description: 'La fecha mínima permitida para cualquier fecha en el rango.' },
29
+ maxDate: { control: 'object', description: 'La fecha máxima permitida para cualquier fecha en el rango.' },
30
+ disabled: { control: 'boolean', description: 'Si es verdadero, el selector de rango estará deshabilitado.' },
31
+ readOnly: { control: 'boolean', description: 'Si es verdadero, el selector de rango estará en modo de solo lectura.' },
32
+ slotProps: { control: 'object', description: 'Propiedades pasadas a los slots internos del DateRangePicker (e.g., `textField`).' },
33
+ },
34
+ };
35
+
36
+ export default meta;
37
+ type Story = StoryObj<typeof DateRangePicker>;
38
+
39
+ // =============================================================================
40
+ // Historias
41
+ // =============================================================================
42
+
43
+ export const BasicDateRangePicker: Story = {
44
+ render: () => {
45
+ const [startDate, setStartDate] = useState<Dayjs | null>(dayjs('2023-01-01'));
46
+ const [endDate, setEndDate] = useState<Dayjs | null>(dayjs('2023-01-31'));
47
+
48
+ const handleDateRangeChange = (start: Dayjs | null, end: Dayjs | null) => {
49
+ setStartDate(start);
50
+ setEndDate(end);
51
+ };
52
+
53
+ return (
54
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
55
+ <DateRangePicker
56
+ label="Seleccionar Rango"
57
+ startDate={startDate}
58
+ endDate={endDate}
59
+ onDateRangeChange={handleDateRangeChange}
60
+ />
61
+ <Typography sx={{ mt: 2 }}>
62
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
63
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
64
+ </Typography>
65
+ </Box>
66
+ );
67
+ },
68
+ parameters: {
69
+ docs: {
70
+ description: {
71
+ story: "Un `DateRangePicker` básico que permite seleccionar un rango de fechas."
72
+ },
73
+ source: { code: BasicDateRangePickerDefinition.trim() }
74
+ }
75
+ }
76
+ };
77
+
78
+ export const DateRangePickerWithMinMax: Story = {
79
+ render: () => {
80
+ const [startDate, setStartDate] = useState<Dayjs | null>(dayjs('2023-06-10'));
81
+ const [endDate, setEndDate] = useState<Dayjs | null>(dayjs('2023-06-20'));
82
+ const minDate = dayjs('2023-06-01');
83
+ const maxDate = dayjs('2023-06-30');
84
+
85
+ const handleDateRangeChange = (start: Dayjs | null, end: Dayjs | null) => {
86
+ setStartDate(start);
87
+ setEndDate(end);
88
+ };
89
+
90
+ return (
91
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
92
+ <DateRangePicker
93
+ label="Rango de Junio"
94
+ startDate={startDate}
95
+ endDate={endDate}
96
+ onDateRangeChange={handleDateRangeChange}
97
+ minDate={minDate}
98
+ maxDate={maxDate}
99
+ />
100
+ <Typography sx={{ mt: 2 }}>
101
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
102
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
103
+ </Typography>
104
+ <Typography variant="caption" color="text.secondary">
105
+ (Rango permitido: ${minDate.format('YYYY-MM-DD')} a ${maxDate.format('YYYY-MM-DD')})
106
+ </Typography>
107
+ </Box>
108
+ );
109
+ },
110
+ parameters: {
111
+ docs: {
112
+ description: {
113
+ story: "Muestra un `DateRangePicker` con fechas mínimas y máximas permitidas para el rango completo."
114
+ },
115
+ source: { code: DateRangePickerWithMinMaxDefinition.trim() }
116
+ }
117
+ }
118
+ };
119
+
120
+ export const DateRangePickerDisabled: Story = {
121
+ render: () => {
122
+ const [startDate, setStartDate] = useState<Dayjs | null>(dayjs('2023-01-01'));
123
+ const [endDate, setEndDate] = useState<Dayjs | null>(dayjs('2023-01-31'));
124
+
125
+ return (
126
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
127
+ <DateRangePicker
128
+ label="Rango Deshabilitado"
129
+ startDate={startDate}
130
+ endDate={endDate}
131
+ onDateRangeChange={() => {}}
132
+ disabled
133
+ />
134
+ <Typography sx={{ mt: 2 }}>
135
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
136
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
137
+ </Typography>
138
+ </Box>
139
+ );
140
+ },
141
+ parameters: {
142
+ docs: {
143
+ description: {
144
+ story: "Demuestra un `DateRangePicker` en estado deshabilitado."
145
+ },
146
+ source: { code: DateRangePickerDisabledDefinition.trim() }
147
+ }
148
+ }
149
+ };
150
+
151
+ export const DateRangePickerReadOnly: Story = {
152
+ render: () => {
153
+ const [startDate, setStartDate] = useState<Dayjs | null>(dayjs('2024-07-01'));
154
+ const [endDate, setEndDate] = useState<Dayjs | null>(dayjs('2024-07-15'));
155
+
156
+ return (
157
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
158
+ <DateRangePicker
159
+ label="Rango Solo Lectura"
160
+ startDate={startDate}
161
+ endDate={endDate}
162
+ onDateRangeChange={() => {}}
163
+ readOnly
164
+ />
165
+ <Typography sx={{ mt: 2 }}>
166
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
167
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
168
+ </Typography>
169
+ </Box>
170
+ );
171
+ },
172
+ parameters: {
173
+ docs: {
174
+ description: {
175
+ story: "Muestra el `DateRangePicker` en modo de solo lectura. El usuario puede ver el rango pero no modificarlo."
176
+ },
177
+ source: { code: DateRangePickerReadOnlyDefinition.trim() }
178
+ }
179
+ }
180
+ };
181
+
182
+ export const DateRangePickerWithInitialNull: Story = {
183
+ render: () => {
184
+ const [startDate, setStartDate] = useState<Dayjs | null>(null);
185
+ const [endDate, setEndDate] = useState<Dayjs | null>(null);
186
+
187
+ const handleDateRangeChange = (start: Dayjs | null, end: Dayjs | null) => {
188
+ setStartDate(start);
189
+ setEndDate(end);
190
+ };
191
+
192
+ return (
193
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
194
+ <DateRangePicker
195
+ label="Rango Sin Selección Inicial"
196
+ startDate={startDate}
197
+ endDate={endDate}
198
+ onDateRangeChange={handleDateRangeChange}
199
+ />
200
+ <Typography sx={{ mt: 2 }}>
201
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
202
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
203
+ </Typography>
204
+ </Box>
205
+ );
206
+ },
207
+ parameters: {
208
+ docs: {
209
+ description: {
210
+ story: "Muestra un `DateRangePicker` sin fechas de inicio o fin seleccionadas inicialmente."
211
+ },
212
+ source: { code: DateRangePickerWithInitialNullDefinition.trim() }
213
+ }
214
+ }
215
+ };
216
+
217
+ export const DateRangePickerWithSize: Story = {
218
+ render: () => {
219
+ const [startDate, setStartDate] = useState<Dayjs | null>(dayjs('2023-01-01'));
220
+ const [endDate, setEndDate] = useState<Dayjs | null>(dayjs('2023-01-31'));
221
+
222
+ const handleDateRangeChange = (start: Dayjs | null, end: Dayjs | null) => {
223
+ setStartDate(start);
224
+ setEndDate(end);
225
+ };
226
+
227
+ return (
228
+ <Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
229
+ <DateRangePicker
230
+ label="Rango de Fechas (Tamaño Pequeño)"
231
+ startDate={startDate}
232
+ endDate={endDate}
233
+ onDateRangeChange={handleDateRangeChange}
234
+ slotProps={{ textField: { size: 'small' } }} // Aplica el tamaño 'small' a los TextFields internos
235
+ />
236
+ <Typography sx={{ mt: 2 }}>
237
+ Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
238
+ Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
239
+ </Typography>
240
+ </Box>
241
+ );
242
+ },
243
+ parameters: {
244
+ docs: {
245
+ description: {
246
+ story: "Demuestra cómo aplicar diferentes tamaños (`small` o `medium`) a los campos de entrada del `DateRangePicker`."
247
+ },
248
+ source: { code: DateRangePickerWithSizeDefinition.trim() }
249
+ }
250
+ }
251
+ };
252
+