@soyfri/shared-library 1.5.0 → 2.0.0-beta.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 (283) hide show
  1. package/dist/components/ActionMenu/ActionMenu.cjs +107 -0
  2. package/dist/components/ActionMenu/ActionMenu.cjs.map +1 -0
  3. package/dist/components/ActionMenu/ActionMenu.d.ts +60 -0
  4. package/dist/components/ActionMenu/ActionMenu.js +107 -0
  5. package/dist/components/ActionMenu/ActionMenu.js.map +1 -0
  6. package/dist/components/ActionMenu/index.d.ts +2 -0
  7. package/dist/components/ActionMenu.d.ts +6 -0
  8. package/dist/components/AppBar/AppBar.cjs +346 -0
  9. package/dist/components/AppBar/AppBar.cjs.map +1 -0
  10. package/dist/components/AppBar/AppBar.d.ts +55 -0
  11. package/dist/components/AppBar/AppBar.js +346 -0
  12. package/dist/components/AppBar/AppBar.js.map +1 -0
  13. package/dist/components/AppBar/AppBar.sx.d.ts +12 -0
  14. package/dist/components/AppBar/AppBarBrand.d.ts +31 -0
  15. package/dist/components/AppBar/AppBarContext.d.ts +18 -0
  16. package/dist/components/AppBar/AppBarMenuToggle.d.ts +39 -0
  17. package/dist/components/AppBar/AppBarUserMenu.d.ts +65 -0
  18. package/dist/components/AppBar/index.d.ts +12 -0
  19. package/dist/components/AppBar.d.ts +6 -0
  20. package/dist/components/Autocomplete/Autocomplete.cjs +259 -54
  21. package/dist/components/Autocomplete/Autocomplete.cjs.map +1 -1
  22. package/dist/components/Autocomplete/Autocomplete.d.ts +64 -9
  23. package/dist/components/Autocomplete/Autocomplete.definitions.d.ts +6 -0
  24. package/dist/components/Autocomplete/Autocomplete.helpers.d.ts +18 -0
  25. package/dist/components/Autocomplete/Autocomplete.js +261 -56
  26. package/dist/components/Autocomplete/Autocomplete.js.map +1 -1
  27. package/dist/components/Autocomplete/Autocomplete.sx.d.ts +7 -0
  28. package/dist/components/Autocomplete/Autocomplete.types.d.ts +1 -0
  29. package/dist/components/Autocomplete/_parts/AutocompleteChips.d.ts +19 -0
  30. package/dist/components/Autocomplete/_parts/AutocompleteLoader.d.ts +9 -0
  31. package/dist/components/Autocomplete/_parts/AutocompleteOption.d.ts +19 -0
  32. package/dist/components/Autocomplete/index.d.ts +2 -1
  33. package/dist/components/Autocomplete.d.ts +4 -0
  34. package/dist/components/Avatar/Avatar.cjs +116 -79
  35. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  36. package/dist/components/Avatar/Avatar.d.ts +16 -2
  37. package/dist/components/Avatar/Avatar.definitions.d.ts +11 -0
  38. package/dist/components/Avatar/Avatar.js +117 -80
  39. package/dist/components/Avatar/Avatar.js.map +1 -1
  40. package/dist/components/Card/Card.cjs +168 -9
  41. package/dist/components/Card/Card.cjs.map +1 -1
  42. package/dist/components/Card/Card.d.ts +78 -8
  43. package/dist/components/Card/Card.js +170 -11
  44. package/dist/components/Card/Card.js.map +1 -1
  45. package/dist/components/Card/Card.sx.d.ts +17 -0
  46. package/dist/components/Card/index.d.ts +4 -1
  47. package/dist/components/Card.d.ts +4 -0
  48. package/dist/components/DatePicker/DatePicker.cjs +201 -3
  49. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  50. package/dist/components/DatePicker/DatePicker.d.ts +47 -9
  51. package/dist/components/DatePicker/DatePicker.definitions.d.ts +1 -0
  52. package/dist/components/DatePicker/DatePicker.helpers.d.ts +7 -0
  53. package/dist/components/DatePicker/DatePicker.js +200 -2
  54. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  55. package/dist/components/DatePicker/DatePicker.sx.d.ts +9 -0
  56. package/dist/components/DatePicker/DatePicker.types.d.ts +1 -0
  57. package/dist/components/DatePicker/index.d.ts +2 -1
  58. package/dist/components/DatePicker.d.ts +4 -0
  59. package/dist/components/DateTimePicker/DateTimePicker.cjs +152 -138
  60. package/dist/components/DateTimePicker/DateTimePicker.cjs.map +1 -1
  61. package/dist/components/DateTimePicker/DateTimePicker.d.ts +46 -9
  62. package/dist/components/DateTimePicker/DateTimePicker.definitions.d.ts +1 -0
  63. package/dist/components/DateTimePicker/DateTimePicker.helpers.d.ts +11 -0
  64. package/dist/components/DateTimePicker/DateTimePicker.js +152 -138
  65. package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
  66. package/dist/components/DateTimePicker/DateTimePicker.sx.d.ts +7 -0
  67. package/dist/components/DateTimePicker/DateTimePicker.types.d.ts +1 -0
  68. package/dist/components/DateTimePicker/index.d.ts +2 -1
  69. package/dist/components/DateTimePicker.d.ts +4 -0
  70. package/dist/components/Drawer/Drawer.cjs +271 -0
  71. package/dist/components/Drawer/Drawer.cjs.map +1 -0
  72. package/dist/components/Drawer/Drawer.d.ts +51 -0
  73. package/dist/components/Drawer/Drawer.js +271 -0
  74. package/dist/components/Drawer/Drawer.js.map +1 -0
  75. package/dist/components/Drawer/Drawer.sx.d.ts +23 -0
  76. package/dist/components/Drawer/DrawerContext.d.ts +18 -0
  77. package/dist/components/Drawer/DrawerItem.d.ts +35 -0
  78. package/dist/components/Drawer/index.d.ts +6 -0
  79. package/dist/components/Drawer.d.ts +6 -0
  80. package/dist/components/Icon/Icon.cjs +44 -3
  81. package/dist/components/Icon/Icon.cjs.map +1 -1
  82. package/dist/components/Icon/Icon.d.ts +34 -1
  83. package/dist/components/Icon/Icon.js +44 -3
  84. package/dist/components/Icon/Icon.js.map +1 -1
  85. package/dist/components/Input/Input.cjs +173 -3
  86. package/dist/components/Input/Input.cjs.map +1 -1
  87. package/dist/components/Input/Input.d.ts +20 -15
  88. package/dist/components/Input/Input.definitions.d.ts +5 -2
  89. package/dist/components/Input/Input.helpers.d.ts +14 -0
  90. package/dist/components/Input/Input.js +172 -2
  91. package/dist/components/Input/Input.js.map +1 -1
  92. package/dist/components/Input/Input.sx.d.ts +8 -0
  93. package/dist/components/Input/Input.types.d.ts +1 -0
  94. package/dist/components/Input/index.d.ts +2 -1
  95. package/dist/components/Input.d.ts +4 -0
  96. package/dist/components/InputGroup/InputGroup.cjs +104 -91
  97. package/dist/components/InputGroup/InputGroup.cjs.map +1 -1
  98. package/dist/components/InputGroup/InputGroup.d.ts +37 -1
  99. package/dist/components/InputGroup/InputGroup.definitions.d.ts +6 -0
  100. package/dist/components/InputGroup/InputGroup.js +106 -93
  101. package/dist/components/InputGroup/InputGroup.js.map +1 -1
  102. package/dist/components/Modal/Modal.cjs +226 -116
  103. package/dist/components/Modal/Modal.cjs.map +1 -1
  104. package/dist/components/Modal/Modal.d.ts +38 -2
  105. package/dist/components/Modal/Modal.js +227 -117
  106. package/dist/components/Modal/Modal.js.map +1 -1
  107. package/dist/components/Modal/ModalFooter.d.ts +9 -1
  108. package/dist/components/Modal/index.d.ts +5 -0
  109. package/dist/components/PageLoader/PageLoader.cjs +61 -0
  110. package/dist/components/PageLoader/PageLoader.cjs.map +1 -0
  111. package/dist/components/PageLoader/PageLoader.d.ts +38 -0
  112. package/dist/components/PageLoader/PageLoader.js +61 -0
  113. package/dist/components/PageLoader/PageLoader.js.map +1 -0
  114. package/dist/components/PageLoader/index.d.ts +2 -0
  115. package/dist/components/PageLoader.d.ts +6 -0
  116. package/dist/components/ScrollTopButton/ScrollTopButton.cjs +79 -0
  117. package/dist/components/ScrollTopButton/ScrollTopButton.cjs.map +1 -0
  118. package/dist/components/ScrollTopButton/ScrollTopButton.d.ts +48 -0
  119. package/dist/components/ScrollTopButton/ScrollTopButton.js +79 -0
  120. package/dist/components/ScrollTopButton/ScrollTopButton.js.map +1 -0
  121. package/dist/components/ScrollTopButton/index.d.ts +4 -0
  122. package/dist/components/ScrollTopButton/scrollToTop.d.ts +29 -0
  123. package/dist/components/ScrollTopButton.d.ts +6 -0
  124. package/dist/components/Select/Select.cjs +446 -4
  125. package/dist/components/Select/Select.cjs.map +1 -1
  126. package/dist/components/Select/Select.d.ts +33 -13
  127. package/dist/components/Select/Select.definitions.d.ts +3 -0
  128. package/dist/components/Select/Select.helpers.d.ts +28 -0
  129. package/dist/components/Select/Select.js +445 -3
  130. package/dist/components/Select/Select.js.map +1 -1
  131. package/dist/components/Select/Select.sx.d.ts +7 -0
  132. package/dist/components/Select/Select.types.d.ts +1 -0
  133. package/dist/components/Select/_parts/SelectMenuItem.d.ts +20 -0
  134. package/dist/components/Select/_parts/SelectSearchHeader.d.ts +15 -0
  135. package/dist/components/Select/_parts/SelectValue.d.ts +22 -0
  136. package/dist/components/Select/index.d.ts +2 -1
  137. package/dist/components/Select.d.ts +4 -0
  138. package/dist/components/Stat/Stat.cjs +1 -1
  139. package/dist/components/Stat/Stat.js +1 -1
  140. package/dist/components/Stepper/Stepper.cjs +4 -1
  141. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  142. package/dist/components/Stepper/Stepper.d.ts +5 -0
  143. package/dist/components/Stepper/Stepper.js +4 -1
  144. package/dist/components/Stepper/Stepper.js.map +1 -1
  145. package/dist/components/_shared/formField.sx.d.ts +33 -0
  146. package/dist/components/_shared/resolvePreset.d.ts +18 -0
  147. package/dist/formField.sx-CQ1mbk9M.cjs +76 -0
  148. package/dist/formField.sx-CQ1mbk9M.cjs.map +1 -0
  149. package/dist/formField.sx-DfVbMe0V.js +77 -0
  150. package/dist/formField.sx-DfVbMe0V.js.map +1 -0
  151. package/dist/hooks/Wizard/Wizard.cjs +7 -0
  152. package/dist/hooks/Wizard/Wizard.cjs.map +1 -0
  153. package/dist/hooks/Wizard/Wizard.js +7 -0
  154. package/dist/hooks/Wizard/Wizard.js.map +1 -0
  155. package/dist/hooks/Wizard/WizardContext.d.ts +67 -0
  156. package/dist/hooks/Wizard/index.d.ts +3 -0
  157. package/dist/hooks/Wizard/useWizard.d.ts +9 -0
  158. package/dist/hooks/Wizard.d.ts +2 -0
  159. package/dist/index.cjs +99 -1
  160. package/dist/index.cjs.map +1 -1
  161. package/dist/index.d.ts +3 -0
  162. package/dist/index.js +31 -2
  163. package/dist/index.js.map +1 -1
  164. package/dist/mui.d.ts +5 -0
  165. package/dist/resolvePreset-B-IB0ehH.js +15 -0
  166. package/dist/resolvePreset-B-IB0ehH.js.map +1 -0
  167. package/dist/resolvePreset-CT3kU-K2.cjs +14 -0
  168. package/dist/resolvePreset-CT3kU-K2.cjs.map +1 -0
  169. package/dist/styles.css +3 -112
  170. package/dist/theme/componentStyles.d.ts +32 -0
  171. package/dist/theme/tokens.d.ts +28 -0
  172. package/dist/useWizard-CWdIxZzX.cjs +94 -0
  173. package/dist/useWizard-CWdIxZzX.cjs.map +1 -0
  174. package/dist/useWizard-CWq--C3o.js +95 -0
  175. package/dist/useWizard-CWq--C3o.js.map +1 -0
  176. package/package.json +1 -1
  177. package/src/components/ActionMenu/ActionMenu.stories.tsx +230 -0
  178. package/src/components/ActionMenu/ActionMenu.tsx +174 -0
  179. package/src/components/ActionMenu/index.ts +2 -0
  180. package/src/components/AppBar/AppBar.stories.tsx +272 -0
  181. package/src/components/AppBar/AppBar.sx.ts +32 -0
  182. package/src/components/AppBar/AppBar.tsx +123 -0
  183. package/src/components/AppBar/AppBarBrand.tsx +120 -0
  184. package/src/components/AppBar/AppBarContext.ts +25 -0
  185. package/src/components/AppBar/AppBarMenuToggle.tsx +90 -0
  186. package/src/components/AppBar/AppBarUserMenu.tsx +217 -0
  187. package/src/components/AppBar/index.ts +25 -0
  188. package/src/components/Autocomplete/Autocomplete.definitions.ts +223 -0
  189. package/src/components/Autocomplete/Autocomplete.helpers.ts +60 -0
  190. package/src/components/Autocomplete/Autocomplete.stories.tsx +363 -2
  191. package/src/components/Autocomplete/Autocomplete.sx.ts +30 -0
  192. package/src/components/Autocomplete/Autocomplete.tsx +312 -90
  193. package/src/components/Autocomplete/Autocomplete.types.ts +13 -0
  194. package/src/components/Autocomplete/_parts/AutocompleteChips.tsx +55 -0
  195. package/src/components/Autocomplete/_parts/AutocompleteLoader.tsx +17 -0
  196. package/src/components/Autocomplete/_parts/AutocompleteOption.tsx +31 -0
  197. package/src/components/Autocomplete/index.ts +12 -1
  198. package/src/components/Avatar/Avatar.definitions.ts +162 -0
  199. package/src/components/Avatar/Avatar.stories.tsx +205 -1
  200. package/src/components/Avatar/Avatar.tsx +166 -103
  201. package/src/components/Card/Card.stories.tsx +205 -16
  202. package/src/components/Card/Card.sx.ts +104 -0
  203. package/src/components/Card/Card.tsx +191 -35
  204. package/src/components/Card/index.ts +9 -1
  205. package/src/components/DatePicker/DatePicker.definitions.ts +24 -1
  206. package/src/components/DatePicker/DatePicker.helpers.ts +24 -0
  207. package/src/components/DatePicker/DatePicker.stories.tsx +29 -2
  208. package/src/components/DatePicker/DatePicker.sx.ts +33 -0
  209. package/src/components/DatePicker/DatePicker.tsx +163 -139
  210. package/src/components/DatePicker/DatePicker.types.ts +10 -0
  211. package/src/components/DatePicker/index.ts +9 -1
  212. package/src/components/DateTimePicker/DateTimePicker.definitions.ts +24 -0
  213. package/src/components/DateTimePicker/DateTimePicker.helpers.ts +38 -0
  214. package/src/components/DateTimePicker/DateTimePicker.stories.tsx +29 -1
  215. package/src/components/DateTimePicker/DateTimePicker.sx.ts +30 -0
  216. package/src/components/DateTimePicker/DateTimePicker.tsx +200 -166
  217. package/src/components/DateTimePicker/DateTimePicker.types.ts +10 -0
  218. package/src/components/DateTimePicker/index.ts +9 -1
  219. package/src/components/Drawer/Drawer.stories.tsx +270 -0
  220. package/src/components/Drawer/Drawer.sx.ts +106 -0
  221. package/src/components/Drawer/Drawer.tsx +214 -0
  222. package/src/components/Drawer/DrawerContext.ts +26 -0
  223. package/src/components/Drawer/DrawerItem.tsx +110 -0
  224. package/src/components/Drawer/index.ts +10 -0
  225. package/src/components/Flyout/Flyout.stories.tsx +26 -18
  226. package/src/components/Icon/Icon.stories.tsx +68 -1
  227. package/src/components/Icon/Icon.tsx +87 -6
  228. package/src/components/Input/Input.definitions.ts +74 -2
  229. package/src/components/Input/Input.helpers.ts +49 -0
  230. package/src/components/Input/Input.stories.tsx +116 -4
  231. package/src/components/Input/Input.sx.ts +42 -0
  232. package/src/components/Input/Input.tsx +117 -162
  233. package/src/components/Input/Input.types.ts +10 -0
  234. package/src/components/Input/index.ts +9 -1
  235. package/src/components/InputGroup/InputGroup.definitions.ts +158 -0
  236. package/src/components/InputGroup/InputGroup.stories.tsx +159 -28
  237. package/src/components/InputGroup/InputGroup.tsx +159 -116
  238. package/src/components/Modal/Modal.stories.tsx +434 -6
  239. package/src/components/Modal/Modal.tsx +303 -121
  240. package/src/components/Modal/ModalFooter.tsx +22 -12
  241. package/src/components/Modal/index.ts +6 -1
  242. package/src/components/PageLoader/PageLoader.stories.tsx +217 -0
  243. package/src/components/PageLoader/PageLoader.tsx +96 -0
  244. package/src/components/PageLoader/index.ts +2 -0
  245. package/src/components/ScrollTopButton/ScrollTopButton.stories.tsx +158 -0
  246. package/src/components/ScrollTopButton/ScrollTopButton.tsx +135 -0
  247. package/src/components/ScrollTopButton/index.ts +8 -0
  248. package/src/components/ScrollTopButton/scrollToTop.ts +37 -0
  249. package/src/components/Select/Select.definitions.ts +114 -0
  250. package/src/components/Select/Select.helpers.ts +71 -0
  251. package/src/components/Select/Select.stories.tsx +126 -8
  252. package/src/components/Select/Select.sx.ts +14 -0
  253. package/src/components/Select/Select.tsx +246 -285
  254. package/src/components/Select/Select.types.ts +15 -0
  255. package/src/components/Select/_parts/SelectMenuItem.tsx +40 -0
  256. package/src/components/Select/_parts/SelectSearchHeader.tsx +51 -0
  257. package/src/components/Select/_parts/SelectValue.tsx +96 -0
  258. package/src/components/Select/index.ts +14 -1
  259. package/src/components/Stepper/Stepper.tsx +17 -1
  260. package/src/components/Tooltip/Tooltip.stories.tsx +15 -3
  261. package/src/components/_shared/formField.sx.ts +118 -0
  262. package/src/components/_shared/resolvePreset.ts +35 -0
  263. package/src/hooks/Wizard/Wizard.stories.tsx +301 -0
  264. package/src/hooks/Wizard/WizardContext.tsx +166 -0
  265. package/src/hooks/Wizard/index.ts +6 -0
  266. package/src/hooks/Wizard/useWizard.ts +13 -0
  267. package/src/index.ts +17 -1
  268. package/src/mui.ts +44 -0
  269. package/src/theme/componentStyles.ts +47 -0
  270. package/src/theme/tokens.ts +43 -0
  271. package/dist/DatePicker-BSNboVhN.js +0 -201
  272. package/dist/DatePicker-BSNboVhN.js.map +0 -1
  273. package/dist/DatePicker-BoqxWAhj.cjs +0 -200
  274. package/dist/DatePicker-BoqxWAhj.cjs.map +0 -1
  275. package/dist/Input-DFHs7cJ_.js +0 -171
  276. package/dist/Input-DFHs7cJ_.js.map +0 -1
  277. package/dist/Input-c8MwNNPg.cjs +0 -170
  278. package/dist/Input-c8MwNNPg.cjs.map +0 -1
  279. package/dist/Select-BO2N56sm.cjs +0 -411
  280. package/dist/Select-BO2N56sm.cjs.map +0 -1
  281. package/dist/Select-BcLkyHSE.js +0 -412
  282. package/dist/Select-BcLkyHSE.js.map +0 -1
  283. package/dist/index.css +0 -3
