anteriority-ui 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.
Files changed (199) hide show
  1. package/.github/workflows/ci.yml +31 -0
  2. package/.github/workflows/publish.yml +45 -0
  3. package/.npmrc.bak +1 -0
  4. package/.storybook/main.js +15 -0
  5. package/.storybook/preview.jsx +26 -0
  6. package/AnteriorityUI.md +2400 -0
  7. package/CLAUDE.md +91 -0
  8. package/README.md +182 -0
  9. package/assets/anteriorityUI/AnteriorityUI.logo.jpeg +0 -0
  10. package/assets/favicon/anteriorityUI.ico +0 -0
  11. package/common/api/client.js +43 -0
  12. package/common/storage/LocalStorage.js +13 -0
  13. package/common/styles/typography.css +5 -0
  14. package/common/styles/variables.css +192 -0
  15. package/common/theme/muiTheme.js +9 -0
  16. package/features/password-reset/api.js +39 -0
  17. package/features/user-profile/api.js +5 -0
  18. package/hooks/useAdminPasswordReset.js +133 -0
  19. package/index.js +57 -0
  20. package/package.json +57 -0
  21. package/pnpm-workspace.yaml +3 -0
  22. package/screens/components/AlertModal/AlertModal.jsx +259 -0
  23. package/screens/components/AlertModal/AlertModal.module.css +185 -0
  24. package/screens/components/AlertModal/AlertModal.stories.jsx +87 -0
  25. package/screens/components/Avatar/index.jsx +0 -0
  26. package/screens/components/Avatar/index.module.css +0 -0
  27. package/screens/components/Avatar/utils.js +0 -0
  28. package/screens/components/Badge/index.jsx +33 -0
  29. package/screens/components/Badge/index.module.css +18 -0
  30. package/screens/components/Badge/index.stories.jsx +40 -0
  31. package/screens/components/Barnner/index.jsx +21 -0
  32. package/screens/components/Barnner/index.module.css +33 -0
  33. package/screens/components/Barnner/index.stories.jsx +39 -0
  34. package/screens/components/Barnner/utils.js +0 -0
  35. package/screens/components/BlueLink/index.jsx +27 -0
  36. package/screens/components/BlueLink/index.module.css +11 -0
  37. package/screens/components/BlueLink/index.stories.jsx +29 -0
  38. package/screens/components/Breadcrumbs/index.jsx +62 -0
  39. package/screens/components/Breadcrumbs/index.module.css +158 -0
  40. package/screens/components/Breadcrumbs/index.stories.jsx +37 -0
  41. package/screens/components/Button/index.jsx +169 -0
  42. package/screens/components/Button/index.module.css +168 -0
  43. package/screens/components/Button/index.stories.jsx +71 -0
  44. package/screens/components/Button/utils.js +28 -0
  45. package/screens/components/CalendarComponent/CustomDatePicker.jsx +248 -0
  46. package/screens/components/CalendarComponent/CustomDatePicker.module.css +323 -0
  47. package/screens/components/CalendarComponent/CustomDatePicker.stories.jsx +45 -0
  48. package/screens/components/CalendarPicker/Constants.js +12 -0
  49. package/screens/components/CalendarPicker/index.jsx +263 -0
  50. package/screens/components/CalendarPicker/index.module.css +147 -0
  51. package/screens/components/CalendarPicker/index.stories.jsx +45 -0
  52. package/screens/components/CalendarPicker/utils.js +42 -0
  53. package/screens/components/CardV1/index.jsx +165 -0
  54. package/screens/components/CardV1/index.module.css +232 -0
  55. package/screens/components/CardV1/index.stories.jsx +62 -0
  56. package/screens/components/CardV1/utils.js +49 -0
  57. package/screens/components/ChatWindow/index.jsx +251 -0
  58. package/screens/components/ChatWindow/index.module.css +311 -0
  59. package/screens/components/ChatWindow/index.stories.jsx +62 -0
  60. package/screens/components/Checks/index.jsx +31 -0
  61. package/screens/components/Checks/index.module.css +32 -0
  62. package/screens/components/Checks/index.stories.jsx +32 -0
  63. package/screens/components/Container/index.jsx +36 -0
  64. package/screens/components/Container/index.module.css +24 -0
  65. package/screens/components/Container/index.stories.jsx +32 -0
  66. package/screens/components/CopyText/index.jsx +42 -0
  67. package/screens/components/CopyText/index.module.css +52 -0
  68. package/screens/components/CopyText/index.stories.jsx +24 -0
  69. package/screens/components/CountdownBar/constants.js +3 -0
  70. package/screens/components/CountdownBar/index.jsx +81 -0
  71. package/screens/components/CountdownBar/index.module.css +45 -0
  72. package/screens/components/CountdownBar/index.stories.jsx +43 -0
  73. package/screens/components/CountdownBar/utils.js +119 -0
  74. package/screens/components/DateTag/index.jsx +33 -0
  75. package/screens/components/DateTag/index.module.css +12 -0
  76. package/screens/components/DateTag/index.stories.jsx +29 -0
  77. package/screens/components/DesplegablePanel/constants.js +0 -0
  78. package/screens/components/DesplegablePanel/index.jsx +61 -0
  79. package/screens/components/DesplegablePanel/index.module.css +120 -0
  80. package/screens/components/DesplegablePanel/index.stories.jsx +44 -0
  81. package/screens/components/DesplegablePanel/utils.js +0 -0
  82. package/screens/components/DrawPanel/index.jsx +217 -0
  83. package/screens/components/DrawPanel/index.module.css +252 -0
  84. package/screens/components/DrawPanel/index.stories.jsx +66 -0
  85. package/screens/components/DrawPanel/utils.js +0 -0
  86. package/screens/components/Filter/index.jsx +105 -0
  87. package/screens/components/Filter/index.module.css +91 -0
  88. package/screens/components/Filter/index.stories.jsx +46 -0
  89. package/screens/components/Filter/utils.js +0 -0
  90. package/screens/components/FormControls/FormControls.module.css +86 -0
  91. package/screens/components/FormControls/index.jsx +51 -0
  92. package/screens/components/FormControls/index.stories.jsx +36 -0
  93. package/screens/components/Frame/index.jsx +54 -0
  94. package/screens/components/Frame/index.module.css +102 -0
  95. package/screens/components/Frame/index.stories.jsx +37 -0
  96. package/screens/components/Frame/utils.js +0 -0
  97. package/screens/components/GreenHighlight/index.jsx +11 -0
  98. package/screens/components/GreenHighlight/index.module.css +7 -0
  99. package/screens/components/GreenHighlight/index.stories.jsx +26 -0
  100. package/screens/components/GreenHighlight/utils.jsx +45 -0
  101. package/screens/components/HoursPicker/Constants.js +26 -0
  102. package/screens/components/HoursPicker/index.jsx +350 -0
  103. package/screens/components/HoursPicker/index.module.css +99 -0
  104. package/screens/components/HoursPicker/index.stories.jsx +44 -0
  105. package/screens/components/HoursPicker/utils.js +48 -0
  106. package/screens/components/InfoTooltip/index.jsx +59 -0
  107. package/screens/components/InfoTooltip/index.module.css +98 -0
  108. package/screens/components/InfoTooltip/index.stories.jsx +35 -0
  109. package/screens/components/Input/index.jsx +36 -0
  110. package/screens/components/Input/index.module.css +49 -0
  111. package/screens/components/Input/index.stories.jsx +37 -0
  112. package/screens/components/Input/utils.js +0 -0
  113. package/screens/components/Loading/index.jsx +76 -0
  114. package/screens/components/Loading/index.module.css +193 -0
  115. package/screens/components/Loading/index.stories.jsx +38 -0
  116. package/screens/components/Loading/utils.js +0 -0
  117. package/screens/components/MarkdownContent/index.jsx +16 -0
  118. package/screens/components/MarkdownContent/index.module.css +149 -0
  119. package/screens/components/MarkdownContent/index.stories.jsx +30 -0
  120. package/screens/components/MarkdownEditor/index.jsx +430 -0
  121. package/screens/components/MarkdownEditor/index.module.css +192 -0
  122. package/screens/components/MarkdownEditor/index.stories.jsx +50 -0
  123. package/screens/components/Material-UI/Components/InputWithIcon/index.jsx +87 -0
  124. package/screens/components/Material-UI/Components/InputWithIcon/index.stories.jsx +49 -0
  125. package/screens/components/Material-UI/Components/MenuPopover/index.jsx +117 -0
  126. package/screens/components/Material-UI/Components/MenuPopover/index.stories.jsx +36 -0
  127. package/screens/components/Material-UI/Components/MultilinePlaceholder/index.jsx +44 -0
  128. package/screens/components/Material-UI/Components/MultilinePlaceholder/index.stories.jsx +45 -0
  129. package/screens/components/Material-UI/Components/Paginador/index.jsx +79 -0
  130. package/screens/components/Material-UI/Components/Paginador/index.stories.jsx +49 -0
  131. package/screens/components/Material-UI/Components/Search/index.jsx +81 -0
  132. package/screens/components/Material-UI/Components/Search/index.stories.jsx +68 -0
  133. package/screens/components/Material-UI/Components/Selector/index.jsx +100 -0
  134. package/screens/components/Material-UI/Components/Selector/index.module.css +0 -0
  135. package/screens/components/Material-UI/Components/Selector/index.stories.jsx +52 -0
  136. package/screens/components/Material-UI/Components/Selector/utils.js +0 -0
  137. package/screens/components/Material-UI/Components/TextField/index.jsx +61 -0
  138. package/screens/components/Material-UI/Components/TextField/index.stories.jsx +53 -0
  139. package/screens/components/ModalTooltip/ModalTooltip.jsx +122 -0
  140. package/screens/components/ModalTooltip/ModalTooltip.module.css +65 -0
  141. package/screens/components/ModalTooltip/ModalTooltip.stories.jsx +39 -0
  142. package/screens/components/Notification/Error/ErrorMessage.jsx +30 -0
  143. package/screens/components/Notification/Error/ErrorMessage.module.css +57 -0
  144. package/screens/components/Notification/Error/ErrorMessage.stories.jsx +37 -0
  145. package/screens/components/PasswordResetPanel/index.jsx +325 -0
  146. package/screens/components/PasswordResetPanel/index.stories.jsx +26 -0
  147. package/screens/components/PlaceholderButton/index.jsx +169 -0
  148. package/screens/components/PlaceholderButton/index.module.css +162 -0
  149. package/screens/components/PlaceholderButton/index.stories.jsx +69 -0
  150. package/screens/components/PlaceholderButton/utils.js +42 -0
  151. package/screens/components/Profile/Avatar/index.jsx +125 -0
  152. package/screens/components/Profile/Avatar/index.module.css +86 -0
  153. package/screens/components/Profile/Avatar/index.stories.jsx +48 -0
  154. package/screens/components/Profile/Avatar/utils.js +18 -0
  155. package/screens/components/Profile/index.jsx +58 -0
  156. package/screens/components/Profile/index.module.css +0 -0
  157. package/screens/components/Profile/index.stories.jsx +38 -0
  158. package/screens/components/Profile/utils.js +0 -0
  159. package/screens/components/ScrollBar/index.jsx +62 -0
  160. package/screens/components/ScrollBar/index.module.css +78 -0
  161. package/screens/components/ScrollBar/index.stories.jsx +64 -0
  162. package/screens/components/ScrollBar/utils.js +127 -0
  163. package/screens/components/Sidebar/constants.js +16 -0
  164. package/screens/components/Sidebar/index.jsx +399 -0
  165. package/screens/components/Sidebar/index.module.css +405 -0
  166. package/screens/components/Sidebar/index.stories.jsx +86 -0
  167. package/screens/components/Sidebar/utils.js +75 -0
  168. package/screens/components/Skeleton/index.jsx +11 -0
  169. package/screens/components/Skeleton/index.module.css +26 -0
  170. package/screens/components/Skeleton/index.stories.jsx +42 -0
  171. package/screens/components/SubSidebarLayout/index.jsx +44 -0
  172. package/screens/components/SubSidebarLayout/index.module.css +80 -0
  173. package/screens/components/SubSidebarLayout/index.stories.jsx +51 -0
  174. package/screens/components/SummaryCard/index.jsx +50 -0
  175. package/screens/components/SummaryCard/index.module.css +30 -0
  176. package/screens/components/SummaryCard/index.stories.jsx +29 -0
  177. package/screens/components/Swich/constants.js +4 -0
  178. package/screens/components/Swich/index.jsx +85 -0
  179. package/screens/components/Swich/index.module.css +68 -0
  180. package/screens/components/Swich/index.stories.jsx +44 -0
  181. package/screens/components/Swich/utils.js +0 -0
  182. package/screens/components/TableA/index.jsx +156 -0
  183. package/screens/components/TableA/index.module.css +105 -0
  184. package/screens/components/TableA/index.stories.jsx +116 -0
  185. package/screens/components/TableA/utils.js +11 -0
  186. package/screens/components/TableB/index.jsx +222 -0
  187. package/screens/components/TableB/index.module.css +295 -0
  188. package/screens/components/TableB/index.stories.jsx +110 -0
  189. package/screens/components/TableB/utils.js +11 -0
  190. package/screens/components/ToggleCard/index.jsx +64 -0
  191. package/screens/components/ToggleCard/index.module.css +111 -0
  192. package/screens/components/ToggleCard/index.stories.jsx +49 -0
  193. package/screens/components/UserEditPopover/index.jsx +102 -0
  194. package/screens/components/UserEditPopover/index.module.css +97 -0
  195. package/screens/components/UserEditPopover/index.stories.jsx +49 -0
  196. package/scripts/build.mjs +129 -0
  197. package/scripts/check-case.mjs +127 -0
  198. package/scripts/verify-dist.mjs +45 -0
  199. package/vitest.config.js +36 -0
