@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,175 @@
|
|
|
1
|
+
import React, { type ReactNode, useMemo } from 'react';
|
|
2
|
+
import { Badge, styled } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
5
|
+
|
|
6
|
+
export interface IconProps {
|
|
7
|
+
/**
|
|
8
|
+
* Contenido icono. Modo legacy: acepta un elemento MUI o SVG ya armado.
|
|
9
|
+
* Si se usa junto con `path` o `url`, `children` tiene prioridad.
|
|
10
|
+
*/
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Ruta SVG inline (el contenido del atributo `d` de un `<path>`). Útil para
|
|
14
|
+
* los iconos custom de Metronic que vienen como strings de path.
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <Icon path="M12 2L2 22h20L12 2z" />
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Si el string contiene el tag `<svg>` completo (no solo el `d`), también
|
|
21
|
+
* se soporta y se inyecta tal cual via `dangerouslySetInnerHTML`.
|
|
22
|
+
*/
|
|
23
|
+
path?: string;
|
|
24
|
+
/**
|
|
25
|
+
* URL a un archivo `.svg` (asset local o remoto). Se renderiza vía `<img>`.
|
|
26
|
+
*
|
|
27
|
+
* ```tsx
|
|
28
|
+
* <Icon url="/assets/icons/custom-warning.svg" />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
url?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Alt text cuando se usa `url`. Default: `"icon"`.
|
|
34
|
+
*/
|
|
35
|
+
alt?: string;
|
|
36
|
+
/**
|
|
37
|
+
* ViewBox cuando se usa `path`. Default: `"0 0 24 24"`. Ignorado si `path`
|
|
38
|
+
* ya viene como `<svg>` completo.
|
|
39
|
+
*/
|
|
40
|
+
viewBox?: string;
|
|
41
|
+
color?: string;
|
|
42
|
+
outlined?: boolean;
|
|
43
|
+
spin?: boolean;
|
|
44
|
+
badge?: string | number;
|
|
45
|
+
badgeColor?: 'primary' | 'secondary' | 'error';
|
|
46
|
+
badgePosition?: {
|
|
47
|
+
vertical: 'top' | 'bottom';
|
|
48
|
+
horizontal: 'right' | 'left';
|
|
49
|
+
};
|
|
50
|
+
badgeSize?: 'small' | 'medium' | 'large';
|
|
51
|
+
size?: IconSize;
|
|
52
|
+
black?: boolean;
|
|
53
|
+
white?: boolean;
|
|
54
|
+
className?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const sizeMap: Record<IconSize, number> = {
|
|
58
|
+
xs: 18,
|
|
59
|
+
sm: 24,
|
|
60
|
+
md: 36,
|
|
61
|
+
lg: 48,
|
|
62
|
+
xl: 64,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const StyledIcon = styled('span')<{
|
|
66
|
+
color?: string;
|
|
67
|
+
fontSize?: number;
|
|
68
|
+
spin?: boolean;
|
|
69
|
+
outlined?: boolean;
|
|
70
|
+
}>(({ color, fontSize, spin, outlined }) => ({
|
|
71
|
+
display: 'inline-flex',
|
|
72
|
+
alignItems: 'center',
|
|
73
|
+
justifyContent: 'center',
|
|
74
|
+
color: color,
|
|
75
|
+
fontSize: fontSize,
|
|
76
|
+
width: fontSize,
|
|
77
|
+
height: fontSize,
|
|
78
|
+
animation: spin ? 'spin 1s linear infinite' : undefined,
|
|
79
|
+
border: outlined ? '1px solid currentColor' : undefined,
|
|
80
|
+
borderRadius: '50%',
|
|
81
|
+
padding: outlined ? 4 : 0,
|
|
82
|
+
'@keyframes spin': {
|
|
83
|
+
'0%': { transform: 'rotate(0deg)' },
|
|
84
|
+
'100%': { transform: 'rotate(360deg)' },
|
|
85
|
+
},
|
|
86
|
+
'& svg': {
|
|
87
|
+
width: '100%',
|
|
88
|
+
height: '100%',
|
|
89
|
+
fill: 'currentColor',
|
|
90
|
+
display: 'block',
|
|
91
|
+
},
|
|
92
|
+
'& img': {
|
|
93
|
+
width: '100%',
|
|
94
|
+
height: '100%',
|
|
95
|
+
display: 'block',
|
|
96
|
+
},
|
|
97
|
+
}));
|
|
98
|
+
|
|
99
|
+
export const Icon: React.FC<IconProps> = ({
|
|
100
|
+
children,
|
|
101
|
+
path,
|
|
102
|
+
url,
|
|
103
|
+
alt = 'icon',
|
|
104
|
+
viewBox = '0 0 24 24',
|
|
105
|
+
color = 'var(--primary-color)',
|
|
106
|
+
outlined = false,
|
|
107
|
+
spin = false,
|
|
108
|
+
badge,
|
|
109
|
+
badgeColor = 'primary',
|
|
110
|
+
badgePosition = { vertical: 'bottom', horizontal: 'right' },
|
|
111
|
+
size = 'sm',
|
|
112
|
+
black,
|
|
113
|
+
white,
|
|
114
|
+
className,
|
|
115
|
+
}) => {
|
|
116
|
+
const finalColor = useMemo(() => {
|
|
117
|
+
if (white) return 'white';
|
|
118
|
+
if (black) return 'black';
|
|
119
|
+
return color;
|
|
120
|
+
}, [color, white, black]);
|
|
121
|
+
|
|
122
|
+
const iconSize = sizeMap[size];
|
|
123
|
+
|
|
124
|
+
// Resolver el contenido según la prop activa.
|
|
125
|
+
const content = useMemo(() => {
|
|
126
|
+
if (children) return children;
|
|
127
|
+
|
|
128
|
+
if (path) {
|
|
129
|
+
const trimmed = path.trim();
|
|
130
|
+
// Si es un SVG completo (empieza con <svg), lo inyectamos tal cual.
|
|
131
|
+
if (trimmed.startsWith('<svg')) {
|
|
132
|
+
return <span dangerouslySetInnerHTML={{ __html: trimmed }} />;
|
|
133
|
+
}
|
|
134
|
+
// Si no, asumimos que es el atributo `d` de un <path>.
|
|
135
|
+
return (
|
|
136
|
+
<svg
|
|
137
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
138
|
+
viewBox={viewBox}
|
|
139
|
+
fill="currentColor"
|
|
140
|
+
aria-hidden="true"
|
|
141
|
+
>
|
|
142
|
+
<path d={trimmed} />
|
|
143
|
+
</svg>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (url) {
|
|
148
|
+
return <img src={url} alt={alt} />;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return null;
|
|
152
|
+
}, [children, path, url, alt, viewBox]);
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<Badge
|
|
156
|
+
badgeContent={badge}
|
|
157
|
+
color={badgeColor}
|
|
158
|
+
anchorOrigin={badgePosition}
|
|
159
|
+
invisible={badge === undefined}
|
|
160
|
+
sx={{ '.MuiBadge-badge': { transform: 'scale(1)' } }}
|
|
161
|
+
>
|
|
162
|
+
<StyledIcon
|
|
163
|
+
color={finalColor}
|
|
164
|
+
fontSize={iconSize}
|
|
165
|
+
spin={spin}
|
|
166
|
+
outlined={outlined}
|
|
167
|
+
className={`hsi-icon ${className || ''}`}
|
|
168
|
+
>
|
|
169
|
+
{content}
|
|
170
|
+
</StyledIcon>
|
|
171
|
+
</Badge>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export default Icon;
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
// Input.definitions.ts
|
|
2
|
+
|
|
3
|
+
export const BasicTextInputDefinition = `
|
|
4
|
+
import React, { useState } from 'react';
|
|
5
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
6
|
+
import { Box, Typography } from '@mui/material';
|
|
7
|
+
|
|
8
|
+
export const BasicTextInputExample = () => {
|
|
9
|
+
const [value, setValue] = useState('Texto de ejemplo');
|
|
10
|
+
return (
|
|
11
|
+
<Box sx={{ width: 300 }}>
|
|
12
|
+
<Input
|
|
13
|
+
label="Nombre"
|
|
14
|
+
value={value}
|
|
15
|
+
onChange={setValue}
|
|
16
|
+
/>
|
|
17
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
18
|
+
</Box>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
export const NumberInputDefinition = `
|
|
24
|
+
import React, { useState } from 'react';
|
|
25
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
26
|
+
import { Box, Typography } from '@mui/material';
|
|
27
|
+
|
|
28
|
+
export const NumberInputExample = () => {
|
|
29
|
+
const [value, setValue] = useState(123);
|
|
30
|
+
return (
|
|
31
|
+
<Box sx={{ width: 300 }}>
|
|
32
|
+
<Input
|
|
33
|
+
label="Cantidad"
|
|
34
|
+
type="number"
|
|
35
|
+
value={value}
|
|
36
|
+
onChange={setValue}
|
|
37
|
+
/>
|
|
38
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
39
|
+
</Box>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
export const EmailInputDefinition = `
|
|
45
|
+
import React, { useState } from 'react';
|
|
46
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
47
|
+
import { Box, Typography } from '@mui/material';
|
|
48
|
+
|
|
49
|
+
export const EmailInputExample = () => {
|
|
50
|
+
const [value, setValue] = useState('ejemplo@dominio.com');
|
|
51
|
+
return (
|
|
52
|
+
<Box sx={{ width: 300 }}>
|
|
53
|
+
<Input
|
|
54
|
+
label="Correo Electrónico"
|
|
55
|
+
type="email"
|
|
56
|
+
value={value}
|
|
57
|
+
onChange={setValue}
|
|
58
|
+
/>
|
|
59
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
60
|
+
</Box>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
export const PasswordInputDefinition = `
|
|
66
|
+
import React, { useState } from 'react';
|
|
67
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
68
|
+
import { Box, Typography } from '@mui/material';
|
|
69
|
+
|
|
70
|
+
export const PasswordInputExample = () => {
|
|
71
|
+
const [value, setValue] = useState('micontraseña');
|
|
72
|
+
return (
|
|
73
|
+
<Box sx={{ width: 300 }}>
|
|
74
|
+
<Input
|
|
75
|
+
label="Contraseña"
|
|
76
|
+
type="password"
|
|
77
|
+
value={value}
|
|
78
|
+
onChange={setValue}
|
|
79
|
+
/>
|
|
80
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
81
|
+
</Box>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
export const InputWithPlaceholderDefinition = `
|
|
87
|
+
import React, { useState } from 'react';
|
|
88
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
89
|
+
import { Box, Typography } from '@mui/material';
|
|
90
|
+
|
|
91
|
+
export const InputWithPlaceholderExample = () => {
|
|
92
|
+
const [value, setValue] = useState('');
|
|
93
|
+
return (
|
|
94
|
+
<Box sx={{ width: 300 }}>
|
|
95
|
+
<Input
|
|
96
|
+
label="Búsqueda"
|
|
97
|
+
placeholder="Escribe tu término de búsqueda..."
|
|
98
|
+
value={value}
|
|
99
|
+
onChange={setValue}
|
|
100
|
+
/>
|
|
101
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value || 'Vacío'}</Typography>
|
|
102
|
+
</Box>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
export const InputWithErrorDefinition = `
|
|
108
|
+
import React, { useState } from 'react';
|
|
109
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
110
|
+
import { Box, Typography } from '@mui/material';
|
|
111
|
+
|
|
112
|
+
export const InputWithErrorExample = () => {
|
|
113
|
+
const [value, setValue] = useState('invalido');
|
|
114
|
+
const hasError = value.length < 5 && value.length > 0;
|
|
115
|
+
return (
|
|
116
|
+
<Box sx={{ width: 300 }}>
|
|
117
|
+
<Input
|
|
118
|
+
label="Nombre de usuario"
|
|
119
|
+
value={value}
|
|
120
|
+
onChange={setValue}
|
|
121
|
+
error={hasError}
|
|
122
|
+
helperText={hasError ? 'Mínimo 5 caracteres' : ''}
|
|
123
|
+
/>
|
|
124
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
125
|
+
</Box>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
export const DisabledInputDefinition = `
|
|
131
|
+
import React, { useState } from 'react';
|
|
132
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
133
|
+
import { Box, Typography } from '@mui/material';
|
|
134
|
+
|
|
135
|
+
export const DisabledInputExample = () => {
|
|
136
|
+
const [value, setValue] = useState('Campo deshabilitado');
|
|
137
|
+
return (
|
|
138
|
+
<Box sx={{ width: 300 }}>
|
|
139
|
+
<Input
|
|
140
|
+
label="Estado"
|
|
141
|
+
value={value}
|
|
142
|
+
onChange={setValue}
|
|
143
|
+
disabled
|
|
144
|
+
/>
|
|
145
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
146
|
+
</Box>
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
`;
|
|
150
|
+
|
|
151
|
+
export const ReadOnlyInputDefinition = `
|
|
152
|
+
import React, { useState } from 'react';
|
|
153
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
154
|
+
import { Box, Typography } from '@mui/material';
|
|
155
|
+
|
|
156
|
+
export const ReadOnlyInputExample = () => {
|
|
157
|
+
const [value, setValue] = useState('Valor de solo lectura');
|
|
158
|
+
return (
|
|
159
|
+
<Box sx={{ width: 300 }}>
|
|
160
|
+
<Input
|
|
161
|
+
label="Información"
|
|
162
|
+
value={value}
|
|
163
|
+
onChange={setValue}
|
|
164
|
+
readOnly
|
|
165
|
+
/>
|
|
166
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
167
|
+
</Box>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
`;
|
|
171
|
+
|
|
172
|
+
export const InputVariantsDefinition = `
|
|
173
|
+
import React, { useState } from 'react';
|
|
174
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
175
|
+
import { Box, Typography } from '@mui/material';
|
|
176
|
+
|
|
177
|
+
export const InputVariantsExample = () => {
|
|
178
|
+
const [valueOutlined, setValueOutlined] = useState('Outlined');
|
|
179
|
+
const [valueFilled, setValueFilled] = useState('Filled');
|
|
180
|
+
const [valueStandard, setValueStandard] = useState('Standard');
|
|
181
|
+
return (
|
|
182
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, width: 300 }}>
|
|
183
|
+
<Input
|
|
184
|
+
label="Esquema Outlined"
|
|
185
|
+
value={valueOutlined}
|
|
186
|
+
onChange={setValueOutlined}
|
|
187
|
+
variant="outlined"
|
|
188
|
+
/>
|
|
189
|
+
<Input
|
|
190
|
+
label="Esquema Filled"
|
|
191
|
+
value={valueFilled}
|
|
192
|
+
onChange={setValueFilled}
|
|
193
|
+
variant="filled"
|
|
194
|
+
/>
|
|
195
|
+
<Input
|
|
196
|
+
label="Esquema Standard"
|
|
197
|
+
value={valueStandard}
|
|
198
|
+
onChange={setValueStandard}
|
|
199
|
+
variant="standard"
|
|
200
|
+
/>
|
|
201
|
+
</Box>
|
|
202
|
+
);
|
|
203
|
+
};
|
|
204
|
+
`;
|
|
205
|
+
|
|
206
|
+
export const InputSizesDefinition = `
|
|
207
|
+
import React, { useState } from 'react';
|
|
208
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
209
|
+
import { Box, Typography } from '@mui/material';
|
|
210
|
+
|
|
211
|
+
export const InputSizesExample = () => {
|
|
212
|
+
const [valueMedium, setValueMedium] = useState('Tamaño Mediano');
|
|
213
|
+
const [valueSmall, setValueSmall] = useState('Tamaño Pequeño');
|
|
214
|
+
return (
|
|
215
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, width: 300 }}>
|
|
216
|
+
<Input
|
|
217
|
+
label="Input Mediano"
|
|
218
|
+
value={valueMedium}
|
|
219
|
+
onChange={setValueMedium}
|
|
220
|
+
size="medium"
|
|
221
|
+
/>
|
|
222
|
+
<Input
|
|
223
|
+
label="Input Pequeño"
|
|
224
|
+
value={valueSmall}
|
|
225
|
+
onChange={setValueSmall}
|
|
226
|
+
size="small"
|
|
227
|
+
/>
|
|
228
|
+
</Box>
|
|
229
|
+
);
|
|
230
|
+
};
|
|
231
|
+
`;
|
|
232
|
+
|
|
233
|
+
export const FullWidthInputDefinition = `
|
|
234
|
+
import React, { useState } from 'react';
|
|
235
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
236
|
+
import { Box, Typography } from '@mui/material';
|
|
237
|
+
|
|
238
|
+
export const FullWidthInputExample = () => {
|
|
239
|
+
const [value, setValue] = useState('Ocupa todo el ancho');
|
|
240
|
+
return (
|
|
241
|
+
<Box sx={{ width: '100%' }}>
|
|
242
|
+
<Input
|
|
243
|
+
label="Input de Ancho Completo"
|
|
244
|
+
value={value}
|
|
245
|
+
onChange={setValue}
|
|
246
|
+
fullWidth
|
|
247
|
+
/>
|
|
248
|
+
<Typography sx={{ mt: 2 }}>Valor actual: {value}</Typography>
|
|
249
|
+
</Box>
|
|
250
|
+
);
|
|
251
|
+
};
|
|
252
|
+
`;
|
|
253
|
+
|
|
254
|
+
export const LabelPositionFloatingDefinition = `
|
|
255
|
+
import React, { useState } from 'react';
|
|
256
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
257
|
+
import { Box } from '@mui/material';
|
|
258
|
+
|
|
259
|
+
export const LabelPositionExample = () => {
|
|
260
|
+
const [outside, setOutside] = useState('Outside (default)');
|
|
261
|
+
const [floating, setFloating] = useState('Floating');
|
|
262
|
+
return (
|
|
263
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, width: 300 }}>
|
|
264
|
+
<Input
|
|
265
|
+
label="Label outside"
|
|
266
|
+
value={outside}
|
|
267
|
+
onChange={setOutside}
|
|
268
|
+
labelPosition="outside"
|
|
269
|
+
/>
|
|
270
|
+
<Input
|
|
271
|
+
label="Label floating (MUI clásico)"
|
|
272
|
+
value={floating}
|
|
273
|
+
onChange={setFloating}
|
|
274
|
+
labelPosition="floating"
|
|
275
|
+
/>
|
|
276
|
+
</Box>
|
|
277
|
+
);
|
|
278
|
+
};
|
|
279
|
+
`;
|
|
280
|
+
|
|
281
|
+
export const CustomBorderRadiusDefinition = `
|
|
282
|
+
import React, { useState } from 'react';
|
|
283
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
284
|
+
import { Box } from '@mui/material';
|
|
285
|
+
|
|
286
|
+
export const CustomBorderRadiusExample = () => {
|
|
287
|
+
const [v, setV] = useState('Texto');
|
|
288
|
+
return (
|
|
289
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, width: 300 }}>
|
|
290
|
+
<Input label="Sin radius" value={v} onChange={setV} borderRadius={0} />
|
|
291
|
+
<Input label="Radius 4px" value={v} onChange={setV} borderRadius={4} />
|
|
292
|
+
<Input label="Default (10px)" value={v} onChange={setV} />
|
|
293
|
+
<Input label="Pill (24px)" value={v} onChange={setV} borderRadius={24} />
|
|
294
|
+
</Box>
|
|
295
|
+
);
|
|
296
|
+
};
|
|
297
|
+
`;
|
|
298
|
+
|
|
299
|
+
export const CustomStylingDefinition = `
|
|
300
|
+
import React, { useState } from 'react';
|
|
301
|
+
import { Input } from './Input'; // Ajusta la ruta si es necesario
|
|
302
|
+
import { Box } from '@mui/material';
|
|
303
|
+
|
|
304
|
+
export const CustomStylingExample = () => {
|
|
305
|
+
const [v, setV] = useState('Custom completo');
|
|
306
|
+
return (
|
|
307
|
+
<Box sx={{ width: 300 }}>
|
|
308
|
+
<Input
|
|
309
|
+
label="Combinado: bg + borderColor + label color"
|
|
310
|
+
value={v}
|
|
311
|
+
onChange={setV}
|
|
312
|
+
sx={{
|
|
313
|
+
'& .MuiInputLabel-root': { color: 'primary.main' },
|
|
314
|
+
'& .MuiOutlinedInput-root': { bgcolor: '#fff7e6' },
|
|
315
|
+
'& .MuiOutlinedInput-notchedOutline': {
|
|
316
|
+
borderColor: 'warning.main',
|
|
317
|
+
borderWidth: 2,
|
|
318
|
+
},
|
|
319
|
+
}}
|
|
320
|
+
/>
|
|
321
|
+
</Box>
|
|
322
|
+
);
|
|
323
|
+
};
|
|
324
|
+
`;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { InputHTMLAttributes } from 'react';
|
|
2
|
+
import type { TextFieldProps } from '@mui/material';
|
|
3
|
+
import type { InputType, LabelPosition } from './Input';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convierte el valor raw del evento al tipo apropiado.
|
|
7
|
+
* Para type="number" intenta parsear a número; si falla, devuelve el raw
|
|
8
|
+
* (permite estados intermedios como "" o "-" mientras el usuario tipea).
|
|
9
|
+
*/
|
|
10
|
+
export const parseValue = (raw: string, type: InputType): string | number => {
|
|
11
|
+
if (type !== 'number') return raw;
|
|
12
|
+
if (raw === '' || raw === '-') return raw;
|
|
13
|
+
const n = parseFloat(raw);
|
|
14
|
+
return isNaN(n) ? raw : n;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Construye los slotProps del TextField consolidando htmlInput + inputLabel.
|
|
19
|
+
* Maneja los atributos min/max cuando type="number" y readOnly.
|
|
20
|
+
*/
|
|
21
|
+
export const buildSlotProps = (
|
|
22
|
+
type: InputType,
|
|
23
|
+
min: number | undefined,
|
|
24
|
+
max: number | undefined,
|
|
25
|
+
customSlotProps: TextFieldProps['slotProps'],
|
|
26
|
+
customInputProps: InputHTMLAttributes<HTMLInputElement> | undefined,
|
|
27
|
+
_labelPosition: LabelPosition,
|
|
28
|
+
readOnly?: boolean,
|
|
29
|
+
): TextFieldProps['slotProps'] => {
|
|
30
|
+
const numberAttrs =
|
|
31
|
+
type === 'number'
|
|
32
|
+
? { min: min ?? Number.NEGATIVE_INFINITY, ...(max !== undefined && { max }) }
|
|
33
|
+
: {};
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
...customSlotProps,
|
|
37
|
+
htmlInput: {
|
|
38
|
+
...customInputProps,
|
|
39
|
+
...(customSlotProps as any)?.htmlInput,
|
|
40
|
+
...numberAttrs,
|
|
41
|
+
...(readOnly && { readOnly: true }),
|
|
42
|
+
},
|
|
43
|
+
// Dejamos que MUI maneje el shrink nativamente (animación inside → up).
|
|
44
|
+
// El consumidor puede forzar shrink con slotProps.inputLabel.shrink=true si lo necesita.
|
|
45
|
+
inputLabel: {
|
|
46
|
+
...(customSlotProps as any)?.inputLabel,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
};
|