@@ -0,0 +1,217 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { Box, Button, Paper, Typography } from '@mui/material';
4
+
5
+ import { PageLoader } from './PageLoader';
6
+
7
+ const meta: Meta<typeof PageLoader> = {
8
+ title: 'Components/PageLoader',
9
+ component: PageLoader,
10
+ tags: ['autodocs'],
11
+ parameters: {
12
+ layout: 'fullscreen',
13
+ docs: {
14
+ description: {
15
+ component:
16
+ 'Loader visual para estados de carga, tanto a nivel de página completa (splash screen) como inline dentro de un contenedor. Reemplaza el `LayoutSplashScreen` de Metronic.',
17
+ },
18
+ },
19
+ },
20
+ argTypes: {
21
+ fullscreen: {
22
+ control: 'boolean',
23
+ description: 'Ocupa toda la ventana con backdrop. Default: true.',
24
+ },
25
+ size: {
26
+ control: { type: 'number', min: 16, max: 120, step: 4 },
27
+ description: 'Tamaño del spinner en px.',
28
+ },
29
+ open: {
30
+ control: 'boolean',
31
+ description: 'Si es false, el loader se desmonta (con fade en fullscreen).',
32
+ },
33
+ },
34
+ };
35
+
36
+ export default meta;
37
+ type Story = StoryObj<typeof PageLoader>;
38
+
39
+ // ── Stories ──────────────────────────────────────────────────────────────
40
+
41
+ export const FullscreenDefault: Story = {
42
+ args: {
43
+ fullscreen: true,
44
+ open: true,
45
+ },
46
+ parameters: {
47
+ docs: {
48
+ description: {
49
+ story: 'Loader full-page sin texto ni logo. Caso más minimal.',
50
+ },
51
+ },
52
+ },
53
+ };
54
+
55
+ export const FullscreenWithMessage: Story = {
56
+ args: {
57
+ fullscreen: true,
58
+ open: true,
59
+ message: 'Cargando aplicación...',
60
+ },
61
+ parameters: {
62
+ docs: {
63
+ description: {
64
+ story: 'Splash screen típico con mensaje bajo el spinner.',
65
+ },
66
+ },
67
+ },
68
+ };
69
+
70
+ export const FullscreenWithLogo: Story = {
71
+ args: {
72
+ fullscreen: true,
73
+ open: true,
74
+ message: 'Inicializando...',
75
+ logo: (
76
+ <Box
77
+ sx={{
78
+ width: 120,
79
+ height: 120,
80
+ borderRadius: '50%',
81
+ bgcolor: 'primary.main',
82
+ color: '#fff',
83
+ display: 'flex',
84
+ alignItems: 'center',
85
+ justifyContent: 'center',
86
+ fontSize: 36,
87
+ fontWeight: 700,
88
+ }}
89
+ >
90
+ fri
91
+ </Box>
92
+ ),
93
+ size: 40,
94
+ },
95
+ parameters: {
96
+ docs: {
97
+ description: {
98
+ story:
99
+ 'Splash de arranque de app con logo/branding arriba del spinner. Equivalente visual al `LayoutSplashScreen` de Metronic.',
100
+ },
101
+ },
102
+ },
103
+ };
104
+
105
+ export const Inline: Story = {
106
+ args: {
107
+ fullscreen: false,
108
+ open: true,
109
+ message: 'Cargando datos',
110
+ size: 32,
111
+ },
112
+ render: (args) => (
113
+ <Paper sx={{ maxWidth: 480, mx: 'auto', mt: 4 }}>
114
+ <Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider' }}>
115
+ <Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
116
+ Panel de resumen
117
+ </Typography>
118
+ </Box>
119
+ <PageLoader {...args} />
120
+ </Paper>
121
+ ),
122
+ parameters: {
123
+ docs: {
124
+ description: {
125
+ story:
126
+ 'Loader inline (no fullscreen). Ocupa el ancho del contenedor padre y tiene una altura mínima. Útil dentro de cards mientras se cargan datos.',
127
+ },
128
+ },
129
+ },
130
+ };
131
+
132
+ export const ToggledFullscreen: Story = {
133
+ render: () => {
134
+ const [loading, setLoading] = useState(false);
135
+
136
+ const simulate = () => {
137
+ setLoading(true);
138
+ setTimeout(() => setLoading(false), 1800);
139
+ };
140
+
141
+ return (
142
+ <Box sx={{ p: 4, height: '100vh' }}>
143
+ <Typography variant="h5" gutterBottom>
144
+ Simulación de carga
145
+ </Typography>
146
+ <Typography color="text.secondary" sx={{ mb: 2 }}>
147
+ Al hacer click, el loader aparece por 1.8s y luego desaparece con fade.
148
+ </Typography>
149
+ <Button variant="contained" onClick={simulate}>
150
+ Simular carga
151
+ </Button>
152
+
153
+ <PageLoader
154
+ fullscreen
155
+ open={loading}
156
+ message="Procesando..."
157
+ logo={
158
+ <Box
159
+ sx={{
160
+ width: 72,
161
+ height: 72,
162
+ borderRadius: 2,
163
+ bgcolor: 'primary.main',
164
+ color: '#fff',
165
+ display: 'flex',
166
+ alignItems: 'center',
167
+ justifyContent: 'center',
168
+ fontSize: 24,
169
+ fontWeight: 700,
170
+ }}
171
+ >
172
+ fri
173
+ </Box>
174
+ }
175
+ />
176
+ </Box>
177
+ );
178
+ },
179
+ parameters: {
180
+ docs: {
181
+ description: {
182
+ story:
183
+ 'Ejemplo controlado: el loader se monta/desmonta según un estado externo, con fade de salida. Patrón típico para bloquear la app durante una operación crítica (auth, inicialización, navegación global).',
184
+ },
185
+ },
186
+ },
187
+ };
188
+
189
+ export const AutoDismiss: Story = {
190
+ render: () => {
191
+ const [open, setOpen] = useState(true);
192
+
193
+ useEffect(() => {
194
+ const t = setTimeout(() => setOpen(false), 2000);
195
+ return () => clearTimeout(t);
196
+ }, []);
197
+
198
+ return (
199
+ <Box sx={{ p: 4, height: '100vh' }}>
200
+ {!open && (
201
+ <Typography variant="h5">
202
+ App lista. (El loader se cerró tras 2s.)
203
+ </Typography>
204
+ )}
205
+ <PageLoader open={open} message="Cargando..." />
206
+ </Box>
207
+ );
208
+ },
209
+ parameters: {
210
+ docs: {
211
+ description: {
212
+ story:
213
+ 'Arranque típico: el loader aparece al montar, y el consumer lo cierra cuando termina la inicialización. Aquí simulamos 2 segundos fijos.',
214
+ },
215
+ },
216
+ },
217
+ };
@@ -0,0 +1,96 @@
1
+ import React, { type ReactNode } from 'react';
2
+ import { Box, CircularProgress, Typography, Fade } from '@mui/material';
3
+ import type { SxProps, Theme } from '@mui/material/styles';
4
+
5
+ export interface PageLoaderProps {
6
+ /**
7
+ * Si es true, muestra el loader ocupando toda la ventana (fixed, 100vh/vw)
8
+ * con backdrop. Default: true.
9
+ */
10
+ fullscreen?: boolean;
11
+ /** Texto bajo el spinner. */
12
+ message?: ReactNode;
13
+ /** Logo/imagen opcional arriba del spinner. */
14
+ logo?: ReactNode;
15
+ /** Tamaño del spinner en px. Default: 48. */
16
+ size?: number;
17
+ /**
18
+ * Control explícito. Si es undefined, el loader se muestra apenas se monta.
19
+ * Útil para fades.
20
+ */
21
+ open?: boolean;
22
+ /** Color del backdrop (solo fullscreen). Default: usa theme.palette.background.default. */
23
+ backdropColor?: string;
24
+ /** sx del root. */
25
+ sx?: SxProps<Theme>;
26
+ className?: string;
27
+ }
28
+
29
+ /**
30
+ * Loader full-page o inline. Reemplaza el `LayoutSplashScreen` de Metronic.
31
+ *
32
+ * ```tsx
33
+ * // Splash de arranque
34
+ * <PageLoader logo={<img src={logo} />} message="Cargando..." />
35
+ *
36
+ * // Loader local dentro de una card
37
+ * <PageLoader fullscreen={false} size={32} />
38
+ * ```
39
+ */
40
+ export function PageLoader({
41
+ fullscreen = true,
42
+ message,
43
+ logo,
44
+ size = 48,
45
+ open = true,
46
+ backdropColor,
47
+ sx,
48
+ className,
49
+ }: PageLoaderProps) {
50
+ const rootSx: SxProps<Theme> = [
51
+ (theme) => ({
52
+ display: 'flex',
53
+ flexDirection: 'column',
54
+ alignItems: 'center',
55
+ justifyContent: 'center',
56
+ gap: 2,
57
+ ...(fullscreen
58
+ ? {
59
+ position: 'fixed',
60
+ inset: 0,
61
+ zIndex: theme.zIndex.modal + 10,
62
+ backgroundColor:
63
+ backdropColor ?? theme.palette.background.default,
64
+ }
65
+ : {
66
+ width: '100%',
67
+ minHeight: 160,
68
+ }),
69
+ }),
70
+ ...(Array.isArray(sx) ? sx : sx ? [sx] : []),
71
+ ];
72
+
73
+ const content = (
74
+ <Box className={className} sx={rootSx} role="status" aria-live="polite">
75
+ {logo && <Box sx={{ mb: 1 }}>{logo}</Box>}
76
+ <CircularProgress size={size} thickness={4} />
77
+ {message && (
78
+ <Typography variant="body2" color="text.secondary">
79
+ {message}
80
+ </Typography>
81
+ )}
82
+ </Box>
83
+ );
84
+
85
+ if (!fullscreen) {
86
+ return open ? content : null;
87
+ }
88
+
89
+ return (
90
+ <Fade in={open} timeout={{ enter: 0, exit: 200 }} unmountOnExit>
91
+ {content}
92
+ </Fade>
93
+ );
94
+ }
95
+
96
+ export default PageLoader;
@@ -0,0 +1,2 @@
1
+ export { PageLoader, default } from './PageLoader';
2
+ export type { PageLoaderProps } from './PageLoader';
@@ -0,0 +1,158 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { Box, Button, Stack, Typography } from '@mui/material';
4
+ import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
5
+
6
+ import { ScrollTopButton } from './ScrollTopButton';
7
+ import { scrollToTop } from './scrollToTop';
8
+
9
+ const meta: Meta<typeof ScrollTopButton> = {
10
+ title: 'Components/ScrollTopButton',
11
+ component: ScrollTopButton,
12
+ tags: ['autodocs'],
13
+ parameters: {
14
+ layout: 'fullscreen',
15
+ docs: {
16
+ description: {
17
+ component:
18
+ 'Botón flotante que aparece tras scrollear más de `threshold` px y lleva al tope al click. Reemplaza al `ScrollTopComponent` visible de Metronic. Para el caso imperativo (p.ej. tras una mutación) usa el helper `scrollToTop()`.',
19
+ },
20
+ },
21
+ },
22
+ argTypes: {
23
+ threshold: { control: { type: 'number', min: 0, max: 1000, step: 50 } },
24
+ position: {
25
+ control: 'select',
26
+ options: ['bottom-right', 'bottom-left', 'bottom-center'],
27
+ },
28
+ size: { control: 'select', options: ['small', 'medium', 'large'] },
29
+ color: {
30
+ control: 'select',
31
+ options: ['default', 'primary', 'secondary', 'success', 'warning', 'error'],
32
+ },
33
+ },
34
+ };
35
+
36
+ export default meta;
37
+ type Story = StoryObj<typeof ScrollTopButton>;
38
+
39
+ const TallContent = () => (
40
+ <Box sx={{ p: 3 }}>
41
+ <Typography variant="h5" gutterBottom>
42
+ Scrollea hacia abajo para que aparezca el botón
43
+ </Typography>
44
+ <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
45
+ El botón aparece cuando `window.scrollY` supera el `threshold`.
46
+ </Typography>
47
+ {Array.from({ length: 60 }).map((_, idx) => (
48
+ <Typography key={idx} variant="body2" sx={{ mb: 1 }}>
49
+ Línea {idx + 1} — contenido de relleno para simular una página larga.
50
+ </Typography>
51
+ ))}
52
+ </Box>
53
+ );
54
+
55
+ export const Default: Story = {
56
+ args: {
57
+ threshold: 300,
58
+ position: 'bottom-right',
59
+ },
60
+ render: (args) => (
61
+ <>
62
+ <TallContent />
63
+ <ScrollTopButton {...args} />
64
+ </>
65
+ ),
66
+ };
67
+
68
+ export const BottomLeft: Story = {
69
+ args: {
70
+ threshold: 200,
71
+ position: 'bottom-left',
72
+ },
73
+ render: (args) => (
74
+ <>
75
+ <TallContent />
76
+ <ScrollTopButton {...args} />
77
+ </>
78
+ ),
79
+ };
80
+
81
+ export const BottomCenter: Story = {
82
+ args: {
83
+ threshold: 200,
84
+ position: 'bottom-center',
85
+ color: 'primary',
86
+ },
87
+ render: (args) => (
88
+ <>
89
+ <TallContent />
90
+ <ScrollTopButton {...args} />
91
+ </>
92
+ ),
93
+ };
94
+
95
+ export const CustomIcon: Story = {
96
+ args: {
97
+ threshold: 200,
98
+ color: 'primary',
99
+ icon: <ArrowUpwardIcon />,
100
+ },
101
+ render: (args) => (
102
+ <>
103
+ <TallContent />
104
+ <ScrollTopButton {...args} />
105
+ </>
106
+ ),
107
+ };
108
+
109
+ export const SmallSize: Story = {
110
+ args: {
111
+ size: 'small',
112
+ threshold: 150,
113
+ },
114
+ render: (args) => (
115
+ <>
116
+ <TallContent />
117
+ <ScrollTopButton {...args} />
118
+ </>
119
+ ),
120
+ };
121
+
122
+ export const ImperativeHelper: Story = {
123
+ render: () => (
124
+ <Box sx={{ p: 3 }}>
125
+ <Typography variant="h5" gutterBottom>
126
+ Uso imperativo: <code>scrollToTop()</code>
127
+ </Typography>
128
+ <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
129
+ Reemplazo directo de <code>ScrollTopComponent.goTop()</code> de Metronic.
130
+ Llamar tras mutaciones / aperturas de modales.
131
+ </Typography>
132
+ <Stack direction="row" spacing={1} sx={{ mb: 3 }}>
133
+ <Button variant="contained" onClick={() => scrollToTop()}>
134
+ scrollToTop() (smooth)
135
+ </Button>
136
+ <Button
137
+ variant="outlined"
138
+ onClick={() => scrollToTop({ behavior: 'auto' })}
139
+ >
140
+ scrollToTop &#123; behavior:'auto' &#125;
141
+ </Button>
142
+ </Stack>
143
+ {Array.from({ length: 50 }).map((_, idx) => (
144
+ <Typography key={idx} variant="body2" sx={{ mb: 1 }}>
145
+ Línea {idx + 1}
146
+ </Typography>
147
+ ))}
148
+ </Box>
149
+ ),
150
+ parameters: {
151
+ docs: {
152
+ description: {
153
+ story:
154
+ 'Demuestra el helper imperativo. Cubre el patrón del legacy: llamar `scrollToTop()` tras una mutación para llevar al usuario a ver el mensaje de confirmación del tope.',
155
+ },
156
+ },
157
+ },
158
+ };
@@ -0,0 +1,135 @@
1
+ import React, { useEffect, useState, type ReactNode } from 'react';
2
+ import { Fab, Zoom, useTheme } from '@mui/material';
3
+ import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
4
+ import type { SxProps, Theme } from '@mui/material/styles';
5
+
6
+ import { resolvePreset } from '../_shared/resolvePreset';
7
+ import { scrollToTop } from './scrollToTop';
8
+
9
+ export type ScrollTopButtonPosition =
10
+ | 'bottom-right'
11
+ | 'bottom-left'
12
+ | 'bottom-center';
13
+
14
+ export interface ScrollTopButtonProps {
15
+ /**
16
+ * Distancia en px que hay que scrollear antes de mostrar el botón.
17
+ * Default: `300`.
18
+ */
19
+ threshold?: number;
20
+ /**
21
+ * Posición del botón en la pantalla. Default: `'bottom-right'`.
22
+ */
23
+ position?: ScrollTopButtonPosition;
24
+ /**
25
+ * Elemento scrolleable a observar y al que se hace scrollTop. Si se omite,
26
+ * se usa `window` (caso más común).
27
+ */
28
+ scrollTarget?: Window | HTMLElement | null;
29
+ /** Tamaño del FAB. Default: `'medium'`. */
30
+ size?: 'small' | 'medium' | 'large';
31
+ /**
32
+ * Color del FAB. Default: `'default'`.
33
+ */
34
+ color?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error';
35
+ /** Icono custom. Default: `<KeyboardArrowUpIcon />`. */
36
+ icon?: ReactNode;
37
+ /** Texto accesible (aria-label). Default: `"Subir al inicio"`. */
38
+ ariaLabel?: string;
39
+ /** Preset registrado en `theme.styles.ScrollTopButton`. */
40
+ preset?: string;
41
+ /** sx del Fab. Se compone sobre la posición + preset. */
42
+ sx?: SxProps<Theme>;
43
+ className?: string;
44
+ }
45
+
46
+ const positionSx: Record<ScrollTopButtonPosition, SxProps<Theme>> = {
47
+ 'bottom-right': { position: 'fixed', bottom: 24, right: 24 },
48
+ 'bottom-left': { position: 'fixed', bottom: 24, left: 24 },
49
+ 'bottom-center': {
50
+ position: 'fixed',
51
+ bottom: 24,
52
+ left: '50%',
53
+ transform: 'translateX(-50%)',
54
+ },
55
+ };
56
+
57
+ /**
58
+ * Botón flotante que aparece tras scrollear más de `threshold` px y, al
59
+ * clickearse, hace scroll suave hasta el tope. Reemplaza al componente
60
+ * visible de `ScrollTopComponent` de Metronic.
61
+ *
62
+ * Para el caso imperativo (llamar `goTop()` tras una mutación), usar el
63
+ * helper `scrollToTop()` directamente.
64
+ *
65
+ * ```tsx
66
+ * <ScrollTopButton threshold={400} position="bottom-right" />
67
+ * ```
68
+ */
69
+ export function ScrollTopButton({
70
+ threshold = 300,
71
+ position = 'bottom-right',
72
+ scrollTarget,
73
+ size = 'medium',
74
+ color = 'default',
75
+ icon,
76
+ ariaLabel = 'Subir al inicio',
77
+ preset,
78
+ sx,
79
+ className,
80
+ }: ScrollTopButtonProps) {
81
+ const theme = useTheme();
82
+ const [visible, setVisible] = useState(false);
83
+
84
+ useEffect(() => {
85
+ // Si viene scrollTarget explícito, usarlo; si no, window.
86
+ const target: Window | HTMLElement | null =
87
+ scrollTarget ?? (typeof window !== 'undefined' ? window : null);
88
+ if (!target) return;
89
+
90
+ const readScrollTop = () =>
91
+ target === window
92
+ ? window.scrollY || document.documentElement.scrollTop
93
+ : (target as HTMLElement).scrollTop;
94
+
95
+ const handleScroll = () => {
96
+ setVisible(readScrollTop() > threshold);
97
+ };
98
+
99
+ handleScroll(); // check inicial por si ya estamos scrolleados
100
+ target.addEventListener('scroll', handleScroll, { passive: true });
101
+ return () => target.removeEventListener('scroll', handleScroll);
102
+ }, [threshold, scrollTarget]);
103
+
104
+ const handleClick = () => {
105
+ scrollToTop({
106
+ target: scrollTarget ?? (typeof window !== 'undefined' ? window : undefined),
107
+ });
108
+ };
109
+
110
+ const presetSx = resolvePreset('ScrollTopButton', preset, theme);
111
+
112
+ const mergedSx: SxProps<Theme> = [
113
+ positionSx[position],
114
+ { zIndex: theme.zIndex.speedDial },
115
+ ...(presetSx ? [presetSx] : []),
116
+ ...(Array.isArray(sx) ? sx : sx ? [sx] : []),
117
+ ];
118
+
119
+ return (
120
+ <Zoom in={visible} unmountOnExit>
121
+ <Fab
122
+ size={size}
123
+ color={color}
124
+ aria-label={ariaLabel}
125
+ onClick={handleClick}
126
+ className={className}
127
+ sx={mergedSx}
128
+ >
129
+ {icon ?? <KeyboardArrowUpIcon />}
130
+ </Fab>
131
+ </Zoom>
132
+ );
133
+ }
134
+
135
+ export default ScrollTopButton;
@@ -0,0 +1,8 @@
1
+ export { ScrollTopButton, default } from './ScrollTopButton';
2
+ export type {
3
+ ScrollTopButtonProps,
4
+ ScrollTopButtonPosition,
5
+ } from './ScrollTopButton';
6
+
7
+ export { scrollToTop } from './scrollToTop';
8
+ export type { ScrollToTopOptions } from './scrollToTop';
@@ -0,0 +1,37 @@
1
+ export interface ScrollToTopOptions {
2
+ /** Comportamiento del scroll. Default: `'smooth'`. */
3
+ behavior?: ScrollBehavior;
4
+ /**
5
+ * Elemento target del scroll. Default: `window`. Útil cuando el contenedor
6
+ * scrolleable NO es `window` (p.ej. un `<Box>` con `overflow: auto`).
7
+ */
8
+ target?: Window | HTMLElement;
9
+ /** Offset desde el top. Default: `0`. */
10
+ top?: number;
11
+ }
12
+
13
+ /**
14
+ * Reemplaza imperativamente a `ScrollTopComponent.goTop()` de Metronic.
15
+ *
16
+ * Llamar tras mutaciones / cambios de filtros / apertura de modales para
17
+ * asegurar que el usuario vea el mensaje de confirmación en la parte
18
+ * superior de la página.
19
+ *
20
+ * ```ts
21
+ * // Reemplazo directo del legacy:
22
+ * // Antes: ScrollTopComponent.goTop()
23
+ * scrollToTop();
24
+ *
25
+ * // Con opciones:
26
+ * scrollToTop({ behavior: 'auto' });
27
+ * scrollToTop({ target: myScrollableRef.current });
28
+ * ```
29
+ */
30
+ export function scrollToTop({
31
+ behavior = 'smooth',
32
+ target = typeof window !== 'undefined' ? window : undefined,
33
+ top = 0,
34
+ }: ScrollToTopOptions = {}): void {
35
+ if (!target) return;
36
+ target.scrollTo({ top, left: 0, behavior });
37
+ }