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
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "anima-ds-nucleus",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Anima Design System - A comprehensive React component library",
|
|
5
|
+
"author": "Nucleus Labs <ipvasallo@nucleus.com.ar>",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/NucleusNova/anima-ds.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"react",
|
|
13
|
+
"design system",
|
|
14
|
+
"ui",
|
|
15
|
+
"components",
|
|
16
|
+
"anima",
|
|
17
|
+
"nucleus"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/anima-ds.cjs.js",
|
|
21
|
+
"module": "./dist/anima-ds.esm.js",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"import": "./dist/anima-ds.esm.js",
|
|
25
|
+
"require": "./dist/anima-ds.cjs.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"src"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"dev": "vite",
|
|
34
|
+
"build": "vite build",
|
|
35
|
+
"build:app": "vite build --config vite.app.config.js",
|
|
36
|
+
"preview": "vite preview",
|
|
37
|
+
"storybook": "storybook dev -p 6006",
|
|
38
|
+
"build-storybook": "storybook build"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"react": "^19.2.0",
|
|
42
|
+
"react-dom": "^19.2.0",
|
|
43
|
+
"@chromatic-com/storybook": "^4.1.3",
|
|
44
|
+
"@storybook/addon-a11y": "^10.0.8",
|
|
45
|
+
"@storybook/addon-docs": "^10.0.8",
|
|
46
|
+
"@storybook/addon-onboarding": "^10.0.8",
|
|
47
|
+
"@storybook/addon-vitest": "^10.0.8",
|
|
48
|
+
"@storybook/react-vite": "^10.0.8",
|
|
49
|
+
"@tailwindcss/postcss": "^4.1.17",
|
|
50
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
51
|
+
"@vitest/browser-playwright": "^4.0.10",
|
|
52
|
+
"@vitest/coverage-v8": "^4.0.10",
|
|
53
|
+
"autoprefixer": "^10.4.22",
|
|
54
|
+
"playwright": "^1.56.1",
|
|
55
|
+
"postcss": "^8.5.6",
|
|
56
|
+
"storybook": "^10.0.8",
|
|
57
|
+
"tailwindcss": "^4.1.17",
|
|
58
|
+
"vite": "^7.2.2",
|
|
59
|
+
"vitest": "^4.0.10"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@emotion/react": "^11.14.0",
|
|
63
|
+
"@emotion/styled": "^11.14.1",
|
|
64
|
+
"@heroicons/react": "^2.1.5",
|
|
65
|
+
"@mui/material": "^7.3.5",
|
|
66
|
+
"@mui/x-data-grid": "^8.18.0",
|
|
67
|
+
"apexcharts": "^5.3.6",
|
|
68
|
+
"i18next": "^25.6.2",
|
|
69
|
+
"react-apexcharts": "^1.8.0",
|
|
70
|
+
"react-i18next": "^16.3.3"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"react": ">=18 <21",
|
|
74
|
+
"react-dom": ">=18 <21"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Icon } from '../Icon/Icon';
|
|
2
|
+
|
|
3
|
+
export const Alert = ({
|
|
4
|
+
variant = 'info',
|
|
5
|
+
title,
|
|
6
|
+
children,
|
|
7
|
+
onClose,
|
|
8
|
+
className = '',
|
|
9
|
+
...props
|
|
10
|
+
}) => {
|
|
11
|
+
const variantClasses = {
|
|
12
|
+
info: 'bg-blue-50 border-blue-200 text-blue-800',
|
|
13
|
+
success: 'bg-green-50 border-green-200 text-green-800',
|
|
14
|
+
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800',
|
|
15
|
+
danger: 'bg-red-50 border-red-200 text-red-800',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const iconMap = {
|
|
19
|
+
info: 'InformationCircleIcon',
|
|
20
|
+
success: 'CheckCircleIcon',
|
|
21
|
+
warning: 'ExclamationTriangleIcon',
|
|
22
|
+
danger: 'XCircleIcon',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const classes = `border rounded-lg p-4 ${variantClasses[variant]} ${className}`;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className={classes} role="alert" {...props}>
|
|
29
|
+
<div className="flex items-start">
|
|
30
|
+
<Icon
|
|
31
|
+
name={iconMap[variant]}
|
|
32
|
+
className="mr-3 h-5 w-5 flex-shrink-0"
|
|
33
|
+
/>
|
|
34
|
+
<div className="flex-1">
|
|
35
|
+
{title && <h3 className="font-semibold mb-1">{title}</h3>}
|
|
36
|
+
<div>{children}</div>
|
|
37
|
+
</div>
|
|
38
|
+
{onClose && (
|
|
39
|
+
<button
|
|
40
|
+
onClick={onClose}
|
|
41
|
+
className="ml-4 text-current opacity-50 hover:opacity-75"
|
|
42
|
+
>
|
|
43
|
+
<Icon name="XMarkIcon" className="h-5 w-5" />
|
|
44
|
+
</button>
|
|
45
|
+
)}
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default Alert;
|
|
52
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Alert } from './Alert';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Atoms/Alert',
|
|
5
|
+
component: Alert,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
argTypes: {
|
|
8
|
+
variant: {
|
|
9
|
+
control: 'select',
|
|
10
|
+
options: ['info', 'success', 'warning', 'danger'],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const Info = {
|
|
16
|
+
args: {
|
|
17
|
+
variant: 'info',
|
|
18
|
+
title: 'Information',
|
|
19
|
+
children: 'This is an informational alert message.',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const Success = {
|
|
24
|
+
args: {
|
|
25
|
+
variant: 'success',
|
|
26
|
+
title: 'Success',
|
|
27
|
+
children: 'Your action was completed successfully.',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const Warning = {
|
|
32
|
+
args: {
|
|
33
|
+
variant: 'warning',
|
|
34
|
+
title: 'Warning',
|
|
35
|
+
children: 'Please review this information carefully.',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Danger = {
|
|
40
|
+
args: {
|
|
41
|
+
variant: 'danger',
|
|
42
|
+
title: 'Error',
|
|
43
|
+
children: 'Something went wrong. Please try again.',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const WithoutTitle = {
|
|
48
|
+
args: {
|
|
49
|
+
variant: 'info',
|
|
50
|
+
children: 'This is an alert without a title.',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Closable = {
|
|
55
|
+
args: {
|
|
56
|
+
variant: 'info',
|
|
57
|
+
title: 'Closable Alert',
|
|
58
|
+
children: 'This alert can be closed.',
|
|
59
|
+
onClose: () => alert('Alert closed'),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Icon } from '../Icon/Icon';
|
|
2
|
+
|
|
3
|
+
export const Avatar = ({
|
|
4
|
+
src,
|
|
5
|
+
alt = '',
|
|
6
|
+
name,
|
|
7
|
+
size = 'medium',
|
|
8
|
+
variant = 'circle',
|
|
9
|
+
className = '',
|
|
10
|
+
...props
|
|
11
|
+
}) => {
|
|
12
|
+
const sizeClasses = {
|
|
13
|
+
small: 'w-8 h-8 text-xs',
|
|
14
|
+
medium: 'w-10 h-10 text-sm',
|
|
15
|
+
large: 'w-12 h-12 text-base',
|
|
16
|
+
xl: 'w-16 h-16 text-lg',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const variantClasses = {
|
|
20
|
+
circle: 'rounded-full',
|
|
21
|
+
square: 'rounded-lg',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const getInitials = (name) => {
|
|
25
|
+
if (!name) return '';
|
|
26
|
+
const parts = name.trim().split(' ');
|
|
27
|
+
if (parts.length === 1) return parts[0][0].toUpperCase();
|
|
28
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const baseClasses = `inline-flex items-center justify-center bg-gray-200 text-gray-600 font-medium ${sizeClasses[size]} ${variantClasses[variant]} ${className}`;
|
|
32
|
+
|
|
33
|
+
if (src) {
|
|
34
|
+
return (
|
|
35
|
+
<img
|
|
36
|
+
src={src}
|
|
37
|
+
alt={alt || name}
|
|
38
|
+
className={`${sizeClasses[size]} ${variantClasses[variant]} object-cover ${className}`}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (name) {
|
|
45
|
+
return (
|
|
46
|
+
<div className={baseClasses} {...props}>
|
|
47
|
+
{getInitials(name)}
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className={baseClasses} {...props}>
|
|
54
|
+
<Icon name="UserIcon" className="w-1/2 h-1/2" />
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default Avatar;
|
|
60
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Avatar } from './Avatar';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Atoms/Avatar',
|
|
5
|
+
component: Avatar,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
argTypes: {
|
|
8
|
+
size: {
|
|
9
|
+
control: 'select',
|
|
10
|
+
options: ['small', 'medium', 'large', 'xl'],
|
|
11
|
+
},
|
|
12
|
+
variant: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['circle', 'square'],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const WithImage = {
|
|
20
|
+
args: {
|
|
21
|
+
src: 'https://i.pravatar.cc/150?img=1',
|
|
22
|
+
alt: 'User avatar',
|
|
23
|
+
size: 'medium',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const WithInitials = {
|
|
28
|
+
args: {
|
|
29
|
+
name: 'John Doe',
|
|
30
|
+
size: 'medium',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const WithoutName = {
|
|
35
|
+
args: {
|
|
36
|
+
size: 'medium',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Small = {
|
|
41
|
+
args: {
|
|
42
|
+
name: 'Jane Smith',
|
|
43
|
+
size: 'small',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Large = {
|
|
48
|
+
args: {
|
|
49
|
+
name: 'Bob Johnson',
|
|
50
|
+
size: 'large',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Square = {
|
|
55
|
+
args: {
|
|
56
|
+
name: 'Alice Williams',
|
|
57
|
+
variant: 'square',
|
|
58
|
+
size: 'medium',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const Badge = ({
|
|
2
|
+
children,
|
|
3
|
+
variant = 'default',
|
|
4
|
+
size = 'medium',
|
|
5
|
+
className = '',
|
|
6
|
+
...props
|
|
7
|
+
}) => {
|
|
8
|
+
const baseClasses = 'inline-flex items-center font-medium rounded-full';
|
|
9
|
+
|
|
10
|
+
const variantClasses = {
|
|
11
|
+
default: 'bg-gray-100 text-gray-800',
|
|
12
|
+
primary: 'bg-blue-100 text-blue-800',
|
|
13
|
+
success: 'bg-green-100 text-green-800',
|
|
14
|
+
warning: 'bg-yellow-100 text-yellow-800',
|
|
15
|
+
danger: 'bg-red-100 text-red-800',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const sizeClasses = {
|
|
19
|
+
small: 'px-2 py-0.5 text-xs',
|
|
20
|
+
medium: 'px-2.5 py-1 text-sm',
|
|
21
|
+
large: 'px-3 py-1.5 text-base',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${className}`;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<span className={classes} {...props}>
|
|
28
|
+
{children}
|
|
29
|
+
</span>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default Badge;
|
|
34
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Badge } from './Badge';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Atoms/Badge',
|
|
5
|
+
component: Badge,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
argTypes: {
|
|
8
|
+
variant: {
|
|
9
|
+
control: 'select',
|
|
10
|
+
options: ['default', 'primary', 'success', 'warning', 'danger'],
|
|
11
|
+
},
|
|
12
|
+
size: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['small', 'medium', 'large'],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Default = {
|
|
20
|
+
args: {
|
|
21
|
+
children: 'Badge',
|
|
22
|
+
variant: 'default',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Primary = {
|
|
27
|
+
args: {
|
|
28
|
+
children: 'Primary',
|
|
29
|
+
variant: 'primary',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const Success = {
|
|
34
|
+
args: {
|
|
35
|
+
children: 'Success',
|
|
36
|
+
variant: 'success',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Small = {
|
|
41
|
+
args: {
|
|
42
|
+
children: 'Small',
|
|
43
|
+
variant: 'primary',
|
|
44
|
+
size: 'small',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const Large = {
|
|
49
|
+
args: {
|
|
50
|
+
children: 'Large Badge',
|
|
51
|
+
variant: 'primary',
|
|
52
|
+
size: 'large',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Button Component
|
|
5
|
+
*
|
|
6
|
+
* Componente de botón reutilizable que sigue el design system de Anima DS.
|
|
7
|
+
* Soporta múltiples tipos (Primary, Secondary, Ghost), colores (Teal, Grape, Honey) y tamaños (Small, Default, Large).
|
|
8
|
+
* Los estados deshabilitados se manejan con el prop disabled.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} texto - Texto a mostrar en el botón (alias de children)
|
|
11
|
+
* @param {React.ReactNode} children - Contenido del botón
|
|
12
|
+
* @param {string} tipo - Tipo del botón: 'Primary', 'Secondary', 'Ghost' (alias de variant)
|
|
13
|
+
* @param {string} variant - Alias de tipo para mayor compatibilidad
|
|
14
|
+
* @param {string} color - Color del botón: 'Teal', 'Grape', 'Honey'
|
|
15
|
+
* @param {string} tamaño - Tamaño del botón: 'Small', 'Default', 'Large'
|
|
16
|
+
* @param {function} onClick - Función a ejecutar cuando se hace click
|
|
17
|
+
* @param {string} type - Tipo de botón HTML (button, submit, reset)
|
|
18
|
+
* @param {boolean} disabled - Estado deshabilitado
|
|
19
|
+
* @param {string} className - Clases CSS adicionales
|
|
20
|
+
* @param {object} props - Props adicionales del botón HTML
|
|
21
|
+
*/
|
|
22
|
+
export const Button = ({
|
|
23
|
+
texto,
|
|
24
|
+
children,
|
|
25
|
+
tipo,
|
|
26
|
+
variant,
|
|
27
|
+
color = 'Teal',
|
|
28
|
+
tamaño = 'Default',
|
|
29
|
+
onClick,
|
|
30
|
+
type = 'button',
|
|
31
|
+
disabled = false,
|
|
32
|
+
className = '',
|
|
33
|
+
...props
|
|
34
|
+
}) => {
|
|
35
|
+
// Normalizar props para compatibilidad:
|
|
36
|
+
// - permitir usar variant además de tipo
|
|
37
|
+
// - permitir usar children además de texto
|
|
38
|
+
const resolvedTipo = tipo || variant || 'Primary';
|
|
39
|
+
const resolvedContent = children != null ? children : texto;
|
|
40
|
+
// Colores del design system
|
|
41
|
+
const COLOR_PALETTE = {
|
|
42
|
+
Teal: '#2D5C63',
|
|
43
|
+
Grape: '#6D3856', // morado/plum profundo
|
|
44
|
+
Honey: '#E8B061', // naranja/ámbar claro
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Color de texto para Primary según el color del botón
|
|
48
|
+
const PRIMARY_TEXT_COLOR = {
|
|
49
|
+
Teal: '#ffffff',
|
|
50
|
+
Grape: '#ffffff',
|
|
51
|
+
Honey: '#374151', // gray-700 (gris oscuro/carbón)
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Color para Secondary según el color del botón (puede diferir del Primary)
|
|
55
|
+
const SECONDARY_COLOR = {
|
|
56
|
+
Teal: COLOR_PALETTE.Teal,
|
|
57
|
+
Grape: COLOR_PALETTE.Grape,
|
|
58
|
+
Honey: '#80501F', // marrón medio-oscuro para Secondary
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Color para Ghost según el color del botón
|
|
62
|
+
const GHOST_COLOR = {
|
|
63
|
+
Teal: COLOR_PALETTE.Teal,
|
|
64
|
+
Grape: COLOR_PALETTE.Grape,
|
|
65
|
+
Honey: '#80501F', // marrón medio-oscuro para Ghost (igual que Secondary)
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Color de texto para Ghost según el color del botón
|
|
69
|
+
const GHOST_TEXT_COLOR = {
|
|
70
|
+
Teal: COLOR_PALETTE.Teal,
|
|
71
|
+
Grape: COLOR_PALETTE.Grape,
|
|
72
|
+
Honey: '#6E4D11', // marrón oscuro para Ghost
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Colores para estados deshabilitados (grises)
|
|
76
|
+
const DISABLED_COLORS = {
|
|
77
|
+
border: '#D1D5DB', // gray-300
|
|
78
|
+
text: '#9CA3AF', // gray-400
|
|
79
|
+
background: '#F3F4F6', // gray-100
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const BUTTON_COLOR = COLOR_PALETTE[color] || COLOR_PALETTE.Teal;
|
|
83
|
+
|
|
84
|
+
// Estado para manejar hover
|
|
85
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
86
|
+
|
|
87
|
+
// Determinar si el botón está deshabilitado
|
|
88
|
+
const isDisabled = disabled;
|
|
89
|
+
|
|
90
|
+
// Clases base comunes a todos los botones
|
|
91
|
+
const baseClasses = 'font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2';
|
|
92
|
+
|
|
93
|
+
// Clases de tamaño con padding y texto
|
|
94
|
+
const sizeClasses = {
|
|
95
|
+
Small: 'px-3 py-1.5 text-sm rounded-md',
|
|
96
|
+
Default: 'px-4 py-2 text-base rounded-lg',
|
|
97
|
+
Large: 'px-6 py-3 text-lg rounded-lg',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Función helper para convertir hex a rgba
|
|
101
|
+
const hexToRgba = (hex, alpha = 1) => {
|
|
102
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
103
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
104
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
105
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Estilos inline con colores según el tipo y color
|
|
109
|
+
const getInlineStyles = () => {
|
|
110
|
+
const styles = {};
|
|
111
|
+
|
|
112
|
+
// Si está deshabilitado, usar colores grises
|
|
113
|
+
if (isDisabled) {
|
|
114
|
+
switch (resolvedTipo) {
|
|
115
|
+
case 'Primary':
|
|
116
|
+
styles.backgroundColor = DISABLED_COLORS.background;
|
|
117
|
+
styles.color = DISABLED_COLORS.text;
|
|
118
|
+
break;
|
|
119
|
+
|
|
120
|
+
case 'Secondary':
|
|
121
|
+
styles.borderColor = DISABLED_COLORS.border;
|
|
122
|
+
styles.color = DISABLED_COLORS.text;
|
|
123
|
+
styles.borderWidth = '1px';
|
|
124
|
+
styles.borderStyle = 'solid';
|
|
125
|
+
styles.backgroundColor = 'transparent';
|
|
126
|
+
break;
|
|
127
|
+
|
|
128
|
+
case 'Ghost':
|
|
129
|
+
styles.color = DISABLED_COLORS.text;
|
|
130
|
+
styles.backgroundColor = 'transparent';
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
return styles;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Estilos para estados habilitados
|
|
137
|
+
switch (resolvedTipo) {
|
|
138
|
+
case 'Primary':
|
|
139
|
+
styles.backgroundColor = BUTTON_COLOR;
|
|
140
|
+
styles.color = PRIMARY_TEXT_COLOR[color] || '#ffffff';
|
|
141
|
+
if (isHovered) {
|
|
142
|
+
styles.opacity = '0.9';
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
|
|
146
|
+
case 'Secondary':
|
|
147
|
+
const secondaryColor = SECONDARY_COLOR[color] || BUTTON_COLOR;
|
|
148
|
+
styles.borderColor = secondaryColor;
|
|
149
|
+
styles.color = secondaryColor;
|
|
150
|
+
styles.borderWidth = '1px';
|
|
151
|
+
styles.borderStyle = 'solid';
|
|
152
|
+
if (isHovered) {
|
|
153
|
+
styles.backgroundColor = hexToRgba(secondaryColor, 0.1);
|
|
154
|
+
} else {
|
|
155
|
+
// Fondo blanco para Honey y Grape Secondary, transparente para los demás
|
|
156
|
+
styles.backgroundColor = (color === 'Honey' || color === 'Grape') ? '#ffffff' : 'transparent';
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
|
|
160
|
+
case 'Ghost':
|
|
161
|
+
const ghostColor = GHOST_COLOR[color] || BUTTON_COLOR;
|
|
162
|
+
const ghostTextColor = GHOST_TEXT_COLOR[color] || BUTTON_COLOR;
|
|
163
|
+
|
|
164
|
+
// Para Honey, Ghost tiene fondo blanco y texto oscuro, sin borde
|
|
165
|
+
if (color === 'Honey') {
|
|
166
|
+
styles.color = ghostTextColor;
|
|
167
|
+
styles.backgroundColor = '#ffffff';
|
|
168
|
+
if (isHovered) {
|
|
169
|
+
styles.backgroundColor = hexToRgba(ghostColor, 0.1);
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
// Para otros colores, Ghost es sin borde
|
|
173
|
+
styles.color = ghostTextColor;
|
|
174
|
+
styles.backgroundColor = isHovered
|
|
175
|
+
? hexToRgba(ghostColor, 0.1)
|
|
176
|
+
: 'transparent';
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return styles;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Clases según el tipo/variante
|
|
185
|
+
const getVariantClasses = () => {
|
|
186
|
+
if (isDisabled) {
|
|
187
|
+
switch (resolvedTipo) {
|
|
188
|
+
case 'Primary':
|
|
189
|
+
return {
|
|
190
|
+
base: 'active:opacity-80',
|
|
191
|
+
disabled: 'cursor-not-allowed',
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
case 'Secondary':
|
|
195
|
+
return {
|
|
196
|
+
base: 'border active:opacity-80',
|
|
197
|
+
disabled: 'cursor-not-allowed',
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
case 'Ghost':
|
|
201
|
+
return {
|
|
202
|
+
base: 'active:opacity-80',
|
|
203
|
+
disabled: 'cursor-not-allowed',
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
default:
|
|
207
|
+
return {
|
|
208
|
+
base: 'active:opacity-80',
|
|
209
|
+
disabled: 'cursor-not-allowed',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
switch (resolvedTipo) {
|
|
215
|
+
case 'Primary':
|
|
216
|
+
// Para Honey, el texto no debe ser blanco
|
|
217
|
+
const primaryTextClass = color === 'Honey' ? '' : 'text-white';
|
|
218
|
+
return {
|
|
219
|
+
base: `${primaryTextClass} active:opacity-80`.trim(),
|
|
220
|
+
disabled: 'opacity-50 cursor-not-allowed',
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
case 'Secondary':
|
|
224
|
+
return {
|
|
225
|
+
base: 'border active:opacity-80',
|
|
226
|
+
disabled: 'opacity-50 cursor-not-allowed',
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
case 'Ghost':
|
|
230
|
+
return {
|
|
231
|
+
base: 'active:opacity-80',
|
|
232
|
+
disabled: 'opacity-50 cursor-not-allowed',
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
default:
|
|
236
|
+
return {
|
|
237
|
+
base: 'text-white active:opacity-80',
|
|
238
|
+
disabled: 'opacity-50 cursor-not-allowed',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const variantClasses = getVariantClasses();
|
|
244
|
+
const sizeClass = sizeClasses[tamaño] || sizeClasses.Default;
|
|
245
|
+
const inlineStyles = getInlineStyles();
|
|
246
|
+
|
|
247
|
+
// Construir clases finales
|
|
248
|
+
const classes = `
|
|
249
|
+
${baseClasses}
|
|
250
|
+
${sizeClass}
|
|
251
|
+
${variantClasses.base}
|
|
252
|
+
${isDisabled ? variantClasses.disabled : 'cursor-pointer'}
|
|
253
|
+
${className}
|
|
254
|
+
`.trim().replace(/\s+/g, ' ');
|
|
255
|
+
|
|
256
|
+
// Manejar el click - no ejecutar si está deshabilitado
|
|
257
|
+
const handleClick = (e) => {
|
|
258
|
+
if (!isDisabled && onClick) {
|
|
259
|
+
onClick(e);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<button
|
|
265
|
+
type={type}
|
|
266
|
+
className={classes}
|
|
267
|
+
style={inlineStyles}
|
|
268
|
+
disabled={isDisabled}
|
|
269
|
+
onClick={handleClick}
|
|
270
|
+
onMouseEnter={() => !isDisabled && setIsHovered(true)}
|
|
271
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
272
|
+
{...props}
|
|
273
|
+
>
|
|
274
|
+
{resolvedContent}
|
|
275
|
+
</button>
|
|
276
|
+
);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
export default Button;
|
|
281
|
+
|