@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.
- package/.dockerignore +8 -0
- package/.github/workflows/publish.yml +107 -0
- package/.prettierrc +3 -0
- package/.storybook/main.ts +19 -0
- package/.storybook/preview.ts +14 -0
- package/.storybook/vitest.setup.ts +9 -0
- package/Dockerfile +37 -0
- package/build.js +102 -0
- package/chromatic.config.json +5 -0
- package/cleanDirectories.js +40 -0
- package/dist/README.md +243 -0
- package/dist/components/Icon/Icon.js +1 -1
- package/dist/components/Table/Table.js +1 -1
- package/dist/index.cjs +24 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -1
- package/dist/mui.d.ts +1 -0
- package/dist/package.json +197 -0
- package/package.json +4 -32
- package/rollup.config.cjs +87 -0
- package/src/components/ActionMenu/ActionMenu.stories.tsx +230 -0
- package/src/components/ActionMenu/ActionMenu.tsx +174 -0
- package/src/components/ActionMenu/index.ts +2 -0
- package/src/components/AppBar/AppBar.stories.tsx +272 -0
- package/src/components/AppBar/AppBar.sx.ts +32 -0
- package/src/components/AppBar/AppBar.tsx +123 -0
- package/src/components/AppBar/AppBarBrand.tsx +120 -0
- package/src/components/AppBar/AppBarContext.ts +25 -0
- package/src/components/AppBar/AppBarMenuToggle.tsx +90 -0
- package/src/components/AppBar/AppBarUserMenu.tsx +217 -0
- package/src/components/AppBar/index.ts +25 -0
- package/src/components/Autocomplete/Autocomplete.definitions.ts +477 -0
- package/src/components/Autocomplete/Autocomplete.helpers.ts +60 -0
- package/src/components/Autocomplete/Autocomplete.stories.tsx +748 -0
- package/src/components/Autocomplete/Autocomplete.sx.ts +30 -0
- package/src/components/Autocomplete/Autocomplete.tsx +361 -0
- package/src/components/Autocomplete/Autocomplete.types.ts +13 -0
- package/src/components/Autocomplete/_parts/AutocompleteChips.tsx +55 -0
- package/src/components/Autocomplete/_parts/AutocompleteLoader.tsx +17 -0
- package/src/components/Autocomplete/_parts/AutocompleteOption.tsx +31 -0
- package/src/components/Autocomplete/index.ts +12 -0
- package/src/components/Avatar/Avatar.definitions.ts +162 -0
- package/src/components/Avatar/Avatar.stories.tsx +258 -0
- package/src/components/Avatar/Avatar.tsx +206 -0
- package/src/components/Avatar/index.ts +1 -0
- package/src/components/Button/Button.definition.ts +97 -0
- package/src/components/Button/Button.stories.tsx +285 -0
- package/src/components/Button/Button.tsx +67 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Card/Card.definition.ts +5 -0
- package/src/components/Card/Card.stories.tsx +221 -0
- package/src/components/Card/Card.sx.ts +104 -0
- package/src/components/Card/Card.tsx +200 -0
- package/src/components/Card/index.ts +9 -0
- package/src/components/Chip/Chip.definitions.ts +167 -0
- package/src/components/Chip/Chip.stories.tsx +265 -0
- package/src/components/Chip/Chip.tsx +61 -0
- package/src/components/Chip/index.ts +1 -0
- package/src/components/Column/Column.tsx +29 -0
- package/src/components/Column/index.ts +1 -0
- package/src/components/DatePicker/DatePicker.definitions.ts +228 -0
- package/src/components/DatePicker/DatePicker.helpers.ts +24 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +309 -0
- package/src/components/DatePicker/DatePicker.sx.ts +33 -0
- package/src/components/DatePicker/DatePicker.tsx +189 -0
- package/src/components/DatePicker/DatePicker.types.ts +10 -0
- package/src/components/DatePicker/index.ts +9 -0
- package/src/components/DateRangePicker/DateRangePicker.definitions.ts +191 -0
- package/src/components/DateRangePicker/DateRangePicker.stories.tsx +252 -0
- package/src/components/DateRangePicker/DateRangePicker.tsx +56 -0
- package/src/components/DateRangePicker/index.ts +1 -0
- package/src/components/DateTimePicker/DateTimePicker.definitions.ts +256 -0
- package/src/components/DateTimePicker/DateTimePicker.helpers.ts +38 -0
- package/src/components/DateTimePicker/DateTimePicker.stories.tsx +418 -0
- package/src/components/DateTimePicker/DateTimePicker.sx.ts +30 -0
- package/src/components/DateTimePicker/DateTimePicker.tsx +225 -0
- package/src/components/DateTimePicker/DateTimePicker.types.ts +10 -0
- package/src/components/DateTimePicker/index.ts +9 -0
- package/src/components/Drawer/Drawer.stories.tsx +270 -0
- package/src/components/Drawer/Drawer.sx.ts +106 -0
- package/src/components/Drawer/Drawer.tsx +214 -0
- package/src/components/Drawer/DrawerContext.ts +26 -0
- package/src/components/Drawer/DrawerItem.tsx +110 -0
- package/src/components/Drawer/index.ts +10 -0
- package/src/components/Flyout/Flyout.stories.tsx +282 -0
- package/src/components/Flyout/Flyout.tsx +122 -0
- package/src/components/Flyout/index.ts +1 -0
- package/src/components/Gallery/Gallery.definition.tsx +37 -0
- package/src/components/Gallery/Gallery.stories.tsx +82 -0
- package/src/components/Gallery/Gallery.tsx +118 -0
- package/src/components/Gallery/GalleryLightbox.tsx +170 -0
- package/src/components/Gallery/GalleryMain.tsx +84 -0
- package/src/components/Gallery/GalleryThumbnails.tsx +106 -0
- package/src/components/Gallery/index.ts +1 -0
- package/src/components/Icon/Icon.stories.tsx +121 -0
- package/src/components/Icon/Icon.tsx +175 -0
- package/src/components/Icon/index.ts +2 -0
- package/src/components/Input/Input.definitions.ts +324 -0
- package/src/components/Input/Input.helpers.ts +49 -0
- package/src/components/Input/Input.stories.tsx +499 -0
- package/src/components/Input/Input.sx.ts +42 -0
- package/src/components/Input/Input.tsx +141 -0
- package/src/components/Input/Input.types.ts +10 -0
- package/src/components/Input/index.ts +9 -0
- package/src/components/InputGroup/InputGroup.definitions.ts +158 -0
- package/src/components/InputGroup/InputGroup.stories.tsx +267 -0
- package/src/components/InputGroup/InputGroup.tsx +179 -0
- package/src/components/InputGroup/index.ts +1 -0
- package/src/components/MenuButton/MenuButton.stories.tsx +197 -0
- package/src/components/MenuButton/MenuButton.tsx +100 -0
- package/src/components/MenuButton/index.ts +1 -0
- package/src/components/Modal/Modal.stories.tsx +721 -0
- package/src/components/Modal/Modal.tsx +355 -0
- package/src/components/Modal/ModalBody.tsx +16 -0
- package/src/components/Modal/ModalFooter.tsx +71 -0
- package/src/components/Modal/ModalHeader.tsx +18 -0
- package/src/components/Modal/index.ts +6 -0
- package/src/components/PageLoader/PageLoader.stories.tsx +217 -0
- package/src/components/PageLoader/PageLoader.tsx +96 -0
- package/src/components/PageLoader/index.ts +2 -0
- package/src/components/ScrollTopButton/ScrollTopButton.stories.tsx +158 -0
- package/src/components/ScrollTopButton/ScrollTopButton.tsx +135 -0
- package/src/components/ScrollTopButton/index.ts +8 -0
- package/src/components/ScrollTopButton/scrollToTop.ts +37 -0
- package/src/components/Select/Select.definitions.ts +602 -0
- package/src/components/Select/Select.helpers.ts +71 -0
- package/src/components/Select/Select.stories.tsx +687 -0
- package/src/components/Select/Select.sx.ts +14 -0
- package/src/components/Select/Select.tsx +429 -0
- package/src/components/Select/Select.types.ts +15 -0
- package/src/components/Select/_parts/SelectMenuItem.tsx +40 -0
- package/src/components/Select/_parts/SelectSearchHeader.tsx +51 -0
- package/src/components/Select/_parts/SelectValue.tsx +96 -0
- package/src/components/Select/index.ts +14 -0
- package/src/components/Stat/Stat.stories.tsx +85 -0
- package/src/components/Stat/Stat.tsx +117 -0
- package/src/components/Stat/index.ts +2 -0
- package/src/components/StatusMessage/StatusMessage.stories.tsx +130 -0
- package/src/components/StatusMessage/StatusMessage.tsx +162 -0
- package/src/components/StatusMessage/index.ts +2 -0
- package/src/components/Stepper/Step.tsx +21 -0
- package/src/components/Stepper/Stepper.definition.ts +75 -0
- package/src/components/Stepper/Stepper.stories.tsx +122 -0
- package/src/components/Stepper/Stepper.tsx +75 -0
- package/src/components/Stepper/index.ts +2 -0
- package/src/components/Table/EmptyTable.png +0 -0
- package/src/components/Table/Table.definition.ts +580 -0
- package/src/components/Table/Table.stories.tsx +853 -0
- package/src/components/Table/Table.tsx +495 -0
- package/src/components/Table/data.ts +134 -0
- package/src/components/Table/exportsUtils.ts +195 -0
- package/src/components/Table/index.ts +3 -0
- package/src/components/Table/types.ts +34 -0
- package/src/components/Tabs/Tab.definition.ts +53 -0
- package/src/components/Tabs/Tab.tsx +19 -0
- package/src/components/Tabs/Tabs.stories.tsx +118 -0
- package/src/components/Tabs/Tabs.tsx +99 -0
- package/src/components/Tabs/_tabUtils.tsx +4 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Timeline/Timeline.definition.ts +43 -0
- package/src/components/Timeline/Timeline.stories.tsx +108 -0
- package/src/components/Timeline/Timeline.tsx +49 -0
- package/src/components/Timeline/TimelineItem.tsx +31 -0
- package/src/components/Timeline/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +129 -0
- package/src/components/Tooltip/Tooltip.tsx +58 -0
- package/src/components/Tooltip/index.ts +1 -0
- package/src/components/_shared/formField.sx.ts +118 -0
- package/src/components/_shared/resolvePreset.ts +35 -0
- package/src/hooks/ClipBoard/ClipBoard.stories.tsx +168 -0
- package/src/hooks/ClipBoard/ClipBoard.tsx +131 -0
- package/src/hooks/ClipBoard/ClipboardUnifiedDemo.tsx +111 -0
- package/src/hooks/ClipBoard/index.ts +1 -0
- package/src/hooks/Wizard/Wizard.stories.tsx +301 -0
- package/src/hooks/Wizard/WizardContext.tsx +166 -0
- package/src/hooks/Wizard/index.ts +6 -0
- package/src/hooks/Wizard/useWizard.ts +13 -0
- package/src/index.ts +17 -0
- package/src/mui.ts +54 -0
- package/src/styles.css +3 -0
- package/src/theme/componentStyles.ts +47 -0
- package/src/theme/tokens.ts +43 -0
- package/tailwind.config.js +10 -0
- package/tsconfig.json +48 -0
- package/tsup.config.js +41 -0
- package/vite.config.js +132 -0
- package/vitest.config.ts +35 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Chip } from './Chip';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// -----------------------------------------------------------------------------
|
|
2
|
+
// Componente Column: Define la estructura de una columna en la tabla.
|
|
3
|
+
// Este componente NO renderiza nada directamente, solo pasa sus props al componente Table.
|
|
4
|
+
// -----------------------------------------------------------------------------
|
|
5
|
+
// Tipo auxiliar para 'field'.
|
|
6
|
+
// Define si 'field' es una sola clave (keyof T) o un array de claves (Array<keyof T>).
|
|
7
|
+
type FieldName<T> = keyof T | Array<keyof T>;
|
|
8
|
+
|
|
9
|
+
export interface ColumnProps<T> {
|
|
10
|
+
name: string; // Nombre a mostrar en el encabezado de la columna
|
|
11
|
+
field: FieldName<T>; // Define el campo o campos a usar de los datos
|
|
12
|
+
// La prop 'children' ahora recibe 'Partial<T>'.
|
|
13
|
+
// Esto permite a TypeScript inferir los tipos de las propiedades desestructuradas
|
|
14
|
+
// como 'avatar', 'nombre', etc., basándose en la interfaz genérica 'T' de tu data.
|
|
15
|
+
width?: string;
|
|
16
|
+
children: (fieldData: Partial<T>) => React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// El componente Column no renderiza nada directamente en el DOM.
|
|
20
|
+
// Su propósito es actuar como un contenedor de configuración para el componente Table.
|
|
21
|
+
export function Column<T>(props: ColumnProps<T>): React.ReactNode {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Esto es crucial para que el componente Table pueda identificar a nuestros componentes Column
|
|
26
|
+
// entre sus hijos, utilizando (child.type as any).displayName === 'Column'.
|
|
27
|
+
Column.displayName = 'Column';
|
|
28
|
+
|
|
29
|
+
export default Column;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Column } from './Column'
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// DatePicker.definitions.ts
|
|
2
|
+
|
|
3
|
+
export const BasicDatePickerDefinition = `
|
|
4
|
+
import React, { useState } from 'react';
|
|
5
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
6
|
+
import dayjs from 'dayjs';
|
|
7
|
+
import { Box, Typography } from '@mui/material';
|
|
8
|
+
|
|
9
|
+
export const BasicDatePickerExample = () => {
|
|
10
|
+
const [selectedDate, setSelectedDate] = useState(dayjs());
|
|
11
|
+
return (
|
|
12
|
+
<Box sx={{ width: 300 }}>
|
|
13
|
+
<DatePicker
|
|
14
|
+
label="Seleccionar Fecha"
|
|
15
|
+
selectedDate={selectedDate}
|
|
16
|
+
onDateChange={setSelectedDate}
|
|
17
|
+
/>
|
|
18
|
+
<Typography sx={{ mt: 2 }}>
|
|
19
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
20
|
+
</Typography>
|
|
21
|
+
</Box>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
export const DatePickerWithMinMaxDefinition = `
|
|
27
|
+
import React, { useState } from 'react';
|
|
28
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
29
|
+
import dayjs from 'dayjs';
|
|
30
|
+
import { Box, Typography } from '@mui/material';
|
|
31
|
+
|
|
32
|
+
export const DatePickerWithMinMaxExample = () => {
|
|
33
|
+
const [selectedDate, setSelectedDate] = useState(dayjs('2023-06-15'));
|
|
34
|
+
const minDate = dayjs('2023-06-01');
|
|
35
|
+
const maxDate = dayjs('2023-06-30');
|
|
36
|
+
return (
|
|
37
|
+
<Box sx={{ width: 300 }}>
|
|
38
|
+
<DatePicker
|
|
39
|
+
label="Fecha en Junio"
|
|
40
|
+
selectedDate={selectedDate}
|
|
41
|
+
onDateChange={setSelectedDate}
|
|
42
|
+
minDate={minDate}
|
|
43
|
+
maxDate={maxDate}
|
|
44
|
+
/>
|
|
45
|
+
<Typography sx={{ mt: 2 }}>
|
|
46
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
47
|
+
</Typography>
|
|
48
|
+
<Typography variant="caption" color="text.secondary">
|
|
49
|
+
(Rango: \${minDate.format('YYYY-MM-DD')} a \${maxDate.format('YYYY-MM-DD')})
|
|
50
|
+
</Typography>
|
|
51
|
+
</Box>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
export const DateRangePickerDefinition = `
|
|
57
|
+
import React, { useState } from 'react';
|
|
58
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
59
|
+
import dayjs from 'dayjs';
|
|
60
|
+
import { Box, Typography } from '@mui/material';
|
|
61
|
+
|
|
62
|
+
export const DateRangePickerExample = () => {
|
|
63
|
+
const [startDate, setStartDate] = useState(dayjs('2023-01-01'));
|
|
64
|
+
const [endDate, setEndDate] = useState(dayjs('2023-01-31'));
|
|
65
|
+
|
|
66
|
+
const handleStartDateChange = (date) => {
|
|
67
|
+
setStartDate(date);
|
|
68
|
+
if (date && endDate && date.isAfter(endDate)) {
|
|
69
|
+
setEndDate(date);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const handleEndDateChange = (date) => {
|
|
74
|
+
setEndDate(date);
|
|
75
|
+
if (date && startDate && date.isBefore(startDate)) {
|
|
76
|
+
setStartDate(date);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<Box sx={{ display: 'flex', gap: 3, flexDirection: 'column' }}>
|
|
82
|
+
<DatePicker
|
|
83
|
+
label="Fecha de Inicio"
|
|
84
|
+
selectedDate={startDate}
|
|
85
|
+
onDateChange={handleStartDateChange}
|
|
86
|
+
maxDate={endDate || undefined}
|
|
87
|
+
/>
|
|
88
|
+
<DatePicker
|
|
89
|
+
label="Fecha de Fin"
|
|
90
|
+
selectedDate={endDate}
|
|
91
|
+
onDateChange={handleEndDateChange}
|
|
92
|
+
minDate={startDate || undefined}
|
|
93
|
+
/>
|
|
94
|
+
<Typography>
|
|
95
|
+
Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
|
|
96
|
+
Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
|
|
97
|
+
</Typography>
|
|
98
|
+
</Box>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
export const DatePickerWithErrorDefinition = `
|
|
104
|
+
import React, { useState } from 'react';
|
|
105
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
106
|
+
import dayjs from 'dayjs';
|
|
107
|
+
import { Box, Typography } from '@mui/material';
|
|
108
|
+
|
|
109
|
+
export const DatePickerWithErrorExample = () => {
|
|
110
|
+
const [selectedDate, setSelectedDate] = useState(dayjs('2023-01-01'));
|
|
111
|
+
// Intentamos establecer una fecha fuera de un rango muy restringido para forzar un error
|
|
112
|
+
const minDate = dayjs('2023-01-05');
|
|
113
|
+
const maxDate = dayjs('2023-01-10');
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<Box sx={{ width: 300 }}>
|
|
117
|
+
<DatePicker
|
|
118
|
+
label="Fecha (con error de rango)"
|
|
119
|
+
selectedDate={selectedDate}
|
|
120
|
+
onDateChange={setSelectedDate}
|
|
121
|
+
minDate={minDate}
|
|
122
|
+
maxDate={maxDate}
|
|
123
|
+
/>
|
|
124
|
+
<Typography sx={{ mt: 2 }}>
|
|
125
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
126
|
+
</Typography>
|
|
127
|
+
<Typography variant="caption" color="error">
|
|
128
|
+
(Intenta seleccionar una fecha fuera de \${minDate.format('YYYY-MM-DD')} - \${maxDate.format('YYYY-MM-DD')})
|
|
129
|
+
</Typography>
|
|
130
|
+
</Box>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
export const DatePickerSmallSizeDefinition = `
|
|
136
|
+
import React, { useState } from 'react';
|
|
137
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
138
|
+
import dayjs from 'dayjs';
|
|
139
|
+
import { Box, Typography } from '@mui/material';
|
|
140
|
+
|
|
141
|
+
export const DatePickerSmallSizeExample = () => {
|
|
142
|
+
const [selectedDate, setSelectedDate] = useState(dayjs());
|
|
143
|
+
return (
|
|
144
|
+
<Box sx={{ width: 250 }}>
|
|
145
|
+
<DatePicker
|
|
146
|
+
label="Fecha (Pequeño)"
|
|
147
|
+
selectedDate={selectedDate}
|
|
148
|
+
onDateChange={setSelectedDate}
|
|
149
|
+
slotProps={{ textField: { size: 'small' } }} // Prop para hacer el TextField pequeño
|
|
150
|
+
/>
|
|
151
|
+
<Typography sx={{ mt: 2 }}>
|
|
152
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
153
|
+
</Typography>
|
|
154
|
+
</Box>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
export const DatePickerDisabledDefinition = `
|
|
160
|
+
import React, { useState } from 'react';
|
|
161
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
162
|
+
import dayjs from 'dayjs';
|
|
163
|
+
import { Box, Typography } from '@mui/material';
|
|
164
|
+
|
|
165
|
+
export const DatePickerDisabledExample = () => {
|
|
166
|
+
const [selectedDate, setSelectedDate] = useState(dayjs());
|
|
167
|
+
return (
|
|
168
|
+
<Box sx={{ width: 300 }}>
|
|
169
|
+
<DatePicker
|
|
170
|
+
label="Fecha (Deshabilitado)"
|
|
171
|
+
selectedDate={selectedDate}
|
|
172
|
+
onDateChange={setSelectedDate}
|
|
173
|
+
disabled
|
|
174
|
+
/>
|
|
175
|
+
<Typography sx={{ mt: 2 }}>
|
|
176
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
177
|
+
</Typography>
|
|
178
|
+
</Box>
|
|
179
|
+
);
|
|
180
|
+
};
|
|
181
|
+
`;
|
|
182
|
+
|
|
183
|
+
export const DatePickerReadOnlyDefinition = `
|
|
184
|
+
import React, { useState } from 'react';
|
|
185
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
186
|
+
import dayjs from 'dayjs';
|
|
187
|
+
import { Box, Typography } from '@mui/material';
|
|
188
|
+
|
|
189
|
+
export const DatePickerReadOnlyDefinition = () => {
|
|
190
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs('2024-07-24'));
|
|
191
|
+
return (
|
|
192
|
+
<Box sx={{ width: 300 }}>
|
|
193
|
+
<DatePicker
|
|
194
|
+
label="Fecha (Solo Lectura)"
|
|
195
|
+
selectedDate={selectedDate}
|
|
196
|
+
onDateChange={() => {}} // No permite cambios
|
|
197
|
+
readOnly
|
|
198
|
+
/>
|
|
199
|
+
<Typography sx={{ mt: 2 }}>
|
|
200
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
201
|
+
</Typography>
|
|
202
|
+
</Box>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
`;
|
|
206
|
+
export const DatePickerEmptyWithMaskDefinition = `
|
|
207
|
+
import React, { useState } from 'react';
|
|
208
|
+
import { DatePicker } from '@soyfri/shared-library/DatePicker';
|
|
209
|
+
import { Dayjs } from 'dayjs';
|
|
210
|
+
import { Box, Typography } from '@mui/material';
|
|
211
|
+
|
|
212
|
+
export const DatePickerEmptyWithMaskExample = () => {
|
|
213
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(null);
|
|
214
|
+
return (
|
|
215
|
+
<Box sx={{ width: 300 }}>
|
|
216
|
+
<DatePicker
|
|
217
|
+
label="Fecha"
|
|
218
|
+
selectedDate={selectedDate}
|
|
219
|
+
onDateChange={setSelectedDate}
|
|
220
|
+
format="DD/MM/YY"
|
|
221
|
+
/>
|
|
222
|
+
<Typography sx={{ mt: 2 }} variant="caption" color="text.secondary">
|
|
223
|
+
Al estar vacío, el campo muestra la máscara del formato (DD/MM/AA).
|
|
224
|
+
</Typography>
|
|
225
|
+
</Box>
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
`;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DateValidationError } from '@mui/x-date-pickers/models';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Traduce el código de error del DatePicker de MUI X a un mensaje en español.
|
|
5
|
+
* Se usa internamente para poblar `helperText` cuando hay error de validación
|
|
6
|
+
* y el consumer no pasó un mensaje propio.
|
|
7
|
+
*/
|
|
8
|
+
export const getDateValidationMessage = (
|
|
9
|
+
error: DateValidationError | null,
|
|
10
|
+
): string => {
|
|
11
|
+
switch (error) {
|
|
12
|
+
case 'minDate':
|
|
13
|
+
case 'maxDate':
|
|
14
|
+
return 'Fecha fuera del rango permitido';
|
|
15
|
+
case 'invalidDate':
|
|
16
|
+
return 'Formato de fecha inválido';
|
|
17
|
+
case 'disableFuture':
|
|
18
|
+
return 'No se permiten fechas futuras';
|
|
19
|
+
case 'disablePast':
|
|
20
|
+
return 'No se permiten fechas pasadas';
|
|
21
|
+
default:
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import React, { useState, useMemo } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
Box,
|
|
6
|
+
Typography,
|
|
7
|
+
} from '@mui/material';
|
|
8
|
+
|
|
9
|
+
// Importar las definiciones de las historias
|
|
10
|
+
import {
|
|
11
|
+
BasicDatePickerDefinition,
|
|
12
|
+
DatePickerWithMinMaxDefinition,
|
|
13
|
+
DateRangePickerDefinition,
|
|
14
|
+
DatePickerWithErrorDefinition,
|
|
15
|
+
DatePickerSmallSizeDefinition,
|
|
16
|
+
DatePickerDisabledDefinition,
|
|
17
|
+
DatePickerReadOnlyDefinition,
|
|
18
|
+
DatePickerEmptyWithMaskDefinition,
|
|
19
|
+
} from './DatePicker.definitions'; // Mantener el nombre del archivo de definiciones como está
|
|
20
|
+
import DatePicker from './DatePicker';
|
|
21
|
+
import dayjs, { Dayjs } from 'dayjs';
|
|
22
|
+
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Definición de las meta-propiedades para Storybook
|
|
25
|
+
// =============================================================================
|
|
26
|
+
const meta: Meta<typeof DatePicker> = { // Renombrado a DatePicker
|
|
27
|
+
title: 'Components/DatePicker', // Renombrado en el título del Storybook
|
|
28
|
+
component: DatePicker, // Renombrado a DatePicker
|
|
29
|
+
tags: ['autodocs'],
|
|
30
|
+
parameters: {
|
|
31
|
+
layout: 'centered',
|
|
32
|
+
docs: {
|
|
33
|
+
description: {
|
|
34
|
+
component: 'Un componente `DatePicker` personalizado de Material UI que gestiona el estado de fecha, rangos y validación de errores.',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
argTypes: {
|
|
39
|
+
label: { control: 'text', description: 'Etiqueta para el selector de fecha.' },
|
|
40
|
+
selectedDate: { control: 'object', description: 'La fecha actualmente seleccionada.', type: { name: 'object', required: false, value: {} } },
|
|
41
|
+
onDateChange: { action: 'dateChanged', description: 'Callback que se dispara cuando la fecha cambia.' },
|
|
42
|
+
minDate: { control: 'object', description: 'La fecha mínima permitida.', type: { name: 'object', required: false, value: {} } },
|
|
43
|
+
maxDate: { control: 'object', description: 'La fecha máxima permitida.', type: { name: 'object', required: false, value: {} } },
|
|
44
|
+
disabled: { control: 'boolean', description: 'Si es verdadero, el selector de fecha estará deshabilitado.' },
|
|
45
|
+
readOnly: { control: 'boolean', description: 'Si es verdadero, el selector de fecha estará en modo de solo lectura.' },
|
|
46
|
+
slotProps: { control: 'object', description: 'Props pasadas a los slots internos del DatePicker, como `textField`.' },
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default meta;
|
|
51
|
+
type Story = StoryObj<typeof DatePicker>; // Renombrado a DatePicker
|
|
52
|
+
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// Historias
|
|
55
|
+
// =============================================================================
|
|
56
|
+
|
|
57
|
+
export const BasicDatePicker: Story = {
|
|
58
|
+
render: () => {
|
|
59
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs());
|
|
60
|
+
return (
|
|
61
|
+
<Box sx={{ width: 300 }}>
|
|
62
|
+
<DatePicker // Renombrado
|
|
63
|
+
label="Seleccionar Fecha"
|
|
64
|
+
selectedDate={selectedDate}
|
|
65
|
+
onDateChange={setSelectedDate}
|
|
66
|
+
/>
|
|
67
|
+
<Typography sx={{ mt: 2 }}>
|
|
68
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
69
|
+
</Typography>
|
|
70
|
+
</Box>
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
parameters: {
|
|
74
|
+
docs: {
|
|
75
|
+
description: {
|
|
76
|
+
story: "Un `DatePicker` básico con selección de una única fecha."
|
|
77
|
+
},
|
|
78
|
+
source: { code: BasicDatePickerDefinition.trim() }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const DatePickerEmptyWithMask: Story = {
|
|
84
|
+
render: () => {
|
|
85
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(null);
|
|
86
|
+
return (
|
|
87
|
+
<Box sx={{ width: 300 }}>
|
|
88
|
+
<DatePicker
|
|
89
|
+
label="Fecha"
|
|
90
|
+
selectedDate={selectedDate}
|
|
91
|
+
onDateChange={setSelectedDate}
|
|
92
|
+
format="DD/MM/YY"
|
|
93
|
+
/>
|
|
94
|
+
<Typography sx={{ mt: 2 }} variant="caption" color="text.secondary">
|
|
95
|
+
Al estar vacío, el campo muestra la máscara del formato (DD/MM/AA).
|
|
96
|
+
</Typography>
|
|
97
|
+
</Box>
|
|
98
|
+
);
|
|
99
|
+
},
|
|
100
|
+
parameters: {
|
|
101
|
+
docs: {
|
|
102
|
+
description: {
|
|
103
|
+
story:
|
|
104
|
+
"DatePicker vacío. Al no haber valor seleccionado, cada sección del campo muestra su placeholder según el `format` (por ejemplo `DD/MM/AA`), funcionando como máscara visual."
|
|
105
|
+
},
|
|
106
|
+
source: { code: DatePickerEmptyWithMaskDefinition.trim() }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const DatePickerWithMinMax: Story = {
|
|
112
|
+
render: () => {
|
|
113
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs('2023-06-15'));
|
|
114
|
+
const minDate = dayjs('2023-06-01');
|
|
115
|
+
const maxDate = dayjs('2023-06-30');
|
|
116
|
+
return (
|
|
117
|
+
<Box sx={{ width: 300 }}>
|
|
118
|
+
<DatePicker // Renombrado
|
|
119
|
+
label="Fecha en Junio (Rango)"
|
|
120
|
+
selectedDate={selectedDate}
|
|
121
|
+
onDateChange={setSelectedDate}
|
|
122
|
+
minDate={minDate}
|
|
123
|
+
maxDate={maxDate}
|
|
124
|
+
/>
|
|
125
|
+
<Typography sx={{ mt: 2 }}>
|
|
126
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
127
|
+
</Typography>
|
|
128
|
+
<Typography variant="caption" color="text.secondary">
|
|
129
|
+
(Rango: ${minDate.format('YYYY-MM-DD')} a ${maxDate.format('YYYY-MM-DD')})
|
|
130
|
+
</Typography>
|
|
131
|
+
</Box>
|
|
132
|
+
);
|
|
133
|
+
},
|
|
134
|
+
parameters: {
|
|
135
|
+
docs: {
|
|
136
|
+
description: {
|
|
137
|
+
story: "Muestra un `DatePicker` con fechas mínimas y máximas permitidas."
|
|
138
|
+
},
|
|
139
|
+
source: { code: DatePickerWithMinMaxDefinition.trim() }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const DateRangePicker: Story = {
|
|
145
|
+
render: () => {
|
|
146
|
+
const [startDate, setStartDate] = useState<Dayjs | null>(dayjs('2023-01-01'));
|
|
147
|
+
const [endDate, setEndDate] = useState<Dayjs | null>(dayjs('2023-01-31'));
|
|
148
|
+
|
|
149
|
+
const handleStartDateChange = (date: Dayjs | null) => {
|
|
150
|
+
setStartDate(date);
|
|
151
|
+
if (date && endDate && date.isAfter(endDate)) {
|
|
152
|
+
setEndDate(date);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const handleEndDateChange = (date: Dayjs | null) => {
|
|
157
|
+
setEndDate(date);
|
|
158
|
+
if (date && startDate && date.isBefore(startDate)) {
|
|
159
|
+
setStartDate(date);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Box sx={{ display: 'flex', gap: 3, flexDirection: 'column', width: 300 }}>
|
|
165
|
+
<DatePicker // Renombrado
|
|
166
|
+
label="Fecha de Inicio"
|
|
167
|
+
selectedDate={startDate}
|
|
168
|
+
onDateChange={handleStartDateChange}
|
|
169
|
+
maxDate={endDate || undefined}
|
|
170
|
+
/>
|
|
171
|
+
<DatePicker // Renombrado
|
|
172
|
+
label="Fecha de Fin"
|
|
173
|
+
selectedDate={endDate}
|
|
174
|
+
onDateChange={handleEndDateChange}
|
|
175
|
+
minDate={startDate || undefined}
|
|
176
|
+
/>
|
|
177
|
+
<Typography>
|
|
178
|
+
Inicio: {startDate ? startDate.format('YYYY-MM-DD') : 'N/A'} |
|
|
179
|
+
Fin: {endDate ? endDate.format('YYYY-MM-DD') : 'N/A'}
|
|
180
|
+
</Typography>
|
|
181
|
+
</Box>
|
|
182
|
+
);
|
|
183
|
+
},
|
|
184
|
+
parameters: {
|
|
185
|
+
docs: {
|
|
186
|
+
description: {
|
|
187
|
+
story: "Dos `DatePicker`s que funcionan como un selector de rango de fechas, donde la fecha de inicio y fin se restringen mutuamente."
|
|
188
|
+
},
|
|
189
|
+
source: { code: DateRangePickerDefinition.trim() }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const DatePickerWithError: Story = {
|
|
195
|
+
render: () => {
|
|
196
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs('2023-01-01'));
|
|
197
|
+
const minDate = dayjs('2023-01-05');
|
|
198
|
+
const maxDate = dayjs('2023-01-10');
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<Box sx={{ width: 300 }}>
|
|
202
|
+
<DatePicker // Renombrado
|
|
203
|
+
label="Fecha (con error de rango)"
|
|
204
|
+
selectedDate={selectedDate}
|
|
205
|
+
onDateChange={setSelectedDate}
|
|
206
|
+
minDate={minDate}
|
|
207
|
+
maxDate={maxDate}
|
|
208
|
+
/>
|
|
209
|
+
<Typography sx={{ mt: 2 }}>
|
|
210
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
211
|
+
</Typography>
|
|
212
|
+
<Typography variant="caption" color="error">
|
|
213
|
+
(Intenta seleccionar una fecha fuera de ${minDate.format('YYYY-MM-DD')} - ${maxDate.format('YYYY-MM-DD')})
|
|
214
|
+
</Typography>
|
|
215
|
+
</Box>
|
|
216
|
+
);
|
|
217
|
+
},
|
|
218
|
+
parameters: {
|
|
219
|
+
docs: {
|
|
220
|
+
description: {
|
|
221
|
+
story: "Demuestra cómo el `DatePicker` maneja los errores de validación, por ejemplo, al seleccionar una fecha fuera del rango permitido."
|
|
222
|
+
},
|
|
223
|
+
source: { code: DatePickerWithErrorDefinition.trim() }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export const DatePickerSmallSize: Story = {
|
|
229
|
+
render: () => {
|
|
230
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs());
|
|
231
|
+
return (
|
|
232
|
+
<Box sx={{ width: 250 }}>
|
|
233
|
+
<DatePicker // Renombrado
|
|
234
|
+
label="Fecha (Pequeño)"
|
|
235
|
+
selectedDate={selectedDate}
|
|
236
|
+
onDateChange={setSelectedDate}
|
|
237
|
+
slotProps={{ textField: { size: 'small' } }}
|
|
238
|
+
/>
|
|
239
|
+
<Typography sx={{ mt: 2 }}>
|
|
240
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
241
|
+
</Typography>
|
|
242
|
+
</Box>
|
|
243
|
+
);
|
|
244
|
+
},
|
|
245
|
+
parameters: {
|
|
246
|
+
docs: {
|
|
247
|
+
description: {
|
|
248
|
+
story: "Muestra el `DatePicker` en un tamaño más pequeño utilizando `slotProps.textField.size`."
|
|
249
|
+
},
|
|
250
|
+
source: { code: DatePickerSmallSizeDefinition.trim() }
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export const DatePickerDisabled: Story = {
|
|
256
|
+
render: () => {
|
|
257
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs());
|
|
258
|
+
return (
|
|
259
|
+
<Box sx={{ width: 300 }}>
|
|
260
|
+
<DatePicker // Renombrado
|
|
261
|
+
label="Fecha (Deshabilitado)"
|
|
262
|
+
selectedDate={selectedDate}
|
|
263
|
+
onDateChange={setSelectedDate}
|
|
264
|
+
disabled
|
|
265
|
+
/>
|
|
266
|
+
<Typography sx={{ mt: 2 }}>
|
|
267
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
268
|
+
</Typography>
|
|
269
|
+
</Box>
|
|
270
|
+
);
|
|
271
|
+
},
|
|
272
|
+
parameters: {
|
|
273
|
+
docs: {
|
|
274
|
+
description: {
|
|
275
|
+
story: "Demuestra un `DatePicker` en estado deshabilitado, donde no se puede interactuar con él."
|
|
276
|
+
},
|
|
277
|
+
source: { code: DatePickerDisabledDefinition.trim() }
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const DatePickerReadOnly: Story = {
|
|
283
|
+
render: () => {
|
|
284
|
+
const [selectedDate, setSelectedDate] = useState<Dayjs | null>(dayjs('2024-07-24'));
|
|
285
|
+
return (
|
|
286
|
+
<Box sx={{ width: 300 }}>
|
|
287
|
+
<DatePicker // Renombrado
|
|
288
|
+
label="Fecha (Solo Lectura)"
|
|
289
|
+
selectedDate={selectedDate}
|
|
290
|
+
onDateChange={() => {}} // No permite cambios
|
|
291
|
+
readOnly
|
|
292
|
+
/>
|
|
293
|
+
<Typography sx={{ mt: 2 }}>
|
|
294
|
+
Fecha seleccionada: {selectedDate ? selectedDate.format('YYYY-MM-DD') : 'Ninguna'}
|
|
295
|
+
</Typography>
|
|
296
|
+
</Box>
|
|
297
|
+
);
|
|
298
|
+
},
|
|
299
|
+
parameters: {
|
|
300
|
+
docs: {
|
|
301
|
+
description: {
|
|
302
|
+
story: "Muestra el `DatePicker` en modo de solo lectura. El usuario puede ver la fecha pero no modificarla."
|
|
303
|
+
},
|
|
304
|
+
source: {
|
|
305
|
+
code: DatePickerReadOnlyDefinition.trim() // Usar la definición importada
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SxProps, Theme } from '@mui/material';
|
|
2
|
+
|
|
3
|
+
import { buildFormFieldSx } from '../_shared/formField.sx';
|
|
4
|
+
import { FIELD_INPUT_PADDING_Y } from '../../theme/tokens';
|
|
5
|
+
import type { LabelPosition } from './DatePicker';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Builder de sx para el DatePicker. Reutiliza `buildFormFieldSx` con
|
|
9
|
+
* `includePickersApi: true` para cubrir tanto la API clásica (MuiInputBase /
|
|
10
|
+
* MuiOutlinedInput) como la nueva (MuiPickersInputBase / MuiPickersOutlinedInput)
|
|
11
|
+
* del DatePicker de MUI X v8.
|
|
12
|
+
*/
|
|
13
|
+
export const buildDatePickerSx = (
|
|
14
|
+
borderRadius: number | string,
|
|
15
|
+
labelPosition: LabelPosition,
|
|
16
|
+
): SxProps<Theme> =>
|
|
17
|
+
buildFormFieldSx({
|
|
18
|
+
borderRadius,
|
|
19
|
+
labelPosition,
|
|
20
|
+
includePickersApi: true,
|
|
21
|
+
extraOutsideSx: {
|
|
22
|
+
'& .MuiInputBase-input': {
|
|
23
|
+
paddingTop: FIELD_INPUT_PADDING_Y,
|
|
24
|
+
paddingBottom: FIELD_INPUT_PADDING_Y,
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Secciones editables del PickersTextField (DD/MM/YYYY en API nueva).
|
|
28
|
+
'& .MuiPickersInputBase-sectionsContainer': {
|
|
29
|
+
paddingTop: FIELD_INPUT_PADDING_Y,
|
|
30
|
+
paddingBottom: FIELD_INPUT_PADDING_Y,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|