@@ -0,0 +1,80 @@
1
+ .layoutWrapper {
2
+ display: flex;
3
+ width: 100%;
4
+ gap: 1.5rem;
5
+ align-items: flex-start;
6
+ margin-top: 1rem;
7
+ }
8
+
9
+ .subSidebar {
10
+ width: 240px;
11
+ flex-shrink: 0;
12
+ background-color: var(--subsidebarlayout-bg, black);
13
+ border: 1px solid var(--gray-200, #e2e8f0);
14
+ border-radius: 12px;
15
+ padding: 1rem;
16
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
17
+ }
18
+
19
+ .menuList {
20
+ display: flex;
21
+ flex-direction: column;
22
+ gap: 0.5rem;
23
+ }
24
+
25
+ .menuItem {
26
+ display: flex;
27
+ align-items: center;
28
+ gap: 0.75rem;
29
+ padding: 0.75rem 1rem;
30
+ border: none;
31
+ background: transparent;
32
+ border-radius: 8px;
33
+ color: var(--gray-600, #4a5568);
34
+ font-weight: 800;
35
+ font-size: 0.95rem;
36
+ cursor: pointer;
37
+ transition: all 0.2s ease;
38
+ text-align: left;
39
+ }
40
+
41
+ .menuItem:hover {
42
+ background-color: var(--gray-50, #f8fafc);
43
+ color: var(--gray-900, #1a202c);
44
+ }
45
+
46
+ .menuItem.active {
47
+ background-color: var(--primary-color, #4299e1);
48
+ color: white;
49
+ }
50
+
51
+ .iconWrapper {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ }
56
+
57
+ .iconWrapper svg {
58
+ width: 18px;
59
+ height: 18px;
60
+ }
61
+
62
+ .menuItem.active .iconWrapper {
63
+ color: white;
64
+ }
65
+
66
+ .contentArea {
67
+ flex: 1;
68
+ min-width: 0;
69
+ }
70
+
71
+ @media (max-width: 768px) {
72
+ .layoutWrapper {
73
+ flex-direction: column;
74
+ }
75
+
76
+ .subSidebar {
77
+ width: 100%;
78
+ margin-bottom: 1rem;
79
+ }
80
+ }
@@ -0,0 +1,51 @@
1
+ import { useState } from 'react';
2
+ import { Settings, Users, FileText } from 'lucide-react';
3
+ import SubSidebarLayout from './index';
4
+
5
+ export default {
6
+ title: 'Components/SubSidebarLayout',
7
+ component: SubSidebarLayout,
8
+ };
9
+
10
+ const menuItems = [
11
+ { id: 'general', label: 'General', icon: <Settings size={16} /> },
12
+ { id: 'users', label: 'Usuarios', icon: <Users size={16} /> },
13
+ { id: 'docs', label: 'Documentos', icon: <FileText size={16} /> },
14
+ ];
15
+
16
+ const LayoutWithState = (args) => {
17
+ const [activeItemId, setActiveItemId] = useState(args.activeItemId ?? menuItems[0].id);
18
+ return (
19
+ <div style={{ height: 400 }}>
20
+ <SubSidebarLayout
21
+ {...args}
22
+ activeItemId={activeItemId}
23
+ onItemClick={(id) => setActiveItemId(id)}
24
+ />
25
+ </div>
26
+ );
27
+ };
28
+
29
+ export const Default = {
30
+ render: (args) => <LayoutWithState {...args} />,
31
+ args: {
32
+ menuItems,
33
+ children: <div style={{ padding: 24 }}>Selected section content goes here.</div>,
34
+ },
35
+ };
36
+
37
+ export const NoIcons = {
38
+ render: (args) => <LayoutWithState {...args} />,
39
+ args: {
40
+ menuItems: menuItems.map(({ id, label }) => ({ id, label })),
41
+ children: <div style={{ padding: 24 }}>Content without icons in the menu.</div>,
42
+ },
43
+ };
44
+
45
+ export const EmptyContent = {
46
+ render: (args) => <LayoutWithState {...args} />,
47
+ args: {
48
+ menuItems,
49
+ children: null,
50
+ },
51
+ };
@@ -0,0 +1,50 @@
1
+ import React, { useState } from 'react';
2
+ import { Sparkles, Copy, Check } from 'lucide-react';
3
+ import styles from './index.module.css';
4
+ import Button from '../Button/index';
5
+
6
+ const SummaryCard = ({ title, text, enableCopy = false, gradientStart, gradientEnd, headerColor }) => {
7
+ const [copied, setCopied] = useState(false);
8
+
9
+ const handleCopy = async () => {
10
+ if (!text) return;
11
+ try {
12
+ await navigator.clipboard.writeText(text);
13
+ setCopied(true);
14
+ setTimeout(() => setCopied(false), 2000);
15
+ } catch (err) {
16
+ console.error('Failed to copy text: ', err);
17
+ }
18
+ };
19
+
20
+ return (
21
+ <div
22
+ className={styles.iaSummaryCard}
23
+ style={{
24
+ ...(gradientStart ? { '--summarycard-gradient-start': gradientStart } : {}),
25
+ ...(gradientEnd ? { '--summarycard-gradient-end': gradientEnd } : {}),
26
+ ...(headerColor ? { '--summarycard-header-color': headerColor } : {}),
27
+ }}
28
+ >
29
+ <div className={styles.iaSummaryHeader}>
30
+ <Sparkles size={24} />
31
+ <h3>{title}</h3>
32
+ {enableCopy && (
33
+ <Button
34
+ onClick={handleCopy}
35
+ variant="ghost"
36
+ color={copied ? "green" : "#64748b"}
37
+ circle
38
+ size="small"
39
+ icon={copied ? Check : Copy}
40
+ style={{ marginLeft: 'auto' }}
41
+ ToolTip={copied ? "¡Copiado!" : "Copiar contenido"}
42
+ />
43
+ )}
44
+ </div>
45
+ <p className={styles.iaSummaryText}>{text}</p>
46
+ </div>
47
+ );
48
+ };
49
+
50
+ export default SummaryCard;
@@ -0,0 +1,30 @@
1
+ .iaSummaryCard {
2
+ background: linear-gradient(135deg, var(--summarycard-gradient-start, #fdf4ff) 0%, var(--summarycard-gradient-end, #f0fdf4) 100%);
3
+ border: 1px solid #e2e8f0;
4
+ border-radius: 12px;
5
+ padding: 1.5rem;
6
+ margin-top: 1.5rem;
7
+ }
8
+
9
+ .iaSummaryHeader {
10
+ display: flex;
11
+ align-items: center;
12
+ gap: 0.75rem;
13
+ color: var(--summarycard-header-color, #103529);
14
+ margin-bottom: 1rem;
15
+ }
16
+
17
+ .iaSummaryHeader h3 {
18
+ margin: 0;
19
+ font-size: 1.25rem;
20
+ font-weight: 700;
21
+ }
22
+
23
+ .iaSummaryText {
24
+ color: #334155;
25
+ line-height: 1.6;
26
+ font-size: 1rem;
27
+ margin: 0;
28
+ }
29
+
30
+
@@ -0,0 +1,29 @@
1
+ import SummaryCard from './index';
2
+
3
+ export default {
4
+ title: 'Components/SummaryCard',
5
+ component: SummaryCard,
6
+ };
7
+
8
+ export const Default = {
9
+ args: {
10
+ title: 'Resumen generado',
11
+ text: 'Este es un resumen de ejemplo generado automáticamente a partir del contenido analizado, mostrando los puntos clave más relevantes.',
12
+ },
13
+ };
14
+
15
+ export const WithCopyButton = {
16
+ args: {
17
+ title: 'Resumen con copia',
18
+ text: 'Este resumen incluye un botón para copiar el contenido al portapapeles con un solo clic.',
19
+ enableCopy: true,
20
+ },
21
+ };
22
+
23
+ export const LongText = {
24
+ args: {
25
+ title: 'Resumen extenso',
26
+ text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.',
27
+ enableCopy: true,
28
+ },
29
+ };
@@ -0,0 +1,4 @@
1
+ export const SWITCH_TEXTS = {
2
+ enabled: 'Habilitado',
3
+ disabled: 'Deshabilitado',
4
+ };
@@ -0,0 +1,85 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import styles from './index.module.css';
3
+ import ModalTooltip from '../ModalTooltip/ModalTooltip';
4
+ import { SWITCH_TEXTS } from './constants';
5
+
6
+ const Switch = ({
7
+ value = false,
8
+ onChange,
9
+ disabled = false,
10
+ activeColor = '#088d4f',
11
+ inactiveColor = '#919191',
12
+ thumbColor = '#ffffff',
13
+ className = '',
14
+ style = {}
15
+ }) => {
16
+ const [active, setActive] = useState(value);
17
+ const [ripples, setRipples] = useState([]);
18
+
19
+ useEffect(() => {
20
+ setActive(value);
21
+ }, [value]);
22
+
23
+ const handleClick = (e) => {
24
+ if (disabled) return;
25
+
26
+ const button = e.currentTarget;
27
+ const rect = button.getBoundingClientRect();
28
+ const size = Math.max(rect.width, rect.height);
29
+ const x = e.clientX - rect.left - size / 2;
30
+ const y = e.clientY - rect.top - size / 2;
31
+
32
+ const newRipple = { x, y, size, id: Date.now() };
33
+ setRipples((prev) => [...prev, newRipple]);
34
+
35
+ setTimeout(() => {
36
+ setRipples((prev) => prev.filter((ripple) => ripple.id !== newRipple.id));
37
+ }, 600);
38
+
39
+ const newActive = !active;
40
+ setActive(newActive);
41
+
42
+ if (onChange) {
43
+ onChange(newActive);
44
+ }
45
+ };
46
+
47
+ const statusClass = active ? styles.active : styles.inactive;
48
+
49
+ const dynamicStyle = {
50
+ ...style,
51
+ backgroundColor: active ? activeColor : inactiveColor,
52
+ };
53
+ const tooltipText = active ? SWITCH_TEXTS.enabled : SWITCH_TEXTS.disabled;
54
+
55
+ return (
56
+ <ModalTooltip text={tooltipText}>
57
+ <button
58
+ type="button"
59
+ role="switch"
60
+ aria-checked={active}
61
+ disabled={disabled}
62
+ className={`${styles.switchButton} ${statusClass} ${className}`}
63
+ style={dynamicStyle}
64
+ onClick={handleClick}
65
+ >
66
+ <div className={styles.thumb} style={{ backgroundColor: thumbColor }} />
67
+
68
+ {ripples.map((ripple) => (
69
+ <span
70
+ key={ripple.id}
71
+ className={styles.ripple}
72
+ style={{
73
+ left: ripple.x,
74
+ top: ripple.y,
75
+ width: ripple.size,
76
+ height: ripple.size
77
+ }}
78
+ />
79
+ ))}
80
+ </button>
81
+ </ModalTooltip>
82
+ );
83
+ };
84
+
85
+ export default Switch;
@@ -0,0 +1,68 @@
1
+ .switchButton {
2
+ position: relative;
3
+ display: inline-flex;
4
+ align-items: center;
5
+ width: 50px;
6
+ height: 24px;
7
+ border-radius: 12px;
8
+ border: none;
9
+ cursor: pointer;
10
+ padding: 0;
11
+ transition: background-color 0.3s ease;
12
+ overflow: hidden;
13
+ }
14
+
15
+ .switchButton:disabled {
16
+ opacity: 0.6;
17
+ cursor: not-allowed;
18
+ }
19
+
20
+ .active {
21
+ /* only used for thumb translation */
22
+ }
23
+
24
+ .inactive {
25
+ /* only used for thumb translation */
26
+ }
27
+
28
+ .thumb {
29
+ position: absolute;
30
+ top: 3px;
31
+ width: 18px;
32
+ height: 18px;
33
+ background-color: #ffffff;
34
+ border-radius: 50%;
35
+ transition: transform 0.2s ease;
36
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
37
+ pointer-events: none;
38
+ z-index: 2;
39
+ }
40
+
41
+ .active .thumb {
42
+ transform: translateX(29px);
43
+ }
44
+
45
+ .inactive .thumb {
46
+ transform: translateX(3px);
47
+ }
48
+
49
+ .ripple {
50
+ position: absolute;
51
+ border-radius: 50%;
52
+ transform: scale(0);
53
+ animation: ripple 0.6s linear;
54
+ background-color: rgba(255, 255, 255, 0.4);
55
+ pointer-events: none;
56
+ z-index: 1;
57
+ }
58
+
59
+ .inactive .ripple {
60
+ background-color: rgba(0, 0, 0, 0.2);
61
+ }
62
+
63
+ @keyframes ripple {
64
+ to {
65
+ transform: scale(4);
66
+ opacity: 0;
67
+ }
68
+ }
@@ -0,0 +1,44 @@
1
+ import { useState } from 'react';
2
+ import Switch from './index';
3
+
4
+ export default {
5
+ title: 'Components/Swich',
6
+ component: Switch,
7
+ };
8
+
9
+ const SwitchWithState = (args) => {
10
+ const [value, setValue] = useState(args.value ?? false);
11
+ return <Switch {...args} value={value} onChange={setValue} />;
12
+ };
13
+
14
+ export const Off = {
15
+ render: (args) => <SwitchWithState {...args} />,
16
+ args: {
17
+ value: false,
18
+ },
19
+ };
20
+
21
+ export const On = {
22
+ render: (args) => <SwitchWithState {...args} />,
23
+ args: {
24
+ value: true,
25
+ },
26
+ };
27
+
28
+ export const Disabled = {
29
+ render: (args) => <SwitchWithState {...args} />,
30
+ args: {
31
+ value: true,
32
+ disabled: true,
33
+ },
34
+ };
35
+
36
+ export const CustomColors = {
37
+ render: (args) => <SwitchWithState {...args} />,
38
+ args: {
39
+ value: true,
40
+ activeColor: '#2563eb',
41
+ inactiveColor: '#cbd5e1',
42
+ thumbColor: '#ffffff',
43
+ },
44
+ };
File without changes
@@ -0,0 +1,156 @@
1
+ import React from 'react';
2
+ import styles from './index.module.css';
3
+ import Skeleton from '../Skeleton/index';
4
+ import { AlertCircle, Inbox, Filter as FilterIcon } from 'lucide-react';
5
+ import Button from '../Button';
6
+ import ScrollBar from '../ScrollBar';
7
+ import { getNextFilterValue, getFilterOptionLabel } from './utils';
8
+
9
+ const TableA = (props) => {
10
+ const {
11
+ columns = [],
12
+ data = [],
13
+ keyExtractor,
14
+ rowClassName,
15
+ loading = false,
16
+ skeletonRows = 6,
17
+ error = null,
18
+ onRetry,
19
+ emptyIcon: EmptyIcon = Inbox,
20
+ emptyMessage = "No hay datos disponibles",
21
+ surfaceColor,
22
+ headerColor,
23
+ textColor,
24
+ headingColor,
25
+ mutedTextColor,
26
+ borderColor,
27
+ hoverColor,
28
+ rowBorderColor,
29
+ onRowClick,
30
+ filterIconColor,
31
+ filterActiveColor = '#10b981'
32
+ } = props;
33
+
34
+ const themeVars = {
35
+ '--tableA-surface': surfaceColor,
36
+ '--tableA-header': headerColor,
37
+ '--tableA-text': textColor,
38
+ '--tableA-heading-text': headingColor,
39
+ '--tableA-muted-text': mutedTextColor,
40
+ '--tableA-border': borderColor,
41
+ '--tableA-hover': hoverColor,
42
+ '--tableA-row-border': rowBorderColor
43
+ };
44
+
45
+ const handleCycleFilter = (filter) => {
46
+ if (!filter || !Array.isArray(filter.options) || filter.options.length === 0) return;
47
+ filter.onChange?.(getNextFilterValue(filter.options, filter.value));
48
+ };
49
+
50
+ return (
51
+ <ScrollBar horizontal vertical={false} className={styles.tableWrapper} style={themeVars}>
52
+ <table className={styles.table}>
53
+ <thead>
54
+ <tr>
55
+ {columns.map((col, idx) => (
56
+ <th
57
+ key={idx}
58
+ style={{
59
+ textAlign: col.align || 'left',
60
+ width: col.width,
61
+ minWidth: col.width,
62
+ maxWidth: col.width,
63
+ }}
64
+ >
65
+ {col.filter ? (
66
+ <div
67
+ className={styles.headerFilterWrap}
68
+ style={{ justifyContent: col.align === 'right' ? 'flex-end' : col.align === 'center' ? 'center' : 'flex-start' }}
69
+ >
70
+ <span>{col.header}</span>
71
+ <Button
72
+ circle
73
+ size="small"
74
+ variant={Button.VARIANTS.GHOST}
75
+ icon={FilterIcon}
76
+ color={col.filter.value ? filterActiveColor : filterIconColor}
77
+ className={styles.headerFilterBtn}
78
+ ToolTip={col.filter.tooltip || getFilterOptionLabel(col.filter.options, col.filter.value)}
79
+ onClick={() => handleCycleFilter(col.filter)}
80
+ />
81
+ </div>
82
+ ) : col.header}
83
+ </th>
84
+ ))}
85
+ </tr>
86
+ </thead>
87
+ <tbody>
88
+ {loading ? (
89
+ Array.from({ length: skeletonRows }).map((_, rowIdx) => (
90
+ <tr key={`skeleton-${rowIdx}`} className={styles.row}>
91
+ {columns.map((col, colIdx) => (
92
+ <td key={colIdx} style={{ textAlign: col.align || 'left', width: col.width, minWidth: col.width, maxWidth: col.width }}>
93
+ <Skeleton height="14px" width={col.align === 'right' || col.align === 'center' ? '60%' : '85%'} />
94
+ </td>
95
+ ))}
96
+ </tr>
97
+ ))
98
+ ) : error ? (
99
+ <tr>
100
+ <td colSpan={columns.length} style={{ padding: 0 }}>
101
+ <div className={styles.centerSection}>
102
+ <div className={styles.errorMessage}>
103
+ <AlertCircle size={32} />
104
+ <span>{error}</span>
105
+ </div>
106
+ {onRetry && (
107
+ <Button
108
+ type={"button"}
109
+ variant={Button.VARIANTS.PRIMARY}
110
+ size={Button.SIZES.LARGE}
111
+ color={Button.COLORS.GREEN}
112
+ onClick={onRetry}>Reintentar</Button>
113
+ )}
114
+ </div>
115
+ </td>
116
+ </tr>
117
+ ) : (!data || data.length === 0) ? (
118
+ <tr>
119
+ <td colSpan={columns.length} style={{ padding: '1.5rem' }}>
120
+ <div className={styles.emptyState}>
121
+ <EmptyIcon size={48} className={styles.emptyIcon} />
122
+ <p style={{ margin: 0 }}>{emptyMessage}</p>
123
+ </div>
124
+ </td>
125
+ </tr>
126
+ ) : (
127
+ data.map((row) => (
128
+ <tr
129
+ key={keyExtractor(row)}
130
+ className={`${styles.row} ${rowClassName ? rowClassName(row) : ''}`}
131
+ onClick={onRowClick ? () => onRowClick(row) : undefined}
132
+ style={onRowClick ? { cursor: 'pointer' } : undefined}
133
+ >
134
+ {columns.map((col, colIndex) => (
135
+ <td
136
+ key={colIndex}
137
+ style={{
138
+ textAlign: col.align || 'left',
139
+ width: col.width,
140
+ minWidth: col.width,
141
+ maxWidth: col.width,
142
+ }}
143
+ >
144
+ {col.render ? col.render(row) : row[col.accessor]}
145
+ </td>
146
+ ))}
147
+ </tr>
148
+ ))
149
+ )}
150
+ </tbody>
151
+ </table>
152
+ </ScrollBar>
153
+ );
154
+ };
155
+
156
+ export default TableA;