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,102 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import Popover from '@mui/material/Popover';
3
+ import InputWithIcon from '../Material-UI/Components/InputWithIcon/index';
4
+ import { CircleUser, Check, X } from 'lucide-react';
5
+ import styles from './index.module.css';
6
+ import { updateUserName } from '../../../features/user-profile/api';
7
+ import { getUserId } from '../../../common/storage/LocalStorage';
8
+ import Button from '../Button/index'
9
+
10
+ const UserEditPopover = ({ open, anchorEl, onClose, currentName, onSuccess, bgColor, saveColor, cancelColor }) => {
11
+ const [tempUserName, setTempUserName] = useState('');
12
+ const [loading, setLoading] = useState(false);
13
+
14
+ useEffect(() => {
15
+ if (open) {
16
+ setTempUserName(currentName || '');
17
+ }
18
+ }, [open, currentName]);
19
+
20
+ const handleSave = async () => {
21
+ if (!tempUserName.trim()) return;
22
+ setLoading(true);
23
+ try {
24
+ const idUser = getUserId();
25
+ await updateUserName({
26
+ idUser: Number(idUser),
27
+ newUserName: tempUserName
28
+ });
29
+ onSuccess(tempUserName);
30
+ } catch (error) {
31
+ console.error('Error al actualizar nombre', error);
32
+ // Actualizar localmente si falla para pruebas
33
+ onSuccess(tempUserName);
34
+ } finally {
35
+ setLoading(false);
36
+ onClose();
37
+ }
38
+ };
39
+
40
+ return (
41
+ <Popover
42
+ open={open}
43
+ anchorEl={anchorEl}
44
+ onClose={onClose}
45
+ anchorOrigin={{
46
+ vertical: 'bottom',
47
+ horizontal: 'right',
48
+ }}
49
+ transformOrigin={{
50
+ vertical: 'top',
51
+ horizontal: 'right',
52
+ }}
53
+ slotProps={{
54
+ paper: {
55
+ className: styles.popoverPaper,
56
+ style: {
57
+ ...(bgColor ? { '--usereditpopover-bg': bgColor } : {}),
58
+ ...(saveColor ? { '--usereditpopover-save': saveColor } : {}),
59
+ ...(cancelColor ? { '--usereditpopover-cancel': cancelColor } : {}),
60
+ }
61
+ }
62
+ }}
63
+ >
64
+ <div className={styles.container}>
65
+ <h4 className={styles.header}>Editar Nombre</h4>
66
+ <div className={styles.inputWrapper}>
67
+ <InputWithIcon
68
+ value={tempUserName}
69
+ onChange={(e) => setTempUserName(e.target.value)}
70
+ icon={CircleUser}
71
+ variant="standard"
72
+ placeholder="Tu nuevo nombre..."
73
+ autoFocus
74
+ fullWidth
75
+ />
76
+ </div>
77
+ <div className={styles.actions}>
78
+ <Button
79
+ className={styles.btnCancel}
80
+ onClick={onClose}
81
+ disabled={loading}
82
+ borderColor="var(--border-gray-low)"
83
+
84
+ >
85
+ <X size={14} style={{ marginRight: '4px', verticalAlign: 'middle' }} />
86
+ Cancelar
87
+ </Button>
88
+ <Button
89
+ className={styles.btnSave}
90
+ onClick={handleSave}
91
+ disabled={loading}
92
+ >
93
+ <Check size={14} style={{ marginRight: '4px', verticalAlign: 'middle' }} />
94
+ {loading ? 'Guardar' : 'Guardar'}
95
+ </Button>
96
+ </div>
97
+ </div>
98
+ </Popover>
99
+ );
100
+ };
101
+
102
+ export default UserEditPopover;
@@ -0,0 +1,97 @@
1
+ .popoverPaper {
2
+ padding: 16px;
3
+ border-radius: 12px;
4
+ background-color: var(--usereditpopover-bg, #ffffff);
5
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
6
+ border: 1px solid #e2e8f0;
7
+ margin-top: 8px;
8
+ min-width: 250px;
9
+ }
10
+
11
+ .container {
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: 12px;
15
+ }
16
+
17
+ .header {
18
+ font-size: 0.95rem;
19
+ font-weight: 600;
20
+ color: #1e293b;
21
+ margin: 0;
22
+ }
23
+
24
+ .inputWrapper {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 8px;
28
+ }
29
+
30
+ .inputWrapper :global(.MuiInput-root) {
31
+ color: #1e293b !important;
32
+ font-size: 0.95rem !important;
33
+ padding: 6px 8px !important;
34
+ background: #f8fafc !important;
35
+ border-radius: 6px !important;
36
+ border: 1px solid #cbd5e1 !important;
37
+ }
38
+
39
+ .inputWrapper :global(.MuiInput-root):before,
40
+ .inputWrapper :global(.MuiInput-root):after {
41
+ display: none !important;
42
+ }
43
+
44
+ .inputWrapper :global(.MuiInputAdornment-root) svg {
45
+ color: #64748b !important;
46
+ }
47
+
48
+ .actions {
49
+ display: flex;
50
+ justify-content: flex-end;
51
+ gap: 8px;
52
+ margin-top: 4px;
53
+ }
54
+
55
+ .btnSave {
56
+ background: var(--usereditpopover-save, #10b981);
57
+ color: white;
58
+ border: none;
59
+ border-radius: 6px;
60
+ padding: 6px 12px;
61
+ cursor: pointer;
62
+ font-weight: 600;
63
+ font-size: 0.85rem;
64
+ transition: background 0.2s;
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 4px;
68
+ }
69
+
70
+ .btnSave:hover:not(:disabled) {
71
+ background: var(--usereditpopover-save-hover, #059669);
72
+ }
73
+
74
+ .btnSave:disabled {
75
+ opacity: 0.7;
76
+ cursor: not-allowed;
77
+ }
78
+
79
+ .btnCancel {
80
+ background: var(--usereditpopover-cancel-bg, #f1f5f9);
81
+ color: var(--usereditpopover-cancel, #64748b);
82
+ border: 1px solid #cbd5e1;
83
+ border-radius: 6px;
84
+ padding: 6px 12px;
85
+ cursor: pointer;
86
+ font-weight: 600;
87
+ font-size: 0.85rem;
88
+ transition: all 0.2s;
89
+ display: flex;
90
+ align-items: center;
91
+ gap: 4px;
92
+ }
93
+
94
+ .btnCancel:hover {
95
+ background: var(--usereditpopover-cancel-hover-bg, #e2e8f0);
96
+ color: var(--usereditpopover-cancel-hover, #0f172a);
97
+ }
@@ -0,0 +1,49 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import UserEditPopover from './index';
3
+
4
+ export default {
5
+ title: 'Components/UserEditPopover',
6
+ component: UserEditPopover,
7
+ };
8
+
9
+ // UserEditPopover uses a MUI Popover, which needs a real DOM node as anchorEl.
10
+ // This wrapper renders a trigger button, stores its DOM node in state once
11
+ // mounted, and passes that node down as anchorEl so the popover has something
12
+ // to anchor to when `open` is true.
13
+ const AnchoredPopover = (args) => {
14
+ const anchorRef = useRef(null);
15
+ const [anchorEl, setAnchorEl] = useState(null);
16
+
17
+ useEffect(() => {
18
+ setAnchorEl(anchorRef.current);
19
+ }, []);
20
+
21
+ return (
22
+ <div style={{ padding: '60px' }}>
23
+ <button ref={anchorRef} type="button">
24
+ Editar nombre
25
+ </button>
26
+ <UserEditPopover {...args} anchorEl={anchorEl} />
27
+ </div>
28
+ );
29
+ };
30
+
31
+ export const Open = {
32
+ render: (args) => <AnchoredPopover {...args} />,
33
+ args: {
34
+ open: true,
35
+ currentName: 'Ana Gomez',
36
+ onClose: () => console.log('popover closed'),
37
+ onSuccess: (name) => console.log('saved name', name),
38
+ },
39
+ };
40
+
41
+ export const EmptyName = {
42
+ render: (args) => <AnchoredPopover {...args} />,
43
+ args: {
44
+ open: true,
45
+ currentName: '',
46
+ onClose: () => console.log('popover closed'),
47
+ onSuccess: (name) => console.log('saved name', name),
48
+ },
49
+ };
@@ -0,0 +1,129 @@
1
+ // Compila la librería para publicar: transpila JSX -> JS (import/export ESM intactos)
2
+ // y copia los assets (CSS Modules, imágenes, etc.) manteniendo la MISMA estructura de
3
+ // carpetas que el código fuente, para que los subpath imports documentados en el README
4
+ // (ej. 'anteriority-ui/screens/components/Button', 'anteriority-ui/common/theme/muiTheme')
5
+ // sigan resolviendo igual una vez instalada la librería, sin exponer JSX sin compilar.
6
+ import { build } from 'esbuild';
7
+ import { cp, mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises';
8
+ import path from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+
11
+ const rootDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
12
+ const outDir = path.join(rootDir, 'dist');
13
+ const sourceDirs = ['screens', 'common', 'features', 'hooks'];
14
+
15
+ const isSourceFile = (file) => /\.(jsx|js)$/.test(file) && !/\.stories\.jsx$/.test(file);
16
+
17
+ async function collectFiles(dir) {
18
+ const entries = await readdir(dir, { withFileTypes: true });
19
+ const files = [];
20
+ for (const entry of entries) {
21
+ const full = path.join(dir, entry.name);
22
+ if (entry.isDirectory()) {
23
+ files.push(...(await collectFiles(full)));
24
+ } else {
25
+ files.push(full);
26
+ }
27
+ }
28
+ return files;
29
+ }
30
+
31
+ async function main() {
32
+ await rm(outDir, { recursive: true, force: true });
33
+ await mkdir(outDir, { recursive: true });
34
+
35
+ const allFiles = [path.join(rootDir, 'index.js')];
36
+ for (const dir of sourceDirs) {
37
+ const abs = path.join(rootDir, dir);
38
+ try {
39
+ await stat(abs);
40
+ } catch {
41
+ continue;
42
+ }
43
+ allFiles.push(...(await collectFiles(abs)));
44
+ }
45
+
46
+ const jsEntryPoints = allFiles.filter((f) => isSourceFile(path.relative(rootDir, f)));
47
+ const assetFiles = allFiles.filter((f) => !isSourceFile(path.relative(rootDir, f)) && !/\.stories\.jsx$/.test(f));
48
+
49
+ if (jsEntryPoints.length === 0) {
50
+ throw new Error('No se encontraron archivos fuente para compilar.');
51
+ }
52
+
53
+ await build({
54
+ entryPoints: jsEntryPoints,
55
+ outdir: outDir,
56
+ outbase: rootDir,
57
+ bundle: false,
58
+ format: 'esm',
59
+ platform: 'neutral',
60
+ jsx: 'automatic',
61
+ logLevel: 'info',
62
+ });
63
+
64
+ for (const file of assetFiles) {
65
+ const rel = path.relative(rootDir, file);
66
+ const dest = path.join(outDir, rel);
67
+ await mkdir(path.dirname(dest), { recursive: true });
68
+ await cp(file, dest);
69
+ }
70
+
71
+ for (const file of ['README.md', 'AnteriorityUI.md', 'LICENSE']) {
72
+ const src = path.join(rootDir, file);
73
+ try {
74
+ await stat(src);
75
+ await cp(src, path.join(outDir, file));
76
+ } catch {
77
+ // opcional, no todos existen
78
+ }
79
+ }
80
+
81
+ // pnpm publish empaqueta desde `dist/` (ver publishConfig.directory en package.json),
82
+ // así que este subset de campos es el package.json que va a terminar publicado.
83
+ const rootPkg = JSON.parse(await readFile(path.join(rootDir, 'package.json'), 'utf8'));
84
+ const {
85
+ name,
86
+ version,
87
+ description,
88
+ main,
89
+ license,
90
+ author,
91
+ type,
92
+ keywords,
93
+ repository,
94
+ homepage,
95
+ bugs,
96
+ dependencies,
97
+ peerDependencies,
98
+ } = rootPkg;
99
+ await writeFile(
100
+ path.join(outDir, 'package.json'),
101
+ JSON.stringify(
102
+ {
103
+ name,
104
+ version,
105
+ description,
106
+ main,
107
+ license,
108
+ author,
109
+ type,
110
+ keywords,
111
+ repository,
112
+ homepage,
113
+ bugs,
114
+ dependencies,
115
+ peerDependencies,
116
+ publishConfig: { registry: rootPkg.publishConfig.registry },
117
+ },
118
+ null,
119
+ 2,
120
+ ) + '\n',
121
+ );
122
+
123
+ console.log(`\nBuild OK: ${jsEntryPoints.length} módulos, ${assetFiles.length} assets copiados -> dist/`);
124
+ }
125
+
126
+ main().catch((err) => {
127
+ console.error(err);
128
+ process.exit(1);
129
+ });
@@ -0,0 +1,127 @@
1
+ // Audita imports relativos contra el filesystem real, comparando MAYÚSCULAS/minúsculas
2
+ // exactas. En Windows/Mac (case-insensitive) un import mal casado resuelve igual y no
3
+ // se nota; en Linux (donde corren los builds de deploy) revienta con "module not found".
4
+ // Uso: node scripts/check-case.mjs (reporta)
5
+ // node scripts/check-case.mjs --fix (además lista qué archivos habría que renombrar)
6
+ import { readFile, readdir, stat } from 'node:fs/promises';
7
+ import path from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const rootDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
11
+ const sourceDirs = ['screens', 'common', 'features', 'hooks'];
12
+ const importRe = /from\s+['"](\.\.?\/[^'"]+)['"]/g;
13
+ const candidateExts = ['', '.jsx', '.js', '.module.css', '.css'];
14
+ const candidateIndexes = ['/index.jsx', '/index.js', '/Index.jsx', '/Index.js'];
15
+
16
+ async function collectFiles(dir) {
17
+ const entries = await readdir(dir, { withFileTypes: true });
18
+ const files = [];
19
+ for (const entry of entries) {
20
+ const full = path.join(dir, entry.name);
21
+ if (entry.isDirectory()) files.push(...(await collectFiles(full)));
22
+ else files.push(full);
23
+ }
24
+ return files;
25
+ }
26
+
27
+ // Devuelve el nombre EXACTO (case-sensitive) tal como está en disco para un segmento
28
+ // dado dentro de un directorio, o null si no existe ningún archivo/carpeta con ese
29
+ // nombre en cualquier casing.
30
+ async function exactNameInDir(dir, name) {
31
+ let entries;
32
+ try {
33
+ entries = await readdir(dir);
34
+ } catch {
35
+ return { exists: false, exact: null };
36
+ }
37
+ const exact = entries.includes(name);
38
+ const insensitiveMatch = entries.find((e) => e.toLowerCase() === name.toLowerCase());
39
+ return { exists: Boolean(insensitiveMatch), exact: exact ? name : insensitiveMatch ?? null, caseMismatch: Boolean(insensitiveMatch) && !exact };
40
+ }
41
+
42
+ async function resolveCaseSensitive(fromFile, spec) {
43
+ const baseDir = path.dirname(fromFile);
44
+ const targetNoExt = path.resolve(baseDir, spec);
45
+ const parentDir = path.dirname(targetNoExt);
46
+ const leaf = path.basename(targetNoExt);
47
+
48
+ // 1. spec ya trae extensión (ej. ./index.module.css)
49
+ if (path.extname(leaf)) {
50
+ const res = await exactNameInDir(parentDir, leaf);
51
+ return res.exists ? { ok: !res.caseMismatch, actual: res.exact, tried: leaf, parentDir } : null;
52
+ }
53
+
54
+ // 2. probar como archivo con extensiones comunes
55
+ for (const ext of candidateExts) {
56
+ if (!ext) continue;
57
+ const res = await exactNameInDir(parentDir, leaf + ext);
58
+ if (res.exists) return { ok: !res.caseMismatch, actual: res.exact, tried: leaf + ext, parentDir };
59
+ }
60
+
61
+ // 3. probar como directorio con index.jsx / Index.jsx adentro
62
+ const dirRes = await exactNameInDir(parentDir, leaf);
63
+ if (dirRes.exists) {
64
+ const dirExactOrGuess = path.join(parentDir, dirRes.exact ?? leaf);
65
+ for (const idx of candidateIndexes) {
66
+ const idxLeaf = path.basename(idx);
67
+ const idxRes = await exactNameInDir(dirExactOrGuess, idxLeaf);
68
+ if (idxRes.exists) {
69
+ return {
70
+ ok: !dirRes.caseMismatch && !idxRes.caseMismatch,
71
+ actual: `${dirRes.actual}/${idxRes.exact}`,
72
+ tried: `${leaf}${idx}`,
73
+ parentDir,
74
+ };
75
+ }
76
+ }
77
+ }
78
+
79
+ return null; // no se pudo resolver ni siquiera sin distinguir mayúsculas -> no es un problema de casing
80
+ }
81
+
82
+ async function main() {
83
+ const allFiles = [];
84
+ for (const dir of sourceDirs) {
85
+ const abs = path.join(rootDir, dir);
86
+ try {
87
+ await stat(abs);
88
+ } catch {
89
+ continue;
90
+ }
91
+ allFiles.push(...(await collectFiles(abs)));
92
+ }
93
+ const sourceFiles = allFiles.filter((f) => /\.jsx?$/.test(f));
94
+
95
+ const mismatches = [];
96
+ for (const file of sourceFiles) {
97
+ const content = await readFile(file, 'utf8');
98
+ for (const match of content.matchAll(importRe)) {
99
+ const spec = match[1];
100
+ const resolved = await resolveCaseSensitive(file, spec);
101
+ if (resolved && !resolved.ok) {
102
+ mismatches.push({
103
+ file: path.relative(rootDir, file),
104
+ spec,
105
+ importedAs: path.basename(spec),
106
+ actualOnDisk: resolved.actual,
107
+ });
108
+ }
109
+ }
110
+ }
111
+
112
+ if (mismatches.length === 0) {
113
+ console.log('OK: ningún import relativo tiene mismatch de mayúsculas/minúsculas.');
114
+ return;
115
+ }
116
+
117
+ console.log(`${mismatches.length} import(s) con casing distinto al archivo real en disco:\n`);
118
+ for (const m of mismatches) {
119
+ console.log(` ${m.file}\n import: '${m.spec}' (pide "${m.importedAs}")\n disco: "${m.actualOnDisk}"\n`);
120
+ }
121
+ process.exitCode = 1;
122
+ }
123
+
124
+ main().catch((err) => {
125
+ console.error(err);
126
+ process.exit(1);
127
+ });
@@ -0,0 +1,45 @@
1
+ // Bundlea dist/index.js (que importa los ~50 componentes) con esbuild para confirmar
2
+ // que el grafo de imports del paquete YA COMPILADO resuelve de verdad. `pnpm build-storybook`
3
+ // no alcanza para esto: corre contra el código FUENTE (.jsx), donde un import con extensión
4
+ // ".jsx" explícita matchea el archivo real; una vez compilado a dist/ (.js), ese mismo import
5
+ // literal deja de resolver. Correr después de `pnpm run build`.
6
+ import { build } from 'esbuild';
7
+ import path from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const rootDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
11
+
12
+ const peerAndDeps = [
13
+ 'react',
14
+ 'react-dom',
15
+ 'react-dom/*',
16
+ 'react/*',
17
+ '@mui/*',
18
+ '@emotion/*',
19
+ 'lucide-react',
20
+ 'date-fns',
21
+ 'react-markdown',
22
+ 'remark-gfm',
23
+ ];
24
+
25
+ async function main() {
26
+ try {
27
+ await build({
28
+ entryPoints: [path.join(rootDir, 'dist', 'index.js')],
29
+ bundle: true,
30
+ outfile: path.join(rootDir, 'dist', '.verify-bundle.js'),
31
+ format: 'esm',
32
+ platform: 'browser',
33
+ loader: { '.css': 'css' },
34
+ external: peerAndDeps,
35
+ logLevel: 'silent',
36
+ });
37
+ } catch (err) {
38
+ console.error('FAIL: el paquete compilado en dist/ tiene imports que no resuelven:\n');
39
+ console.error(err.message);
40
+ process.exit(1);
41
+ }
42
+ console.log('OK: dist/index.js y los ~50 componentes que importa resuelven correctamente.');
43
+ }
44
+
45
+ main();
@@ -0,0 +1,36 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ import { defineConfig } from 'vitest/config';
5
+
6
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
7
+
8
+ import { playwright } from '@vitest/browser-playwright';
9
+
10
+ const dirname =
11
+ typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
12
+
13
+ // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
14
+ export default defineConfig({
15
+ test: {
16
+ projects: [
17
+ {
18
+ extends: true,
19
+ plugins: [
20
+ // The plugin will run tests for the stories defined in your Storybook config
21
+ // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
22
+ storybookTest({ configDir: path.join(dirname, '.storybook') }),
23
+ ],
24
+ test: {
25
+ name: 'storybook',
26
+ browser: {
27
+ enabled: true,
28
+ headless: true,
29
+ provider: playwright({}),
30
+ instances: [{ browser: 'chromium' }],
31
+ },
32
+ },
33
+ },
34
+ ],
35
+ },
36
+ });