@soyfri/shared-library 1.5.0 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.js +75 -38
- package/dist/components/ActionMenu/ActionMenu.cjs +107 -0
- package/dist/components/ActionMenu/ActionMenu.cjs.map +1 -0
- package/dist/components/ActionMenu/ActionMenu.d.ts +60 -0
- package/dist/components/ActionMenu/ActionMenu.js +107 -0
- package/dist/components/ActionMenu/ActionMenu.js.map +1 -0
- package/dist/components/ActionMenu/index.d.ts +2 -0
- package/dist/components/ActionMenu.d.ts +6 -0
- package/dist/components/AppBar/AppBar.cjs +346 -0
- package/dist/components/AppBar/AppBar.cjs.map +1 -0
- package/dist/components/AppBar/AppBar.d.ts +55 -0
- package/dist/components/AppBar/AppBar.js +346 -0
- package/dist/components/AppBar/AppBar.js.map +1 -0
- package/dist/components/AppBar/AppBar.sx.d.ts +12 -0
- package/dist/components/AppBar/AppBarBrand.d.ts +31 -0
- package/dist/components/AppBar/AppBarContext.d.ts +18 -0
- package/dist/components/AppBar/AppBarMenuToggle.d.ts +39 -0
- package/dist/components/AppBar/AppBarUserMenu.d.ts +65 -0
- package/dist/components/AppBar/index.d.ts +12 -0
- package/dist/components/AppBar.d.ts +6 -0
- package/dist/components/Autocomplete/Autocomplete.cjs +259 -54
- package/dist/components/Autocomplete/Autocomplete.cjs.map +1 -1
- package/dist/components/Autocomplete/Autocomplete.d.ts +64 -9
- package/dist/components/Autocomplete/Autocomplete.definitions.d.ts +6 -0
- package/dist/components/Autocomplete/Autocomplete.helpers.d.ts +18 -0
- package/dist/components/Autocomplete/Autocomplete.js +261 -56
- package/dist/components/Autocomplete/Autocomplete.js.map +1 -1
- package/dist/components/Autocomplete/Autocomplete.sx.d.ts +7 -0
- package/dist/components/Autocomplete/Autocomplete.types.d.ts +1 -0
- package/dist/components/Autocomplete/_parts/AutocompleteChips.d.ts +19 -0
- package/dist/components/Autocomplete/_parts/AutocompleteLoader.d.ts +9 -0
- package/dist/components/Autocomplete/_parts/AutocompleteOption.d.ts +19 -0
- package/dist/components/Autocomplete/index.d.ts +2 -1
- package/dist/components/Autocomplete.d.ts +4 -0
- package/dist/components/Avatar/Avatar.cjs +116 -79
- package/dist/components/Avatar/Avatar.cjs.map +1 -1
- package/dist/components/Avatar/Avatar.d.ts +16 -2
- package/dist/components/Avatar/Avatar.definitions.d.ts +11 -0
- package/dist/components/Avatar/Avatar.js +117 -80
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Card/Card.cjs +168 -9
- package/dist/components/Card/Card.cjs.map +1 -1
- package/dist/components/Card/Card.d.ts +78 -8
- package/dist/components/Card/Card.js +170 -11
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Card/Card.sx.d.ts +17 -0
- package/dist/components/Card/index.d.ts +4 -1
- package/dist/components/Card.d.ts +4 -0
- package/dist/components/DatePicker/DatePicker.cjs +201 -3
- package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +47 -9
- package/dist/components/DatePicker/DatePicker.definitions.d.ts +1 -0
- package/dist/components/DatePicker/DatePicker.helpers.d.ts +7 -0
- package/dist/components/DatePicker/DatePicker.js +200 -2
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.sx.d.ts +9 -0
- package/dist/components/DatePicker/DatePicker.types.d.ts +1 -0
- package/dist/components/DatePicker/index.d.ts +2 -1
- package/dist/components/DatePicker.d.ts +4 -0
- package/dist/components/DateTimePicker/DateTimePicker.cjs +152 -138
- package/dist/components/DateTimePicker/DateTimePicker.cjs.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.d.ts +46 -9
- package/dist/components/DateTimePicker/DateTimePicker.definitions.d.ts +1 -0
- package/dist/components/DateTimePicker/DateTimePicker.helpers.d.ts +11 -0
- package/dist/components/DateTimePicker/DateTimePicker.js +152 -138
- package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.sx.d.ts +7 -0
- package/dist/components/DateTimePicker/DateTimePicker.types.d.ts +1 -0
- package/dist/components/DateTimePicker/index.d.ts +2 -1
- package/dist/components/DateTimePicker.d.ts +4 -0
- package/dist/components/Drawer/Drawer.cjs +271 -0
- package/dist/components/Drawer/Drawer.cjs.map +1 -0
- package/dist/components/Drawer/Drawer.d.ts +51 -0
- package/dist/components/Drawer/Drawer.js +271 -0
- package/dist/components/Drawer/Drawer.js.map +1 -0
- package/dist/components/Drawer/Drawer.sx.d.ts +23 -0
- package/dist/components/Drawer/DrawerContext.d.ts +18 -0
- package/dist/components/Drawer/DrawerItem.d.ts +35 -0
- package/dist/components/Drawer/index.d.ts +6 -0
- package/dist/components/Drawer.d.ts +6 -0
- package/dist/components/Icon/Icon.cjs +44 -3
- package/dist/components/Icon/Icon.cjs.map +1 -1
- package/dist/components/Icon/Icon.d.ts +34 -1
- package/dist/components/Icon/Icon.js +44 -3
- package/dist/components/Icon/Icon.js.map +1 -1
- package/dist/components/Input/Input.cjs +173 -3
- package/dist/components/Input/Input.cjs.map +1 -1
- package/dist/components/Input/Input.d.ts +20 -15
- package/dist/components/Input/Input.definitions.d.ts +5 -2
- package/dist/components/Input/Input.helpers.d.ts +14 -0
- package/dist/components/Input/Input.js +172 -2
- package/dist/components/Input/Input.js.map +1 -1
- package/dist/components/Input/Input.sx.d.ts +8 -0
- package/dist/components/Input/Input.types.d.ts +1 -0
- package/dist/components/Input/index.d.ts +2 -1
- package/dist/components/Input.d.ts +4 -0
- package/dist/components/InputGroup/InputGroup.cjs +104 -91
- package/dist/components/InputGroup/InputGroup.cjs.map +1 -1
- package/dist/components/InputGroup/InputGroup.d.ts +37 -1
- package/dist/components/InputGroup/InputGroup.definitions.d.ts +6 -0
- package/dist/components/InputGroup/InputGroup.js +106 -93
- package/dist/components/InputGroup/InputGroup.js.map +1 -1
- package/dist/components/Modal/Modal.cjs +226 -116
- package/dist/components/Modal/Modal.cjs.map +1 -1
- package/dist/components/Modal/Modal.d.ts +38 -2
- package/dist/components/Modal/Modal.js +227 -117
- package/dist/components/Modal/Modal.js.map +1 -1
- package/dist/components/Modal/ModalFooter.d.ts +9 -1
- package/dist/components/Modal/index.d.ts +5 -0
- package/dist/components/PageLoader/PageLoader.cjs +61 -0
- package/dist/components/PageLoader/PageLoader.cjs.map +1 -0
- package/dist/components/PageLoader/PageLoader.d.ts +38 -0
- package/dist/components/PageLoader/PageLoader.js +61 -0
- package/dist/components/PageLoader/PageLoader.js.map +1 -0
- package/dist/components/PageLoader/index.d.ts +2 -0
- package/dist/components/PageLoader.d.ts +6 -0
- package/dist/components/ScrollTopButton/ScrollTopButton.cjs +79 -0
- package/dist/components/ScrollTopButton/ScrollTopButton.cjs.map +1 -0
- package/dist/components/ScrollTopButton/ScrollTopButton.d.ts +48 -0
- package/dist/components/ScrollTopButton/ScrollTopButton.js +79 -0
- package/dist/components/ScrollTopButton/ScrollTopButton.js.map +1 -0
- package/dist/components/ScrollTopButton/index.d.ts +4 -0
- package/dist/components/ScrollTopButton/scrollToTop.d.ts +29 -0
- package/dist/components/ScrollTopButton.d.ts +6 -0
- package/dist/components/Select/Select.cjs +446 -4
- package/dist/components/Select/Select.cjs.map +1 -1
- package/dist/components/Select/Select.d.ts +33 -13
- package/dist/components/Select/Select.definitions.d.ts +3 -0
- package/dist/components/Select/Select.helpers.d.ts +28 -0
- package/dist/components/Select/Select.js +445 -3
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/Select.sx.d.ts +7 -0
- package/dist/components/Select/Select.types.d.ts +1 -0
- package/dist/components/Select/_parts/SelectMenuItem.d.ts +20 -0
- package/dist/components/Select/_parts/SelectSearchHeader.d.ts +15 -0
- package/dist/components/Select/_parts/SelectValue.d.ts +22 -0
- package/dist/components/Select/index.d.ts +2 -1
- package/dist/components/Select.d.ts +4 -0
- package/dist/components/Stat/Stat.cjs +1 -1
- package/dist/components/Stat/Stat.js +1 -1
- package/dist/components/Stepper/Stepper.cjs +4 -1
- package/dist/components/Stepper/Stepper.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.d.ts +5 -0
- package/dist/components/Stepper/Stepper.js +4 -1
- package/dist/components/Stepper/Stepper.js.map +1 -1
- package/dist/components/_shared/formField.sx.d.ts +33 -0
- package/dist/components/_shared/resolvePreset.d.ts +18 -0
- package/dist/formField.sx-CQ1mbk9M.cjs +76 -0
- package/dist/formField.sx-CQ1mbk9M.cjs.map +1 -0
- package/dist/formField.sx-DfVbMe0V.js +77 -0
- package/dist/formField.sx-DfVbMe0V.js.map +1 -0
- package/dist/hooks/Wizard/Wizard.cjs +7 -0
- package/dist/hooks/Wizard/Wizard.cjs.map +1 -0
- package/dist/hooks/Wizard/Wizard.js +7 -0
- package/dist/hooks/Wizard/Wizard.js.map +1 -0
- package/dist/hooks/Wizard/WizardContext.d.ts +67 -0
- package/dist/hooks/Wizard/index.d.ts +3 -0
- package/dist/hooks/Wizard/useWizard.d.ts +9 -0
- package/dist/hooks/Wizard.d.ts +2 -0
- package/dist/index.cjs +99 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +31 -2
- package/dist/index.js.map +1 -1
- package/dist/mui.d.ts +5 -0
- package/dist/resolvePreset-B-IB0ehH.js +15 -0
- package/dist/resolvePreset-B-IB0ehH.js.map +1 -0
- package/dist/resolvePreset-CT3kU-K2.cjs +14 -0
- package/dist/resolvePreset-CT3kU-K2.cjs.map +1 -0
- package/dist/styles.css +3 -112
- package/dist/theme/componentStyles.d.ts +32 -0
- package/dist/theme/tokens.d.ts +28 -0
- package/dist/useWizard-CWdIxZzX.cjs +94 -0
- package/dist/useWizard-CWdIxZzX.cjs.map +1 -0
- package/dist/useWizard-CWq--C3o.js +95 -0
- package/dist/useWizard-CWq--C3o.js.map +1 -0
- package/package.json +1 -1
- package/src/components/ActionMenu/ActionMenu.stories.tsx +230 -0
- package/src/components/ActionMenu/ActionMenu.tsx +174 -0
- package/src/components/ActionMenu/index.ts +2 -0
- package/src/components/AppBar/AppBar.stories.tsx +272 -0
- package/src/components/AppBar/AppBar.sx.ts +32 -0
- package/src/components/AppBar/AppBar.tsx +123 -0
- package/src/components/AppBar/AppBarBrand.tsx +120 -0
- package/src/components/AppBar/AppBarContext.ts +25 -0
- package/src/components/AppBar/AppBarMenuToggle.tsx +90 -0
- package/src/components/AppBar/AppBarUserMenu.tsx +217 -0
- package/src/components/AppBar/index.ts +25 -0
- package/src/components/Autocomplete/Autocomplete.definitions.ts +223 -0
- package/src/components/Autocomplete/Autocomplete.helpers.ts +60 -0
- package/src/components/Autocomplete/Autocomplete.stories.tsx +363 -2
- package/src/components/Autocomplete/Autocomplete.sx.ts +30 -0
- package/src/components/Autocomplete/Autocomplete.tsx +312 -90
- package/src/components/Autocomplete/Autocomplete.types.ts +13 -0
- package/src/components/Autocomplete/_parts/AutocompleteChips.tsx +55 -0
- package/src/components/Autocomplete/_parts/AutocompleteLoader.tsx +17 -0
- package/src/components/Autocomplete/_parts/AutocompleteOption.tsx +31 -0
- package/src/components/Autocomplete/index.ts +12 -1
- package/src/components/Avatar/Avatar.definitions.ts +162 -0
- package/src/components/Avatar/Avatar.stories.tsx +205 -1
- package/src/components/Avatar/Avatar.tsx +166 -103
- package/src/components/Card/Card.stories.tsx +205 -16
- package/src/components/Card/Card.sx.ts +104 -0
- package/src/components/Card/Card.tsx +191 -35
- package/src/components/Card/index.ts +9 -1
- package/src/components/DatePicker/DatePicker.definitions.ts +24 -1
- package/src/components/DatePicker/DatePicker.helpers.ts +24 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +29 -2
- package/src/components/DatePicker/DatePicker.sx.ts +33 -0
- package/src/components/DatePicker/DatePicker.tsx +163 -139
- package/src/components/DatePicker/DatePicker.types.ts +10 -0
- package/src/components/DatePicker/index.ts +9 -1
- package/src/components/DateTimePicker/DateTimePicker.definitions.ts +24 -0
- package/src/components/DateTimePicker/DateTimePicker.helpers.ts +38 -0
- package/src/components/DateTimePicker/DateTimePicker.stories.tsx +29 -1
- package/src/components/DateTimePicker/DateTimePicker.sx.ts +30 -0
- package/src/components/DateTimePicker/DateTimePicker.tsx +200 -166
- package/src/components/DateTimePicker/DateTimePicker.types.ts +10 -0
- package/src/components/DateTimePicker/index.ts +9 -1
- package/src/components/Drawer/Drawer.stories.tsx +270 -0
- package/src/components/Drawer/Drawer.sx.ts +106 -0
- package/src/components/Drawer/Drawer.tsx +214 -0
- package/src/components/Drawer/DrawerContext.ts +26 -0
- package/src/components/Drawer/DrawerItem.tsx +110 -0
- package/src/components/Drawer/index.ts +10 -0
- package/src/components/Flyout/Flyout.stories.tsx +26 -18
- package/src/components/Icon/Icon.stories.tsx +68 -1
- package/src/components/Icon/Icon.tsx +87 -6
- package/src/components/Input/Input.definitions.ts +74 -2
- package/src/components/Input/Input.helpers.ts +49 -0
- package/src/components/Input/Input.stories.tsx +116 -4
- package/src/components/Input/Input.sx.ts +42 -0
- package/src/components/Input/Input.tsx +117 -162
- package/src/components/Input/Input.types.ts +10 -0
- package/src/components/Input/index.ts +9 -1
- package/src/components/InputGroup/InputGroup.definitions.ts +158 -0
- package/src/components/InputGroup/InputGroup.stories.tsx +159 -28
- package/src/components/InputGroup/InputGroup.tsx +159 -116
- package/src/components/Modal/Modal.stories.tsx +434 -6
- package/src/components/Modal/Modal.tsx +303 -121
- package/src/components/Modal/ModalFooter.tsx +22 -12
- package/src/components/Modal/index.ts +6 -1
- package/src/components/PageLoader/PageLoader.stories.tsx +217 -0
- package/src/components/PageLoader/PageLoader.tsx +96 -0
- package/src/components/PageLoader/index.ts +2 -0
- package/src/components/ScrollTopButton/ScrollTopButton.stories.tsx +158 -0
- package/src/components/ScrollTopButton/ScrollTopButton.tsx +135 -0
- package/src/components/ScrollTopButton/index.ts +8 -0
- package/src/components/ScrollTopButton/scrollToTop.ts +37 -0
- package/src/components/Select/Select.definitions.ts +114 -0
- package/src/components/Select/Select.helpers.ts +71 -0
- package/src/components/Select/Select.stories.tsx +126 -8
- package/src/components/Select/Select.sx.ts +14 -0
- package/src/components/Select/Select.tsx +246 -285
- package/src/components/Select/Select.types.ts +15 -0
- package/src/components/Select/_parts/SelectMenuItem.tsx +40 -0
- package/src/components/Select/_parts/SelectSearchHeader.tsx +51 -0
- package/src/components/Select/_parts/SelectValue.tsx +96 -0
- package/src/components/Select/index.ts +14 -1
- package/src/components/Stepper/Stepper.tsx +17 -1
- package/src/components/Tooltip/Tooltip.stories.tsx +15 -3
- package/src/components/_shared/formField.sx.ts +118 -0
- package/src/components/_shared/resolvePreset.ts +35 -0
- package/src/hooks/Wizard/Wizard.stories.tsx +301 -0
- package/src/hooks/Wizard/WizardContext.tsx +166 -0
- package/src/hooks/Wizard/index.ts +6 -0
- package/src/hooks/Wizard/useWizard.ts +13 -0
- package/src/index.ts +17 -1
- package/src/mui.ts +44 -0
- package/src/theme/componentStyles.ts +47 -0
- package/src/theme/tokens.ts +43 -0
- package/dist/DatePicker-BSNboVhN.js +0 -201
- package/dist/DatePicker-BSNboVhN.js.map +0 -1
- package/dist/DatePicker-BoqxWAhj.cjs +0 -200
- package/dist/DatePicker-BoqxWAhj.cjs.map +0 -1
- package/dist/Input-DFHs7cJ_.js +0 -171
- package/dist/Input-DFHs7cJ_.js.map +0 -1
- package/dist/Input-c8MwNNPg.cjs +0 -170
- package/dist/Input-c8MwNNPg.cjs.map +0 -1
- package/dist/Select-BO2N56sm.cjs +0 -411
- package/dist/Select-BO2N56sm.cjs.map +0 -1
- package/dist/Select-BcLkyHSE.js +0 -412
- package/dist/Select-BcLkyHSE.js.map +0 -1
- package/dist/index.css +0 -3
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React, { useState, useRef } from 'react'; // 👈 Importa useRef
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { useForm } from 'react-hook-form';
|
|
3
4
|
|
|
4
|
-
import { Button, Typography, Box } from '@mui/material';
|
|
5
|
+
import { Button, Typography, Box, Stack } from '@mui/material';
|
|
5
6
|
import { fn } from '@storybook/test';
|
|
6
7
|
import Modal, { ModalRef } from './Modal';
|
|
8
|
+
import { Input } from '../Input/Input';
|
|
7
9
|
import { useClipboard } from '../../hooks/ClipBoard';
|
|
8
10
|
|
|
9
11
|
const meta: Meta<typeof Modal> = {
|
|
@@ -230,9 +232,7 @@ export const Sizing: Story = {
|
|
|
230
232
|
render: (args: any) => {
|
|
231
233
|
const [openXs, setOpenXs] = useState(false);
|
|
232
234
|
const [openLg, setOpenLg] = useState(false);
|
|
233
|
-
const { ref,
|
|
234
|
-
|
|
235
|
-
|
|
235
|
+
const { ref, CopyMessage } = useClipboard();
|
|
236
236
|
|
|
237
237
|
return (
|
|
238
238
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
|
@@ -246,7 +246,7 @@ export const Sizing: Story = {
|
|
|
246
246
|
<Modal {...args} open={openLg} onClose={() => setOpenLg(false)} title="Modal LG" maxWidth="lg">
|
|
247
247
|
<Modal.Body>
|
|
248
248
|
<Typography ref={ref}>Este es un modal de tamaño grande.</Typography>
|
|
249
|
-
<
|
|
249
|
+
<CopyMessage />
|
|
250
250
|
</Modal.Body>
|
|
251
251
|
</Modal>
|
|
252
252
|
</Box>
|
|
@@ -290,4 +290,432 @@ export const LongContent: Story = {
|
|
|
290
290
|
},
|
|
291
291
|
},
|
|
292
292
|
},
|
|
293
|
-
};
|
|
293
|
+
};
|
|
294
|
+
// =============================================================================
|
|
295
|
+
// RHF DENTRO DEL MODAL — Botones a nivel de BODY (forma recomendada)
|
|
296
|
+
// =============================================================================
|
|
297
|
+
// PROBLEMA: Si los botones viven en `Modal.Footer` (hermano de `Modal.Body`),
|
|
298
|
+
// el `<form>` no puede envolver a ambos porque son hermanos en el árbol.
|
|
299
|
+
// Entonces "Guardar" NO dispara submit ni validaciones.
|
|
300
|
+
//
|
|
301
|
+
// SOLUCIÓN: Meter el `<form>` + inputs + botones dentro del mismo `Modal.Body`.
|
|
302
|
+
// Usar `hiddenFooter` para ocultar el footer por defecto.
|
|
303
|
+
// =============================================================================
|
|
304
|
+
|
|
305
|
+
type UserFormValues = {
|
|
306
|
+
name: string;
|
|
307
|
+
email: string;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export const RHFInsideBody: Story = {
|
|
311
|
+
render: () => {
|
|
312
|
+
const [open, setOpen] = useState(false);
|
|
313
|
+
const [submitted, setSubmitted] = useState<UserFormValues | null>(null);
|
|
314
|
+
|
|
315
|
+
const {
|
|
316
|
+
control,
|
|
317
|
+
handleSubmit,
|
|
318
|
+
reset,
|
|
319
|
+
formState: { isSubmitting },
|
|
320
|
+
} = useForm<UserFormValues>({
|
|
321
|
+
defaultValues: { name: '', email: '' },
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const onSubmit = async (data: UserFormValues) => {
|
|
325
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
326
|
+
setSubmitted(data);
|
|
327
|
+
setOpen(false);
|
|
328
|
+
reset();
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const handleClose = () => {
|
|
332
|
+
setOpen(false);
|
|
333
|
+
reset();
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<Box>
|
|
338
|
+
<Button variant="contained" onClick={() => setOpen(true)}>
|
|
339
|
+
Abrir form en Modal
|
|
340
|
+
</Button>
|
|
341
|
+
{submitted && (
|
|
342
|
+
<Typography sx={{ mt: 2 }} color="success.main">
|
|
343
|
+
Enviado: {JSON.stringify(submitted)}
|
|
344
|
+
</Typography>
|
|
345
|
+
)}
|
|
346
|
+
|
|
347
|
+
<Modal
|
|
348
|
+
open={open}
|
|
349
|
+
onClose={handleClose}
|
|
350
|
+
title="Crear usuario"
|
|
351
|
+
maxWidth="sm"
|
|
352
|
+
hiddenFooter // 👈 ocultamos el footer por defecto
|
|
353
|
+
>
|
|
354
|
+
<Modal.Body>
|
|
355
|
+
{/* El form envuelve TODO: inputs + botones.
|
|
356
|
+
Los botones están dentro del body, NO en un footer. */}
|
|
357
|
+
<Box
|
|
358
|
+
component="form"
|
|
359
|
+
onSubmit={handleSubmit(onSubmit)}
|
|
360
|
+
noValidate
|
|
361
|
+
paddingTop={2}
|
|
362
|
+
>
|
|
363
|
+
<Stack spacing={3}>
|
|
364
|
+
<Input
|
|
365
|
+
name="name"
|
|
366
|
+
control={control}
|
|
367
|
+
label="Nombre"
|
|
368
|
+
validation={{
|
|
369
|
+
required: 'El nombre es requerido',
|
|
370
|
+
minLength: { value: 2, message: 'Mínimo 2 caracteres' },
|
|
371
|
+
}}
|
|
372
|
+
/>
|
|
373
|
+
<Input
|
|
374
|
+
name="email"
|
|
375
|
+
control={control}
|
|
376
|
+
label="Email"
|
|
377
|
+
type="email"
|
|
378
|
+
validation={{
|
|
379
|
+
required: 'El email es requerido',
|
|
380
|
+
pattern: {
|
|
381
|
+
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
382
|
+
message: 'Email inválido',
|
|
383
|
+
},
|
|
384
|
+
}}
|
|
385
|
+
/>
|
|
386
|
+
|
|
387
|
+
{/* Botones DENTRO del form, a nivel del body. */}
|
|
388
|
+
<Stack
|
|
389
|
+
direction="row"
|
|
390
|
+
spacing={1}
|
|
391
|
+
justifyContent="flex-end"
|
|
392
|
+
sx={{ pt: 1 }}
|
|
393
|
+
>
|
|
394
|
+
<Button
|
|
395
|
+
type="button"
|
|
396
|
+
variant="text"
|
|
397
|
+
onClick={handleClose}
|
|
398
|
+
disabled={isSubmitting}
|
|
399
|
+
>
|
|
400
|
+
Cancelar
|
|
401
|
+
</Button>
|
|
402
|
+
<Button
|
|
403
|
+
type="submit"
|
|
404
|
+
variant="contained"
|
|
405
|
+
disabled={isSubmitting}
|
|
406
|
+
>
|
|
407
|
+
{isSubmitting ? 'Guardando...' : 'Guardar'}
|
|
408
|
+
</Button>
|
|
409
|
+
</Stack>
|
|
410
|
+
</Stack>
|
|
411
|
+
</Box>
|
|
412
|
+
</Modal.Body>
|
|
413
|
+
</Modal>
|
|
414
|
+
</Box>
|
|
415
|
+
);
|
|
416
|
+
},
|
|
417
|
+
parameters: {
|
|
418
|
+
docs: {
|
|
419
|
+
description: {
|
|
420
|
+
story: [
|
|
421
|
+
'**Modal + React Hook Form con botones a nivel del Body (recomendado).**',
|
|
422
|
+
'',
|
|
423
|
+
'Cuando usás RHF dentro de un modal, los botones de submit/cancel deben',
|
|
424
|
+
'vivir dentro del mismo `<form>` que los inputs. Si ponés los botones',
|
|
425
|
+
'en `Modal.Footer`, quedan en un subárbol hermano al Body y el submit',
|
|
426
|
+
'no dispara porque el `<form>` no los envuelve.',
|
|
427
|
+
'',
|
|
428
|
+
'La solución es:',
|
|
429
|
+
'1. Usar `hiddenFooter` en el Modal para ocultar el footer por defecto.',
|
|
430
|
+
'2. Meter el `<form>`, los inputs y los botones todos dentro de `Modal.Body`.',
|
|
431
|
+
'3. El botón de submit usa `type="submit"`, que dispara el `onSubmit` del form.',
|
|
432
|
+
].join('\n'),
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// =============================================================================
|
|
439
|
+
// RHF con botones en FOOTER usando formId (alternativa avanzada)
|
|
440
|
+
// =============================================================================
|
|
441
|
+
// Si querés mantener el layout clásico (botones en footer, form en body), la
|
|
442
|
+
// forma correcta es conectar el botón al form por su atributo `form=""`.
|
|
443
|
+
// Esto sí funciona con HTML5 nativo: un `<button form="myFormId">` fuera del
|
|
444
|
+
// `<form>` sigue disparando el submit.
|
|
445
|
+
// =============================================================================
|
|
446
|
+
|
|
447
|
+
// =============================================================================
|
|
448
|
+
// MODO CONFIRM — reemplazo del ConfirmModal legacy
|
|
449
|
+
// =============================================================================
|
|
450
|
+
|
|
451
|
+
export const ConfirmInfo: Story = {
|
|
452
|
+
render: () => {
|
|
453
|
+
const [open, setOpen] = useState(false);
|
|
454
|
+
return (
|
|
455
|
+
<Box>
|
|
456
|
+
<Button variant="contained" onClick={() => setOpen(true)}>
|
|
457
|
+
Abrir confirm (info)
|
|
458
|
+
</Button>
|
|
459
|
+
<Modal
|
|
460
|
+
mode="confirm"
|
|
461
|
+
open={open}
|
|
462
|
+
onClose={() => setOpen(false)}
|
|
463
|
+
title="¿Deseas continuar?"
|
|
464
|
+
confirmMessage="Esta acción guardará los cambios realizados en el formulario."
|
|
465
|
+
confirmText="Sí, continuar"
|
|
466
|
+
closeButtonText="Cancelar"
|
|
467
|
+
onConfirm={() => console.log('confirmed')}
|
|
468
|
+
/>
|
|
469
|
+
</Box>
|
|
470
|
+
);
|
|
471
|
+
},
|
|
472
|
+
parameters: {
|
|
473
|
+
docs: {
|
|
474
|
+
description: {
|
|
475
|
+
story: 'Confirm de severidad `info` (default). Layout centrado con icono circular, título, mensaje y botones Cancelar / Confirmar.',
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
export const ConfirmDelete: Story = {
|
|
482
|
+
render: () => {
|
|
483
|
+
const [open, setOpen] = useState(false);
|
|
484
|
+
return (
|
|
485
|
+
<Box>
|
|
486
|
+
<Button variant="outlined" color="error" onClick={() => setOpen(true)}>
|
|
487
|
+
Eliminar afiliación
|
|
488
|
+
</Button>
|
|
489
|
+
<Modal
|
|
490
|
+
mode="confirm"
|
|
491
|
+
severity="error"
|
|
492
|
+
open={open}
|
|
493
|
+
onClose={() => setOpen(false)}
|
|
494
|
+
title="Eliminar afiliación"
|
|
495
|
+
confirmMessage="Esta acción no se puede deshacer. ¿Confirmas que deseas eliminar la afiliación #12458?"
|
|
496
|
+
confirmText="Sí, eliminar"
|
|
497
|
+
closeButtonText="Cancelar"
|
|
498
|
+
onConfirm={() => console.log('deleted')}
|
|
499
|
+
/>
|
|
500
|
+
</Box>
|
|
501
|
+
);
|
|
502
|
+
},
|
|
503
|
+
parameters: {
|
|
504
|
+
docs: {
|
|
505
|
+
description: {
|
|
506
|
+
story: 'Confirm de severidad `error` — icono rojo y botón primario rojo. Patrón típico para operaciones destructivas.',
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
export const ConfirmWarning: Story = {
|
|
513
|
+
render: () => {
|
|
514
|
+
const [open, setOpen] = useState(false);
|
|
515
|
+
return (
|
|
516
|
+
<Box>
|
|
517
|
+
<Button variant="contained" color="warning" onClick={() => setOpen(true)}>
|
|
518
|
+
Salir sin guardar
|
|
519
|
+
</Button>
|
|
520
|
+
<Modal
|
|
521
|
+
mode="confirm"
|
|
522
|
+
severity="warning"
|
|
523
|
+
open={open}
|
|
524
|
+
onClose={() => setOpen(false)}
|
|
525
|
+
title="Tienes cambios sin guardar"
|
|
526
|
+
confirmMessage="Si sales ahora perderás los cambios realizados. ¿Deseas salir igualmente?"
|
|
527
|
+
confirmText="Salir sin guardar"
|
|
528
|
+
closeButtonText="Seguir editando"
|
|
529
|
+
onConfirm={() => console.log('discarded')}
|
|
530
|
+
/>
|
|
531
|
+
</Box>
|
|
532
|
+
);
|
|
533
|
+
},
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
export const ConfirmSuccess: Story = {
|
|
537
|
+
render: () => {
|
|
538
|
+
const [open, setOpen] = useState(false);
|
|
539
|
+
return (
|
|
540
|
+
<Box>
|
|
541
|
+
<Button variant="contained" color="success" onClick={() => setOpen(true)}>
|
|
542
|
+
Aprobar solicitud
|
|
543
|
+
</Button>
|
|
544
|
+
<Modal
|
|
545
|
+
mode="confirm"
|
|
546
|
+
severity="success"
|
|
547
|
+
open={open}
|
|
548
|
+
onClose={() => setOpen(false)}
|
|
549
|
+
title="Aprobar solicitud"
|
|
550
|
+
confirmMessage="Al aprobar, el cliente recibirá una notificación y se activará su afiliación."
|
|
551
|
+
confirmText="Aprobar"
|
|
552
|
+
closeButtonText="Cancelar"
|
|
553
|
+
onConfirm={() => console.log('approved')}
|
|
554
|
+
/>
|
|
555
|
+
</Box>
|
|
556
|
+
);
|
|
557
|
+
},
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
export const ConfirmAsync: Story = {
|
|
561
|
+
render: () => {
|
|
562
|
+
const [open, setOpen] = useState(false);
|
|
563
|
+
const [result, setResult] = useState<string | null>(null);
|
|
564
|
+
|
|
565
|
+
const simulateRequest = () =>
|
|
566
|
+
new Promise<void>((resolve) => {
|
|
567
|
+
setTimeout(() => {
|
|
568
|
+
setResult('Ejecutado después de 1.5s');
|
|
569
|
+
resolve();
|
|
570
|
+
}, 1500);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
return (
|
|
574
|
+
<Box>
|
|
575
|
+
<Button variant="contained" onClick={() => setOpen(true)}>
|
|
576
|
+
Confirmar con request async
|
|
577
|
+
</Button>
|
|
578
|
+
{result && (
|
|
579
|
+
<Typography sx={{ mt: 2 }} color="success.main">
|
|
580
|
+
{result}
|
|
581
|
+
</Typography>
|
|
582
|
+
)}
|
|
583
|
+
<Modal
|
|
584
|
+
mode="confirm"
|
|
585
|
+
open={open}
|
|
586
|
+
onClose={() => setOpen(false)}
|
|
587
|
+
title="Procesar afiliación"
|
|
588
|
+
confirmMessage="Esto enviará la solicitud al backend y puede tardar unos segundos."
|
|
589
|
+
confirmText="Procesar"
|
|
590
|
+
onConfirm={simulateRequest}
|
|
591
|
+
/>
|
|
592
|
+
</Box>
|
|
593
|
+
);
|
|
594
|
+
},
|
|
595
|
+
parameters: {
|
|
596
|
+
docs: {
|
|
597
|
+
description: {
|
|
598
|
+
story: 'El `onConfirm` puede devolver una `Promise`. Mientras resuelve, los botones quedan deshabilitados para evitar clicks dobles. Al resolver, el modal cierra automáticamente.',
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
export const RHFWithFooterFormId: Story = {
|
|
605
|
+
render: () => {
|
|
606
|
+
const [open, setOpen] = useState(false);
|
|
607
|
+
const [submitted, setSubmitted] = useState<UserFormValues | null>(null);
|
|
608
|
+
|
|
609
|
+
const {
|
|
610
|
+
control,
|
|
611
|
+
handleSubmit,
|
|
612
|
+
reset,
|
|
613
|
+
formState: { isSubmitting },
|
|
614
|
+
} = useForm<UserFormValues>({
|
|
615
|
+
defaultValues: { name: '', email: '' },
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
const FORM_ID = 'user-form-footer';
|
|
619
|
+
|
|
620
|
+
const onSubmit = async (data: UserFormValues) => {
|
|
621
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
622
|
+
setSubmitted(data);
|
|
623
|
+
setOpen(false);
|
|
624
|
+
reset();
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
const handleClose = () => {
|
|
628
|
+
setOpen(false);
|
|
629
|
+
reset();
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
return (
|
|
633
|
+
<Box>
|
|
634
|
+
<Button variant="contained" onClick={() => setOpen(true)}>
|
|
635
|
+
Abrir form (footer con formId)
|
|
636
|
+
</Button>
|
|
637
|
+
{submitted && (
|
|
638
|
+
<Typography sx={{ mt: 2 }} color="success.main">
|
|
639
|
+
Enviado: {JSON.stringify(submitted)}
|
|
640
|
+
</Typography>
|
|
641
|
+
)}
|
|
642
|
+
|
|
643
|
+
<Modal
|
|
644
|
+
open={open}
|
|
645
|
+
onClose={handleClose}
|
|
646
|
+
title="Crear usuario (footer)"
|
|
647
|
+
maxWidth="sm"
|
|
648
|
+
actions={[
|
|
649
|
+
{
|
|
650
|
+
text: isSubmitting ? 'Guardando...' : 'Guardar',
|
|
651
|
+
// 👇 clave: el botón referencia al form por id.
|
|
652
|
+
buttonProps: {
|
|
653
|
+
type: 'submit',
|
|
654
|
+
form: FORM_ID,
|
|
655
|
+
variant: 'contained',
|
|
656
|
+
disabled: isSubmitting,
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
]}
|
|
660
|
+
closeButtonText="Cancelar"
|
|
661
|
+
>
|
|
662
|
+
<Modal.Body>
|
|
663
|
+
<Box
|
|
664
|
+
component="form"
|
|
665
|
+
id={FORM_ID}
|
|
666
|
+
onSubmit={handleSubmit(onSubmit)}
|
|
667
|
+
noValidate
|
|
668
|
+
paddingTop={2}
|
|
669
|
+
>
|
|
670
|
+
<Stack spacing={3}>
|
|
671
|
+
<Input
|
|
672
|
+
name="name"
|
|
673
|
+
control={control}
|
|
674
|
+
label="Nombre"
|
|
675
|
+
validation={{
|
|
676
|
+
required: 'El nombre es requerido',
|
|
677
|
+
}}
|
|
678
|
+
/>
|
|
679
|
+
<Input
|
|
680
|
+
name="email"
|
|
681
|
+
control={control}
|
|
682
|
+
label="Email"
|
|
683
|
+
type="email"
|
|
684
|
+
validation={{
|
|
685
|
+
required: 'El email es requerido',
|
|
686
|
+
pattern: {
|
|
687
|
+
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
688
|
+
message: 'Email inválido',
|
|
689
|
+
},
|
|
690
|
+
}}
|
|
691
|
+
/>
|
|
692
|
+
</Stack>
|
|
693
|
+
</Box>
|
|
694
|
+
</Modal.Body>
|
|
695
|
+
</Modal>
|
|
696
|
+
</Box>
|
|
697
|
+
);
|
|
698
|
+
},
|
|
699
|
+
parameters: {
|
|
700
|
+
docs: {
|
|
701
|
+
description: {
|
|
702
|
+
story: [
|
|
703
|
+
'**Alternativa avanzada: botones en el footer usando `form="formId"`.**',
|
|
704
|
+
'',
|
|
705
|
+
'Si necesitás mantener el layout clásico (Header / Body / Footer) con los',
|
|
706
|
+
'botones en el footer, la forma correcta es asignarle un `id` al `<form>`',
|
|
707
|
+
'y al botón de submit le pasás `form="mismoId"`. HTML5 nativo conecta',
|
|
708
|
+
'el botón con el form aunque no sean hermanos en el DOM.',
|
|
709
|
+
'',
|
|
710
|
+
'```tsx',
|
|
711
|
+
'<form id="user-form" onSubmit={handleSubmit(onSubmit)}>...</form>',
|
|
712
|
+
'<button type="submit" form="user-form">Guardar</button>',
|
|
713
|
+
'```',
|
|
714
|
+
'',
|
|
715
|
+
'Es la alternativa cuando querés reutilizar `Modal.Footer` con sus `actions`',
|
|
716
|
+
'en lugar de construir los botones a mano dentro del body.',
|
|
717
|
+
].join('\n'),
|
|
718
|
+
},
|
|
719
|
+
},
|
|
720
|
+
},
|
|
721
|
+
};
|