anima-ds-nucleus 1.0.0
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/LICENSE.md +20 -0
- package/README.md +109 -0
- package/dist/anima-ds.cjs.js +1332 -0
- package/dist/anima-ds.esm.js +88297 -0
- package/dist/vite.svg +1 -0
- package/package.json +76 -0
- package/src/assets/charly.png +0 -0
- package/src/components/Atoms/Alert/Alert.jsx +52 -0
- package/src/components/Atoms/Alert/Alert.stories.jsx +62 -0
- package/src/components/Atoms/Avatar/Avatar.jsx +60 -0
- package/src/components/Atoms/Avatar/Avatar.stories.jsx +61 -0
- package/src/components/Atoms/Badge/Badge.jsx +34 -0
- package/src/components/Atoms/Badge/Badge.stories.jsx +55 -0
- package/src/components/Atoms/Button/Button.jsx +281 -0
- package/src/components/Atoms/Button/Button.stories.jsx +365 -0
- package/src/components/Atoms/Divider/Divider.jsx +49 -0
- package/src/components/Atoms/Divider/Divider.stories.jsx +62 -0
- package/src/components/Atoms/Icon/Icon.jsx +361 -0
- package/src/components/Atoms/Icon/Icon.stories.jsx +115 -0
- package/src/components/Atoms/Label/Label.jsx +22 -0
- package/src/components/Atoms/Progress/Progress.jsx +49 -0
- package/src/components/Atoms/Progress/Progress.stories.jsx +88 -0
- package/src/components/Atoms/Radios/Radios.jsx +39 -0
- package/src/components/Atoms/Radios/Radios.stories.jsx +119 -0
- package/src/components/Atoms/Shadow/Shadow.stories.jsx +25 -0
- package/src/components/Atoms/Skeleton/Skeleton.jsx +50 -0
- package/src/components/Atoms/Skeleton/Skeleton.stories.jsx +55 -0
- package/src/components/Atoms/Spacing/Spacing.jsx +56 -0
- package/src/components/Atoms/Spacing/Spacing.stories.jsx +78 -0
- package/src/components/Atoms/Spinner/Spinner.jsx +47 -0
- package/src/components/Atoms/Spinner/Spinner.stories.jsx +56 -0
- package/src/components/Atoms/Toast/Toast.jsx +74 -0
- package/src/components/Atoms/Toast/Toast.stories.jsx +101 -0
- package/src/components/Atoms/Tooltip/Tooltip.jsx +49 -0
- package/src/components/Atoms/Tooltip/Tooltip.stories.jsx +58 -0
- package/src/components/Atoms/Typography/Typography.jsx +52 -0
- package/src/components/Atoms/Typography/Typography.stories.jsx +267 -0
- package/src/components/DataDisplay/AreaChart/AreaChart.jsx +95 -0
- package/src/components/DataDisplay/AreaChart/AreaChart.stories.jsx +51 -0
- package/src/components/DataDisplay/BarChart/BarChart.jsx +90 -0
- package/src/components/DataDisplay/BarChart/BarChart.stories.jsx +60 -0
- package/src/components/DataDisplay/Card/Card.jsx +31 -0
- package/src/components/DataDisplay/Card/Card.stories.jsx +50 -0
- package/src/components/DataDisplay/ColumnChart/ColumnChart.jsx +92 -0
- package/src/components/DataDisplay/ColumnChart/ColumnChart.stories.jsx +65 -0
- package/src/components/DataDisplay/DBGrid/DBGrid.jsx +138 -0
- package/src/components/DataDisplay/DBGrid/DBGrid.stories.jsx +126 -0
- package/src/components/DataDisplay/DonutChart/DonutChart.jsx +83 -0
- package/src/components/DataDisplay/DonutChart/DonutChart.stories.jsx +48 -0
- package/src/components/DataDisplay/EmptyState/EmptyState.jsx +30 -0
- package/src/components/DataDisplay/EmptyState/EmptyState.stories.jsx +42 -0
- package/src/components/DataDisplay/LineChart/LineChart.jsx +86 -0
- package/src/components/DataDisplay/LineChart/LineChart.stories.jsx +67 -0
- package/src/components/DataDisplay/List/List.jsx +30 -0
- package/src/components/DataDisplay/List/List.stories.jsx +59 -0
- package/src/components/DataDisplay/PieChart/PieChart.jsx +64 -0
- package/src/components/DataDisplay/PieChart/PieChart.stories.jsx +47 -0
- package/src/components/DataDisplay/StatCard/StatCard.jsx +55 -0
- package/src/components/DataDisplay/StatCard/StatCard.stories.jsx +59 -0
- package/src/components/DataDisplay/TagList/TagList.jsx +37 -0
- package/src/components/DataDisplay/TagList/TagList.stories.jsx +48 -0
- package/src/components/DataDisplay/Timeline/Timeline.jsx +41 -0
- package/src/components/DataDisplay/Timeline/Timeline.stories.jsx +64 -0
- package/src/components/Inputs/Checkbox/Checkbox.jsx +27 -0
- package/src/components/Inputs/Checkbox/Checkbox.stories.jsx +51 -0
- package/src/components/Inputs/DatePicker/DatePicker.jsx +55 -0
- package/src/components/Inputs/DatePicker/DatePicker.stories.jsx +52 -0
- package/src/components/Inputs/FileUpload/FileUpload.jsx +108 -0
- package/src/components/Inputs/FileUpload/FileUpload.stories.jsx +52 -0
- package/src/components/Inputs/Input/Input.jsx +50 -0
- package/src/components/Inputs/Input/Input.stories.jsx +63 -0
- package/src/components/Inputs/RadioButton/RadioButton.jsx +31 -0
- package/src/components/Inputs/RadioButton/RadioButton.stories.jsx +59 -0
- package/src/components/Inputs/Select/Select.jsx +59 -0
- package/src/components/Inputs/Select/Select.stories.jsx +66 -0
- package/src/components/Inputs/Switch/Switch.jsx +44 -0
- package/src/components/Inputs/Switch/Switch.stories.jsx +51 -0
- package/src/components/Inputs/Textarea/Textarea.jsx +51 -0
- package/src/components/Inputs/Textarea/Textarea.stories.jsx +65 -0
- package/src/components/Layout/Accordion/Accordion.jsx +58 -0
- package/src/components/Layout/Accordion/Accordion.stories.jsx +55 -0
- package/src/components/Layout/Breadcrumbs/Breadcrumbs.jsx +49 -0
- package/src/components/Layout/Breadcrumbs/Breadcrumbs.stories.jsx +44 -0
- package/src/components/Layout/Breakpoint/Breakpoint.jsx +35 -0
- package/src/components/Layout/Breakpoint/Breakpoint.stories.jsx +348 -0
- package/src/components/Layout/Drawer/Drawer.jsx +75 -0
- package/src/components/Layout/Drawer/Drawer.stories.jsx +77 -0
- package/src/components/Layout/Dropdown/Dropdown.jsx +83 -0
- package/src/components/Layout/Dropdown/Dropdown.stories.jsx +53 -0
- package/src/components/Layout/Grid/Grid.jsx +39 -0
- package/src/components/Layout/Grid/Grid.stories.jsx +546 -0
- package/src/components/Layout/Header/Header.jsx +50 -0
- package/src/components/Layout/Header/Header.stories.jsx +36 -0
- package/src/components/Layout/Layout/Layout.jsx +14 -0
- package/src/components/Layout/Layout/Layout.stories.jsx +34 -0
- package/src/components/Layout/Modal/Modal.jsx +78 -0
- package/src/components/Layout/Modal/Modal.stories.jsx +98 -0
- package/src/components/Layout/Pagination/Pagination.jsx +109 -0
- package/src/components/Layout/Pagination/Pagination.stories.jsx +62 -0
- package/src/components/Layout/Sidebar/Sidebar.jsx +57 -0
- package/src/components/Layout/Sidebar/Sidebar.stories.jsx +51 -0
- package/src/components/Layout/Stepper/Stepper.jsx +132 -0
- package/src/components/Layout/Stepper/Stepper.stories.jsx +78 -0
- package/src/components/Layout/Tabs/Tabs.jsx +63 -0
- package/src/components/Layout/Tabs/Tabs.stories.jsx +62 -0
- package/src/components/Views/ChangePasswordForm/ChangePasswordForm.jsx +125 -0
- package/src/components/Views/ChangePasswordForm/ChangePasswordForm.stories.jsx +55 -0
- package/src/components/Views/Chat/Chat.jsx +134 -0
- package/src/components/Views/Chat/Chat.stories.jsx +143 -0
- package/src/components/Views/LoginForm/LoginForm.jsx +98 -0
- package/src/components/Views/LoginForm/LoginForm.stories.jsx +55 -0
- package/src/i18n/config.js +209 -0
- package/src/index.js +60 -0
- package/src/main.jsx +510 -0
- package/src/providers/I18nProvider.jsx +13 -0
- package/src/style.css +721 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Radios, RADIOS_SCALE } from './Radios';
|
|
2
|
+
|
|
3
|
+
const sizeOptions = RADIOS_SCALE.map((token) => token.key);
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Atoms/Radios',
|
|
7
|
+
component: Radios,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
argTypes: {
|
|
10
|
+
size: {
|
|
11
|
+
control: 'select',
|
|
12
|
+
options: sizeOptions,
|
|
13
|
+
description: 'Token de radio (px base transformado a rem)',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const Playground = {
|
|
19
|
+
args: {
|
|
20
|
+
size: '16',
|
|
21
|
+
className: 'bg-emerald-500 w-32 h-32',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const EscalaCompleta = () => (
|
|
26
|
+
<div className="space-y-4">
|
|
27
|
+
<h3 className="text-lg font-semibold text-gray-800 mb-4">Tamaños</h3>
|
|
28
|
+
{RADIOS_SCALE.map((token) => (
|
|
29
|
+
<div
|
|
30
|
+
key={token.key}
|
|
31
|
+
className="flex items-center gap-6"
|
|
32
|
+
>
|
|
33
|
+
<div className={`radius-token radius-token-${token.key}`} />
|
|
34
|
+
<div className="flex items-center gap-2 text-sm">
|
|
35
|
+
<span className={`text-gray-800 ${token.key === '16' ? 'font-bold' : ''}`}>
|
|
36
|
+
{token.px}
|
|
37
|
+
</span>
|
|
38
|
+
<span className={`${token.key === '16' ? 'text-emerald-600 font-bold' : 'text-emerald-600'}`}>
|
|
39
|
+
{token.rem}
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
))}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const EjemplosDeUso = () => (
|
|
48
|
+
<div className="space-y-6">
|
|
49
|
+
<div>
|
|
50
|
+
<p className="text-body-md font-medium text-gray-700 mb-4">
|
|
51
|
+
Botones con diferentes radios
|
|
52
|
+
</p>
|
|
53
|
+
<div className="flex items-center gap-4 flex-wrap">
|
|
54
|
+
<button className={`px-4 py-2 bg-emerald-500 text-white radius-4 hover:bg-emerald-600 transition-colors`}>
|
|
55
|
+
radius-4
|
|
56
|
+
</button>
|
|
57
|
+
<button className={`px-4 py-2 bg-emerald-500 text-white radius-8 hover:bg-emerald-600 transition-colors`}>
|
|
58
|
+
radius-8
|
|
59
|
+
</button>
|
|
60
|
+
<button className={`px-4 py-2 bg-emerald-500 text-white radius-12 hover:bg-emerald-600 transition-colors`}>
|
|
61
|
+
radius-12
|
|
62
|
+
</button>
|
|
63
|
+
<button className={`px-4 py-2 bg-emerald-500 text-white radius-16 hover:bg-emerald-600 transition-colors`}>
|
|
64
|
+
radius-16 (Base)
|
|
65
|
+
</button>
|
|
66
|
+
<button className={`px-4 py-2 bg-emerald-500 text-white radius-24 hover:bg-emerald-600 transition-colors`}>
|
|
67
|
+
radius-24
|
|
68
|
+
</button>
|
|
69
|
+
<button className={`px-4 py-2 bg-emerald-500 text-white radius-32 hover:bg-emerald-600 transition-colors`}>
|
|
70
|
+
radius-32
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div>
|
|
76
|
+
<p className="text-body-md font-medium text-gray-700 mb-4">
|
|
77
|
+
Cards con diferentes radios
|
|
78
|
+
</p>
|
|
79
|
+
<div className="grid grid-cols-3 gap-4">
|
|
80
|
+
<div className={`p-4 bg-white border border-gray-200 shadow-sm radius-4`}>
|
|
81
|
+
<h3 className="font-semibold mb-2">Card radius-4</h3>
|
|
82
|
+
<p className="text-sm text-gray-600">Bordes más cuadrados</p>
|
|
83
|
+
</div>
|
|
84
|
+
<div className={`p-4 bg-white border border-gray-200 shadow-sm radius-16`}>
|
|
85
|
+
<h3 className="font-semibold mb-2">Card radius-16</h3>
|
|
86
|
+
<p className="text-sm text-gray-600">Bordes estándar</p>
|
|
87
|
+
</div>
|
|
88
|
+
<div className={`p-4 bg-white border border-gray-200 shadow-sm radius-32`}>
|
|
89
|
+
<h3 className="font-semibold mb-2">Card radius-32</h3>
|
|
90
|
+
<p className="text-sm text-gray-600">Bordes muy redondeados</p>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div>
|
|
96
|
+
<p className="text-body-md font-medium text-gray-700 mb-4">
|
|
97
|
+
Inputs con diferentes radios
|
|
98
|
+
</p>
|
|
99
|
+
<div className="flex flex-col gap-4 max-w-md">
|
|
100
|
+
<input
|
|
101
|
+
type="text"
|
|
102
|
+
placeholder="Input con radius-4"
|
|
103
|
+
className={`px-4 py-2 border border-gray-300 radius-4 focus:outline-none focus:ring-2 focus:ring-emerald-500`}
|
|
104
|
+
/>
|
|
105
|
+
<input
|
|
106
|
+
type="text"
|
|
107
|
+
placeholder="Input con radius-12"
|
|
108
|
+
className={`px-4 py-2 border border-gray-300 radius-12 focus:outline-none focus:ring-2 focus:ring-emerald-500`}
|
|
109
|
+
/>
|
|
110
|
+
<input
|
|
111
|
+
type="text"
|
|
112
|
+
placeholder="Input con radius-16 (Base)"
|
|
113
|
+
className={`px-4 py-2 border border-gray-300 radius-16 focus:outline-none focus:ring-2 focus:ring-emerald-500`}
|
|
114
|
+
/>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const ShadowCard = ({ children = 'Default' }) => (
|
|
2
|
+
<div className="p-12 bg-gradient-to-br from-gray-50 to-white min-h-[240px] flex items-center justify-center">
|
|
3
|
+
<div className="shadow px-10 py-8 text-center">
|
|
4
|
+
<p className="text-body-lg text-gray-700">{children}</p>
|
|
5
|
+
</div>
|
|
6
|
+
</div>
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Atoms/Shadows',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const Default = {
|
|
14
|
+
render: () => (
|
|
15
|
+
<div className="max-w-lg mx-auto space-y-4">
|
|
16
|
+
<ShadowCard>Shadow Default</ShadowCard>
|
|
17
|
+
<div className="text-center">
|
|
18
|
+
<code className="text-emerald-600 text-sm">.shadow</code>
|
|
19
|
+
<p className="text-gray-500 text-sm mt-1">Box shadow oficial del sistema</p>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export const Skeleton = ({
|
|
2
|
+
variant = 'text',
|
|
3
|
+
width,
|
|
4
|
+
height,
|
|
5
|
+
className = '',
|
|
6
|
+
...props
|
|
7
|
+
}) => {
|
|
8
|
+
const baseClasses = 'animate-pulse bg-gray-200 rounded';
|
|
9
|
+
|
|
10
|
+
const variantClasses = {
|
|
11
|
+
text: 'h-4',
|
|
12
|
+
circular: 'rounded-full',
|
|
13
|
+
rectangular: 'rounded',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const style = {};
|
|
17
|
+
if (width) style.width = width;
|
|
18
|
+
if (height) style.height = height;
|
|
19
|
+
|
|
20
|
+
if (variant === 'circular') {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
className={`${baseClasses} ${variantClasses.circular} ${className}`}
|
|
24
|
+
style={style}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (variant === 'rectangular') {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
className={`${baseClasses} ${variantClasses.rectangular} ${className}`}
|
|
34
|
+
style={style}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
className={`${baseClasses} ${variantClasses.text} ${className}`}
|
|
43
|
+
style={style}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default Skeleton;
|
|
50
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Skeleton } from './Skeleton';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Atoms/Skeleton',
|
|
5
|
+
component: Skeleton,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
argTypes: {
|
|
8
|
+
variant: {
|
|
9
|
+
control: 'select',
|
|
10
|
+
options: ['text', 'circular', 'rectangular'],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const Text = {
|
|
16
|
+
args: {
|
|
17
|
+
variant: 'text',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Circular = {
|
|
22
|
+
args: {
|
|
23
|
+
variant: 'circular',
|
|
24
|
+
width: 40,
|
|
25
|
+
height: 40,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Rectangular = {
|
|
30
|
+
args: {
|
|
31
|
+
variant: 'rectangular',
|
|
32
|
+
width: 200,
|
|
33
|
+
height: 100,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const CustomSize = {
|
|
38
|
+
args: {
|
|
39
|
+
variant: 'text',
|
|
40
|
+
width: '50%',
|
|
41
|
+
height: 20,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const CardSkeleton = {
|
|
46
|
+
render: () => (
|
|
47
|
+
<div className="border rounded-lg p-4 space-y-3">
|
|
48
|
+
<Skeleton variant="circular" width={40} height={40} />
|
|
49
|
+
<Skeleton variant="text" width="80%" />
|
|
50
|
+
<Skeleton variant="text" width="60%" />
|
|
51
|
+
<Skeleton variant="rectangular" width="100%" height={100} />
|
|
52
|
+
</div>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const SCALE = [
|
|
2
|
+
{ key: '160', px: '160px', rem: '10rem' },
|
|
3
|
+
{ key: '96', px: '96px', rem: '6rem' },
|
|
4
|
+
{ key: '80', px: '80px', rem: '5rem' },
|
|
5
|
+
{ key: '64', px: '64px', rem: '4rem' },
|
|
6
|
+
{ key: '48', px: '48px', rem: '3rem' },
|
|
7
|
+
{ key: '40', px: '40px', rem: '2.5rem' },
|
|
8
|
+
{ key: '32', px: '32px', rem: '2rem' },
|
|
9
|
+
{ key: '24', px: '24px', rem: '1.5rem' },
|
|
10
|
+
{ key: '16', px: '16px', rem: '1rem' },
|
|
11
|
+
{ key: '12', px: '12px', rem: '0.75rem' },
|
|
12
|
+
{ key: '8', px: '8px', rem: '0.5rem' },
|
|
13
|
+
{ key: '4', px: '4px', rem: '0.25rem' },
|
|
14
|
+
{ key: '2', px: '2px', rem: '0.125rem' },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const scaleMap = SCALE.reduce((acc, token) => {
|
|
18
|
+
acc[token.key] = token;
|
|
19
|
+
acc[`space-${token.key}`] = token;
|
|
20
|
+
return acc;
|
|
21
|
+
}, {});
|
|
22
|
+
|
|
23
|
+
export const SPACING_SCALE = SCALE;
|
|
24
|
+
|
|
25
|
+
export const Spacing = ({
|
|
26
|
+
size = '16',
|
|
27
|
+
axis = 'vertical',
|
|
28
|
+
as: Component = 'div',
|
|
29
|
+
className = '',
|
|
30
|
+
style = {},
|
|
31
|
+
thickness = '1px',
|
|
32
|
+
...props
|
|
33
|
+
}) => {
|
|
34
|
+
const normalized = typeof size === 'number' ? String(size) : size;
|
|
35
|
+
const token = scaleMap[normalized] || scaleMap['16'];
|
|
36
|
+
const cssVar = `var(--space-${token.key})`;
|
|
37
|
+
|
|
38
|
+
const dimensionStyle =
|
|
39
|
+
axis === 'horizontal'
|
|
40
|
+
? { width: cssVar, height: thickness }
|
|
41
|
+
: axis === 'square'
|
|
42
|
+
? { width: cssVar, height: cssVar }
|
|
43
|
+
: { height: cssVar, width: thickness };
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Component
|
|
47
|
+
className={className}
|
|
48
|
+
style={{ display: 'inline-flex', ...dimensionStyle, ...style }}
|
|
49
|
+
aria-hidden="true"
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default Spacing;
|
|
56
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Spacing, SPACING_SCALE } from './Spacing';
|
|
2
|
+
|
|
3
|
+
const sizeOptions = SPACING_SCALE.map((token) => token.key);
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Atoms/Spacing',
|
|
7
|
+
component: Spacing,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
argTypes: {
|
|
10
|
+
size: {
|
|
11
|
+
control: 'select',
|
|
12
|
+
options: sizeOptions,
|
|
13
|
+
description: 'Token de espacio (px base transformado a rem)',
|
|
14
|
+
},
|
|
15
|
+
axis: {
|
|
16
|
+
control: 'inline-radio',
|
|
17
|
+
options: ['vertical', 'horizontal', 'square'],
|
|
18
|
+
},
|
|
19
|
+
thickness: {
|
|
20
|
+
control: 'text',
|
|
21
|
+
description: 'Grosor usado cuando axis es vertical u horizontal',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Playground = {
|
|
27
|
+
args: {
|
|
28
|
+
size: '32',
|
|
29
|
+
axis: 'square',
|
|
30
|
+
className: 'bg-emerald-500 rounded',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const EscalaCompleta = () => (
|
|
35
|
+
<div className="space-y-4">
|
|
36
|
+
{SPACING_SCALE.map((token) => (
|
|
37
|
+
<div
|
|
38
|
+
key={token.key}
|
|
39
|
+
className="flex items-center gap-6 border border-gray-100 rounded-lg p-4 shadow-sm bg-white"
|
|
40
|
+
>
|
|
41
|
+
<div className={`space-token space-token-${token.key}`} />
|
|
42
|
+
<div className="flex flex-col text-sm text-gray-700">
|
|
43
|
+
<span className="font-semibold">{`space-${token.key}`}</span>
|
|
44
|
+
<span>{token.px} / {token.rem}</span>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export const UsosComunes = () => (
|
|
52
|
+
<div className="space-y-6">
|
|
53
|
+
<div>
|
|
54
|
+
<p className="text-body-md font-medium text-gray-700 mb-2">
|
|
55
|
+
Separadores verticales
|
|
56
|
+
</p>
|
|
57
|
+
<div className="flex flex-col border rounded-lg p-4 gap-0 bg-white">
|
|
58
|
+
<div className="py-2 text-gray-600">Bloque A</div>
|
|
59
|
+
<Spacing size="24" axis="vertical" className="bg-transparent" />
|
|
60
|
+
<div className="py-2 text-gray-600">Bloque B</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div>
|
|
65
|
+
<p className="text-body-md font-medium text-gray-700 mb-2">
|
|
66
|
+
Separadores horizontales
|
|
67
|
+
</p>
|
|
68
|
+
<div className="flex items-center border rounded-lg p-4 bg-white">
|
|
69
|
+
<div className="text-gray-600">Etiqueta</div>
|
|
70
|
+
<Spacing size="16" axis="horizontal" thickness="1px" className="bg-transparent" />
|
|
71
|
+
<button className="px-3 py-1 text-sm rounded-md bg-emerald-50 text-emerald-700">
|
|
72
|
+
Acción
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const Spinner = ({
|
|
2
|
+
size = 'medium',
|
|
3
|
+
variant = 'primary',
|
|
4
|
+
className = '',
|
|
5
|
+
...props
|
|
6
|
+
}) => {
|
|
7
|
+
const sizeClasses = {
|
|
8
|
+
small: 'w-4 h-4',
|
|
9
|
+
medium: 'w-8 h-8',
|
|
10
|
+
large: 'w-12 h-12',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const variantClasses = {
|
|
14
|
+
primary: 'text-blue-600',
|
|
15
|
+
secondary: 'text-gray-600',
|
|
16
|
+
white: 'text-white',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const classes = `animate-spin ${sizeClasses[size]} ${variantClasses[variant]} ${className}`;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<svg
|
|
23
|
+
className={classes}
|
|
24
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
25
|
+
fill="none"
|
|
26
|
+
viewBox="0 0 24 24"
|
|
27
|
+
{...props}
|
|
28
|
+
>
|
|
29
|
+
<circle
|
|
30
|
+
className="opacity-25"
|
|
31
|
+
cx="12"
|
|
32
|
+
cy="12"
|
|
33
|
+
r="10"
|
|
34
|
+
stroke="currentColor"
|
|
35
|
+
strokeWidth="4"
|
|
36
|
+
/>
|
|
37
|
+
<path
|
|
38
|
+
className="opacity-75"
|
|
39
|
+
fill="currentColor"
|
|
40
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
41
|
+
/>
|
|
42
|
+
</svg>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default Spinner;
|
|
47
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Spinner } from './Spinner';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Atoms/Spinner',
|
|
5
|
+
component: Spinner,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
argTypes: {
|
|
8
|
+
size: {
|
|
9
|
+
control: 'select',
|
|
10
|
+
options: ['small', 'medium', 'large'],
|
|
11
|
+
},
|
|
12
|
+
variant: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['primary', 'secondary', 'white'],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Default = {
|
|
20
|
+
args: {
|
|
21
|
+
size: 'medium',
|
|
22
|
+
variant: 'primary',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Small = {
|
|
27
|
+
args: {
|
|
28
|
+
size: 'small',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Large = {
|
|
33
|
+
args: {
|
|
34
|
+
size: 'large',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Secondary = {
|
|
39
|
+
args: {
|
|
40
|
+
variant: 'secondary',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const White = {
|
|
45
|
+
args: {
|
|
46
|
+
variant: 'white',
|
|
47
|
+
},
|
|
48
|
+
decorators: [
|
|
49
|
+
(Story) => (
|
|
50
|
+
<div className="bg-gray-800 p-4">
|
|
51
|
+
<Story />
|
|
52
|
+
</div>
|
|
53
|
+
),
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { Icon } from '../Icon/Icon';
|
|
3
|
+
|
|
4
|
+
export const Toast = ({
|
|
5
|
+
message,
|
|
6
|
+
variant = 'info',
|
|
7
|
+
duration = 5000,
|
|
8
|
+
onClose,
|
|
9
|
+
position = 'top-right',
|
|
10
|
+
className = '',
|
|
11
|
+
...props
|
|
12
|
+
}) => {
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (duration > 0 && onClose) {
|
|
15
|
+
const timer = setTimeout(() => {
|
|
16
|
+
onClose();
|
|
17
|
+
}, duration);
|
|
18
|
+
return () => clearTimeout(timer);
|
|
19
|
+
}
|
|
20
|
+
}, [duration, onClose]);
|
|
21
|
+
|
|
22
|
+
const variantClasses = {
|
|
23
|
+
info: 'bg-blue-50 border-blue-200 text-blue-800',
|
|
24
|
+
success: 'bg-green-50 border-green-200 text-green-800',
|
|
25
|
+
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800',
|
|
26
|
+
danger: 'bg-red-50 border-red-200 text-red-800',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const iconMap = {
|
|
30
|
+
info: 'InformationCircleIcon',
|
|
31
|
+
success: 'CheckCircleIcon',
|
|
32
|
+
warning: 'ExclamationTriangleIcon',
|
|
33
|
+
danger: 'XCircleIcon',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const positionClasses = {
|
|
37
|
+
'top-right': 'top-4 right-4',
|
|
38
|
+
'top-left': 'top-4 left-4',
|
|
39
|
+
'top-center': 'top-4 left-1/2 transform -translate-x-1/2',
|
|
40
|
+
'bottom-right': 'bottom-4 right-4',
|
|
41
|
+
'bottom-left': 'bottom-4 left-4',
|
|
42
|
+
'bottom-center': 'bottom-4 left-1/2 transform -translate-x-1/2',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div
|
|
47
|
+
className={`fixed ${positionClasses[position]} z-50 max-w-sm w-full ${className}`}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
<div
|
|
51
|
+
className={`border rounded-lg shadow-lg p-4 flex items-start ${variantClasses[variant]}`}
|
|
52
|
+
>
|
|
53
|
+
<Icon
|
|
54
|
+
name={iconMap[variant]}
|
|
55
|
+
className="mr-3 h-5 w-5 flex-shrink-0 mt-0.5"
|
|
56
|
+
/>
|
|
57
|
+
<div className="flex-1">
|
|
58
|
+
<p className="text-sm font-medium">{message}</p>
|
|
59
|
+
</div>
|
|
60
|
+
{onClose && (
|
|
61
|
+
<button
|
|
62
|
+
onClick={onClose}
|
|
63
|
+
className="ml-4 text-current opacity-50 hover:opacity-75"
|
|
64
|
+
>
|
|
65
|
+
<Icon name="XMarkIcon" className="h-5 w-5" />
|
|
66
|
+
</button>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default Toast;
|
|
74
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Toast } from './Toast';
|
|
3
|
+
import { Button } from '../Button/Button';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Atoms/Toast',
|
|
7
|
+
component: Toast,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const Info = {
|
|
12
|
+
render: () => {
|
|
13
|
+
const [show, setShow] = useState(false);
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<Button onClick={() => setShow(true)}>Mostrar Toast Info</Button>
|
|
17
|
+
{show && (
|
|
18
|
+
<Toast
|
|
19
|
+
message="Esta es una notificación informativa"
|
|
20
|
+
variant="info"
|
|
21
|
+
onClose={() => setShow(false)}
|
|
22
|
+
/>
|
|
23
|
+
)}
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Success = {
|
|
30
|
+
render: () => {
|
|
31
|
+
const [show, setShow] = useState(false);
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<Button onClick={() => setShow(true)}>Mostrar Toast Success</Button>
|
|
35
|
+
{show && (
|
|
36
|
+
<Toast
|
|
37
|
+
message="Operación completada exitosamente"
|
|
38
|
+
variant="success"
|
|
39
|
+
onClose={() => setShow(false)}
|
|
40
|
+
/>
|
|
41
|
+
)}
|
|
42
|
+
</>
|
|
43
|
+
);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Warning = {
|
|
48
|
+
render: () => {
|
|
49
|
+
const [show, setShow] = useState(false);
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
<Button onClick={() => setShow(true)}>Mostrar Toast Warning</Button>
|
|
53
|
+
{show && (
|
|
54
|
+
<Toast
|
|
55
|
+
message="Por favor revisa esta información"
|
|
56
|
+
variant="warning"
|
|
57
|
+
onClose={() => setShow(false)}
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
</>
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const Danger = {
|
|
66
|
+
render: () => {
|
|
67
|
+
const [show, setShow] = useState(false);
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
<Button onClick={() => setShow(true)}>Mostrar Toast Error</Button>
|
|
71
|
+
{show && (
|
|
72
|
+
<Toast
|
|
73
|
+
message="Ocurrió un error al procesar la solicitud"
|
|
74
|
+
variant="danger"
|
|
75
|
+
onClose={() => setShow(false)}
|
|
76
|
+
/>
|
|
77
|
+
)}
|
|
78
|
+
</>
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const AutoClose = {
|
|
84
|
+
render: () => {
|
|
85
|
+
const [show, setShow] = useState(false);
|
|
86
|
+
return (
|
|
87
|
+
<>
|
|
88
|
+
<Button onClick={() => setShow(true)}>Mostrar Toast (Auto-close 3s)</Button>
|
|
89
|
+
{show && (
|
|
90
|
+
<Toast
|
|
91
|
+
message="Este toast se cerrará automáticamente en 3 segundos"
|
|
92
|
+
variant="info"
|
|
93
|
+
duration={3000}
|
|
94
|
+
onClose={() => setShow(false)}
|
|
95
|
+
/>
|
|
96
|
+
)}
|
|
97
|
+
</>
|
|
98
|
+
);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|