@axzydev/axzy_ui_system 1.4.7 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -11
- package/dist/index.cjs +2174 -1570
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +232 -19
- package/dist/index.d.ts +232 -19
- package/dist/index.js +1838 -1238
- package/dist/index.js.map +1 -1
- package/dist/layered.css +1 -1
- package/package.json +3 -16
- package/src/App.tsx +90 -73
- package/src/components/atoms/badget/badget.tsx +23 -5
- package/src/components/atoms/chip/chip.tsx +3 -1
- package/src/components/atoms/image/image.tsx +3 -1
- package/src/components/atoms/input/input.tsx +8 -5
- package/src/components/atoms/loader/loader.tsx +3 -1
- package/src/components/atoms/slide/slide.props.ts +12 -0
- package/src/components/atoms/slide/slide.tsx +3 -0
- package/src/components/molecules/alert/alert.tsx +3 -1
- package/src/components/molecules/breadcrumbs/breadcrumbs.tsx +3 -1
- package/src/components/molecules/calendar/calendar.tsx +9 -6
- package/src/components/molecules/card/card.tsx +5 -2
- package/src/components/molecules/chip-input/chip-input.tsx +9 -7
- package/src/components/molecules/date-picker/datePicker.tsx +9 -9
- package/src/components/molecules/dropdown-menu/dropdown-menu.props.ts +1 -1
- package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +6 -3
- package/src/components/molecules/field/field.tsx +3 -1
- package/src/components/molecules/form-header/form-header.tsx +3 -1
- package/src/components/molecules/line-bar-chart/line-bar-chart.props.ts +2 -2
- package/src/components/molecules/line-bar-chart/line-bar-chart.tsx +20 -15
- package/src/components/molecules/masked-input/masked-input.tsx +3 -1
- package/src/components/molecules/multi-select/multi-select.tsx +12 -9
- package/src/components/molecules/pagination/pagination.tsx +11 -5
- package/src/components/molecules/search-select/search-select.tsx +11 -9
- package/src/components/molecules/select/select.tsx +6 -4
- package/src/components/molecules/stepper/stepper.tsx +6 -4
- package/src/components/molecules/table/table.props.ts +10 -2
- package/src/components/molecules/table/table.tsx +163 -114
- package/src/components/molecules/time-picker/timePicker.tsx +8 -6
- package/src/components/molecules/wysiwyg/wysiwyg.tsx +23 -12
- package/src/components/organisms/confirm-dialog/confirm-dialog.props.ts +4 -4
- package/src/components/organisms/confirm-dialog/confirm-dialog.tsx +16 -8
- package/src/components/organisms/data-table/dataTable.props.ts +3 -2
- package/src/components/organisms/data-table/dataTable.tsx +149 -81
- package/src/components/organisms/dialog/dialog.tsx +3 -0
- package/src/components/organisms/drawer/drawer.tsx +3 -0
- package/src/components/organisms/dropfile/dropfile.tsx +19 -17
- package/src/components/organisms/form-builder/fieldRenderer.tsx +4 -2
- package/src/components/organisms/navbar/navbar.tsx +4 -2
- package/src/components/organisms/page-header/page-header.tsx +3 -1
- package/src/components/organisms/searchTable/components/PaginationControls.tsx +8 -6
- package/src/components/organisms/searchTable/components/PaginationInfo.tsx +3 -1
- package/src/components/organisms/searchTable/components/SearchAndSortBar.tsx +7 -5
- package/src/components/organisms/searchTable/components/SearchInput.tsx +4 -2
- package/src/components/organisms/searchTable/components/SortButton.tsx +13 -11
- package/src/components/organisms/searchTable/components/TableEmptyState.tsx +4 -2
- package/src/components/organisms/searchTable/components/TableRow.tsx +6 -4
- package/src/components/organisms/searchTable/searchTable.tsx +4 -2
- package/src/components/organisms/sidebar/sidebar.props.ts +1 -1
- package/src/components/organisms/sidebar/sidebar.tsx +9 -4
- package/src/components/organisms/toast/toast.tsx +3 -1
- package/src/components/organisms/topbar/topbar.tsx +4 -2
- package/src/components/templates/page/page.props.ts +4 -4
- package/src/components/templates/page/page.tsx +6 -4
- package/src/components/theme-provider/themeProvider.tsx +28 -17
- package/src/dev.css +77 -2
- package/src/global.d.ts +10 -0
- package/src/i18n/context.ts +9 -0
- package/src/i18n/index.ts +22 -0
- package/src/i18n/locales/en.ts +163 -0
- package/src/i18n/locales/es.ts +165 -0
- package/src/i18n/provider.tsx +44 -0
- package/src/i18n/translator.ts +82 -0
- package/src/i18n/types.ts +54 -0
- package/src/i18n/useITTranslation.ts +20 -0
- package/src/index.css +0 -1
- package/src/index.ts +9 -3
- package/src/sandbox/LandingShowcase.tsx +224 -580
- package/src/sandbox/NotFoundShowcase.tsx +51 -36
- package/src/sandbox/TopbarSearch.tsx +6 -4
- package/src/sandbox/controls.tsx +180 -0
- package/src/sandbox/i18n.ts +1929 -0
- package/src/sandbox/icons.tsx +25 -0
- package/src/sandbox/locale.tsx +72 -0
- package/src/sandbox/ui.tsx +377 -0
- package/src/sandbox/useHashRoute.ts +46 -10
- package/src/showcases/DataShowcases.tsx +201 -80
- package/src/showcases/FeedbackShowcases.tsx +37 -30
- package/src/showcases/FormShowcases.tsx +302 -214
- package/src/showcases/GettingStartedShowcase.tsx +151 -145
- package/src/showcases/HelpShowcase.tsx +126 -128
- package/src/showcases/HomeShowcase.tsx +678 -482
- package/src/showcases/LayoutPrimitivesShowcases.tsx +129 -114
- package/src/showcases/NavigationShowcases.tsx +45 -37
- package/src/showcases/PageShowcases.tsx +171 -152
- package/src/showcases/ProductoDetalle.tsx +272 -129
- package/src/showcases/ShowcaseLayout.tsx +270 -216
- package/src/showcases/SizesShowcase.tsx +123 -64
- package/src/showcases/StructureShowcases.tsx +157 -131
- package/src/showcases/portfolioUi.tsx +153 -0
- package/src/showcases/techIcons.ts +3 -0
- package/src/types/table.types.ts +110 -0
- package/src/utils/table.utils.ts +10 -2
- package/src/components/atoms/avatar/avatar.doc.mdx +0 -48
- package/src/components/atoms/avatar/avatar.stories.tsx +0 -64
- package/src/components/atoms/badget/badget.doc.mdx +0 -46
- package/src/components/atoms/badget/badget.stories.tsx +0 -75
- package/src/components/atoms/button/button.doc.mdx +0 -59
- package/src/components/atoms/button/button.stories.tsx +0 -173
- package/src/components/atoms/checkbox/checkbox.doc.mdx +0 -54
- package/src/components/atoms/checkbox/checkbox.stories.tsx +0 -53
- package/src/components/atoms/chip/chip.doc.mdx +0 -47
- package/src/components/atoms/chip/chip.stories.tsx +0 -64
- package/src/components/atoms/divider/divider.doc.mdx +0 -42
- package/src/components/atoms/divider/divider.stories.tsx +0 -33
- package/src/components/atoms/flex/flex.doc.mdx +0 -59
- package/src/components/atoms/flex/flex.stories.tsx +0 -70
- package/src/components/atoms/grid/grid.doc.mdx +0 -54
- package/src/components/atoms/grid/grid.stories.tsx +0 -71
- package/src/components/atoms/image/image.doc.mdx +0 -44
- package/src/components/atoms/image/image.stories.tsx +0 -48
- package/src/components/atoms/input/input.doc.mdx +0 -70
- package/src/components/atoms/input/input.stories.tsx +0 -113
- package/src/components/atoms/input-number/input-number.doc.mdx +0 -74
- package/src/components/atoms/input-number/input-number.stories.tsx +0 -111
- package/src/components/atoms/loader/loader.doc.mdx +0 -43
- package/src/components/atoms/loader/loader.stories.tsx +0 -104
- package/src/components/atoms/popover/popover.doc.mdx +0 -53
- package/src/components/atoms/popover/popover.stories.tsx +0 -24
- package/src/components/atoms/progress/progress.doc.mdx +0 -48
- package/src/components/atoms/progress/progress.stories.tsx +0 -39
- package/src/components/atoms/radio/radio.doc.mdx +0 -62
- package/src/components/atoms/radio/radio.stories.tsx +0 -48
- package/src/components/atoms/segmented-control/segmented-control.doc.mdx +0 -60
- package/src/components/atoms/segmented-control/segmented-control.stories.tsx +0 -62
- package/src/components/atoms/skeleton/skeleton.doc.mdx +0 -43
- package/src/components/atoms/skeleton/skeleton.stories.tsx +0 -29
- package/src/components/atoms/slide/slide.doc.mdx +0 -46
- package/src/components/atoms/slide/slide.stories.tsx +0 -120
- package/src/components/atoms/slider/slider.doc.mdx +0 -49
- package/src/components/atoms/slider/slider.stories.tsx +0 -29
- package/src/components/atoms/stack/stack.doc.mdx +0 -126
- package/src/components/atoms/stack/stack.stories.tsx +0 -283
- package/src/components/atoms/text/text.doc.mdx +0 -41
- package/src/components/atoms/text/text.stories.tsx +0 -66
- package/src/components/atoms/textarea/textarea.doc.mdx +0 -64
- package/src/components/atoms/textarea/textarea.stories.tsx +0 -26
- package/src/components/atoms/tooltip/tooltip.doc.mdx +0 -47
- package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -19
- package/src/components/isolation/isolation.stories.tsx +0 -202
- package/src/components/molecules/accordion/accordion.doc.mdx +0 -47
- package/src/components/molecules/accordion/accordion.stories.tsx +0 -68
- package/src/components/molecules/alert/alert.doc.mdx +0 -48
- package/src/components/molecules/alert/alert.stories.tsx +0 -40
- package/src/components/molecules/breadcrumbs/breadcrumbs.doc.mdx +0 -57
- package/src/components/molecules/breadcrumbs/breadcrumbs.stories.tsx +0 -20
- package/src/components/molecules/calendar/calendar.doc.mdx +0 -76
- package/src/components/molecules/calendar/calendar.stories.tsx +0 -90
- package/src/components/molecules/card/card.doc.mdx +0 -54
- package/src/components/molecules/card/card.stories.tsx +0 -57
- package/src/components/molecules/chip-input/chip-input.doc.mdx +0 -44
- package/src/components/molecules/chip-input/chip-input.stories.tsx +0 -52
- package/src/components/molecules/date-picker/date-picker.doc.mdx +0 -65
- package/src/components/molecules/date-picker/date-picker.stories.tsx +0 -88
- package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +0 -46
- package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +0 -41
- package/src/components/molecules/empty-state/empty-state.doc.mdx +0 -50
- package/src/components/molecules/empty-state/empty-state.stories.tsx +0 -19
- package/src/components/molecules/field/field.doc.mdx +0 -43
- package/src/components/molecules/field/field.stories.tsx +0 -42
- package/src/components/molecules/form-header/form-header.doc.mdx +0 -38
- package/src/components/molecules/form-header/form-header.stories.tsx +0 -52
- package/src/components/molecules/masked-input/masked-input.doc.mdx +0 -78
- package/src/components/molecules/masked-input/masked-input.stories.tsx +0 -126
- package/src/components/molecules/multi-select/multi-select.doc.mdx +0 -55
- package/src/components/molecules/multi-select/multi-select.stories.tsx +0 -59
- package/src/components/molecules/pagination/pagination.doc.mdx +0 -62
- package/src/components/molecules/pagination/pagination.stories.tsx +0 -110
- package/src/components/molecules/search-select/search-select.doc.mdx +0 -77
- package/src/components/molecules/search-select/search-select.stories.tsx +0 -146
- package/src/components/molecules/select/select.doc.mdx +0 -75
- package/src/components/molecules/select/select.stories.tsx +0 -85
- package/src/components/molecules/stat-card/stat-card.doc.mdx +0 -48
- package/src/components/molecules/stat-card/stat-card.stories.tsx +0 -40
- package/src/components/molecules/stepper/stepper.doc.mdx +0 -54
- package/src/components/molecules/stepper/stepper.stories.tsx +0 -154
- package/src/components/molecules/table/table.doc.mdx +0 -123
- package/src/components/molecules/table/table.stories.tsx +0 -402
- package/src/components/molecules/tabs/tabs.doc.mdx +0 -52
- package/src/components/molecules/tabs/tabs.stories.tsx +0 -31
- package/src/components/molecules/time-picker/timePicker.doc.mdx +0 -68
- package/src/components/molecules/time-picker/timePicker.stories.tsx +0 -130
- package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +0 -95
- package/src/components/organisms/confirm-dialog/confirm-dialog.doc.mdx +0 -60
- package/src/components/organisms/confirm-dialog/confirm-dialog.stories.tsx +0 -32
- package/src/components/organisms/data-table/ITDataTable.doc.mdx +0 -115
- package/src/components/organisms/data-table/ITDataTable.stories.tsx +0 -353
- package/src/components/organisms/dialog/dialog.doc.mdx +0 -54
- package/src/components/organisms/dialog/dialog.stories.tsx +0 -126
- package/src/components/organisms/drawer/drawer.doc.mdx +0 -59
- package/src/components/organisms/drawer/drawer.stories.tsx +0 -40
- package/src/components/organisms/dropfile/dropfile.doc.mdx +0 -74
- package/src/components/organisms/dropfile/dropfile.stories.tsx +0 -93
- package/src/components/organisms/form-builder/formBuilder.doc.mdx +0 -251
- package/src/components/organisms/form-builder/formBuilder.stories.tsx +0 -914
- package/src/components/organisms/navbar/navbar.doc.mdx +0 -77
- package/src/components/organisms/navbar/navbar.stories.tsx +0 -83
- package/src/components/organisms/page-header/page-header.doc.mdx +0 -54
- package/src/components/organisms/page-header/page-header.stories.tsx +0 -74
- package/src/components/organisms/searchTable/searchTable.doc.mdx +0 -79
- package/src/components/organisms/searchTable/searchTable.stories.tsx +0 -73
- package/src/components/organisms/sidebar/sidebar.doc.mdx +0 -176
- package/src/components/organisms/sidebar/sidebar.stories.tsx +0 -234
- package/src/components/organisms/toast/toast.doc.mdx +0 -50
- package/src/components/organisms/toast/toast.stories.tsx +0 -137
- package/src/components/organisms/topbar/topbar.doc.mdx +0 -72
- package/src/components/organisms/topbar/topbar.stories.tsx +0 -79
- package/src/components/organisms/triple-filter/tripleFilter.doc.mdx +0 -62
- package/src/components/organisms/triple-filter/tripleFilter.stories.tsx +0 -31
- package/src/components/templates/layout/layout.doc.mdx +0 -53
- package/src/components/templates/layout/layout.stories.tsx +0 -113
- package/src/components/templates/page/page.doc.mdx +0 -86
- package/src/components/templates/page/page.stories.tsx +0 -97
- package/src/components/theme-provider/themeProvider.doc.mdx +0 -85
- package/src/components/theme-provider/themeProvider.stories.tsx +0 -58
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './dropfile.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITDropfile
|
|
7
|
-
|
|
8
|
-
A drag-and-drop file upload zone with preview support for images. Tracks upload lifecycle with status enumeration and provides confirm/cancel actions. Configurable accepted file types limit which formats are allowed.
|
|
9
|
-
|
|
10
|
-
## Props
|
|
11
|
-
|
|
12
|
-
| Prop | Type | Default | Description |
|
|
13
|
-
|------|------|---------|-------------|
|
|
14
|
-
| `onFileSelect` | `(file: File \| null) => void` | — | Called when a file is selected or cleared. |
|
|
15
|
-
| `onCancel` | `() => void` | — | Called when the user cancels the current selection. |
|
|
16
|
-
| `onSubmit` | `(file: File) => void` | — | Called when the user confirms and submits the file. |
|
|
17
|
-
| `acceptedFileTypes` | `FileTypeEnum[]` | — | List of accepted MIME types (PDF, XLS, CSV, PNG, JPG, etc.). |
|
|
18
|
-
| `contentClassName` | `string` | — | CSS classes for the preview/content area. |
|
|
19
|
-
| `containerClassName` | `string` | — | CSS classes for the outermost container. |
|
|
20
|
-
| `showStatusBadge` | `boolean` | — | Whether to show the status badge (pending/uploading/uploaded/error). |
|
|
21
|
-
| `uploadStatus` | `UploadStatus` | — | Externally controlled upload status. |
|
|
22
|
-
| `onStatusChange` | `(status: UploadStatus) => void` | — | Callback when upload status changes. |
|
|
23
|
-
| `initialPreviewUrl` | `string \| null` | — | Initial preview URL shown before any file is selected (e.g., editing an existing entry). |
|
|
24
|
-
| `view` | `"drop" \| "button"` | `"drop"` | `"drop"` renders the dropzone/preview inline. `"button"` renders a compact trigger button that opens the same UI inside an `ITDialog` modal. |
|
|
25
|
-
| `buttonLabel` | `string` | `"Subir archivo"` | Label for the trigger button when `view="button"` and no file is selected yet. |
|
|
26
|
-
| `modalTitle` | `string` | `buttonLabel` | Title of the modal opened when `view="button"`. |
|
|
27
|
-
|
|
28
|
-
### Enums
|
|
29
|
-
|
|
30
|
-
| Enum | Values |
|
|
31
|
-
|------|--------|
|
|
32
|
-
| `UploadStatus` | `PENDING` (`"pendiente"`), `UPLOADING` (`"subiendo"`), `UPLOADED` (`"subido"`), `ERROR` (`"error"`) |
|
|
33
|
-
| `FileTypeEnum` | `PDF`, `XLS`, `XLSX`, `CSV`, `PNG`, `JPG`, `JPEG` |
|
|
34
|
-
|
|
35
|
-
## Usage
|
|
36
|
-
|
|
37
|
-
```tsx
|
|
38
|
-
import { ITDropfile, UploadStatus, FileTypeEnum } from '@axzydev/axzy_ui_system';
|
|
39
|
-
|
|
40
|
-
<ITDropfile
|
|
41
|
-
onFileSelect={(file) => setSelectedFile(file)}
|
|
42
|
-
onSubmit={(file) => uploadFile(file)}
|
|
43
|
-
onCancel={() => clearFile()}
|
|
44
|
-
acceptedFileTypes={[FileTypeEnum.PNG, FileTypeEnum.JPG, FileTypeEnum.PDF]}
|
|
45
|
-
uploadStatus={UploadStatus.PENDING}
|
|
46
|
-
showStatusBadge
|
|
47
|
-
/>
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### `view="button"`
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
<ITDropfile
|
|
54
|
-
view="button"
|
|
55
|
-
buttonLabel="Subir archivos"
|
|
56
|
-
onFileSelect={(file) => setSelectedFile(file)}
|
|
57
|
-
/>
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Use this when you'd otherwise write your own button + modal wrapper around `ITDropfile` — it's built in. The button shows the picked file's name (and status badge, if `showStatusBadge`) once one is selected, and reopens the same dropzone/preview to change it. ~900ms after a successful confirm the modal closes **and the selection resets**, so the button goes back to `buttonLabel`, ready to upload another file — this mode is built for repeated uploads (e.g. an attachments list), replacing the old pattern of remounting `ITDropfile` with a changing `key` after each upload.
|
|
61
|
-
|
|
62
|
-
## Notes
|
|
63
|
-
|
|
64
|
-
- Displays image preview for image file types; shows a file icon for non-image types.
|
|
65
|
-
- The `uploadStatus` and `showStatusBadge` props enable external lifecycle control and visual feedback.
|
|
66
|
-
- `initialPreviewUrl` is useful for edit forms where an existing file is already associated.
|
|
67
|
-
- Only one file at a time is supported — selecting a new file replaces the current one.
|
|
68
|
-
- The confirm/cancel flow gives users a chance to review their selection before submission.
|
|
69
|
-
|
|
70
|
-
## Stories
|
|
71
|
-
|
|
72
|
-
<Primary />
|
|
73
|
-
<Controls />
|
|
74
|
-
<Stories />
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import type { Meta } from '@storybook/react';
|
|
2
|
-
import ITDropfile, { UploadStatus } from '@/components/organisms/dropfile/dropfile';
|
|
3
|
-
|
|
4
|
-
const meta = {
|
|
5
|
-
title: 'Components/Actions/ITDropfile',
|
|
6
|
-
component: ITDropfile,
|
|
7
|
-
parameters: {
|
|
8
|
-
layout: 'centered',
|
|
9
|
-
},
|
|
10
|
-
argTypes: {
|
|
11
|
-
onFileSelect: { action: 'file selected' },
|
|
12
|
-
onCancel: { action: 'cancelled' },
|
|
13
|
-
onSubmit: { action: 'submitted' },
|
|
14
|
-
showStatusBadge: { control: 'boolean' },
|
|
15
|
-
uploadStatus: {
|
|
16
|
-
control: 'select',
|
|
17
|
-
options: Object.values(UploadStatus),
|
|
18
|
-
},
|
|
19
|
-
view: {
|
|
20
|
-
control: 'radio',
|
|
21
|
-
options: ['drop', 'button'],
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
} satisfies Meta<typeof ITDropfile>;
|
|
25
|
-
|
|
26
|
-
export default meta;
|
|
27
|
-
|
|
28
|
-
// Wrapper for stateful file handling in story
|
|
29
|
-
const DropfileWrapper = (args: any) => {
|
|
30
|
-
return <ITDropfile {...args} className="w-[500px]" />;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const Default: any = {
|
|
34
|
-
render: (args) => <DropfileWrapper {...args} />,
|
|
35
|
-
args: {
|
|
36
|
-
showStatusBadge: true,
|
|
37
|
-
containerClassName: 'w-[400px]',
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const WithImage: any = {
|
|
42
|
-
render: (args) => <DropfileWrapper {...args} />,
|
|
43
|
-
args: {
|
|
44
|
-
showStatusBadge: true,
|
|
45
|
-
initialPreviewUrl: 'https://images.unsplash.com/photo-1575936123452-b67c3203c357?ixlib=rb-4.0.3&auto=format&fit=crop&w=1000&q=80',
|
|
46
|
-
uploadStatus: UploadStatus.UPLOADED,
|
|
47
|
-
containerClassName: 'w-[400px]',
|
|
48
|
-
},
|
|
49
|
-
parameters: {
|
|
50
|
-
docs: {
|
|
51
|
-
description: {
|
|
52
|
-
story: 'Simulates a pre-loaded image (e.g., editing an existing entry).'
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export const Uploading: any = {
|
|
59
|
-
render: (args) => <DropfileWrapper {...args} />,
|
|
60
|
-
args: {
|
|
61
|
-
showStatusBadge: true,
|
|
62
|
-
initialPreviewUrl: 'https://images.unsplash.com/photo-1575936123452-b67c3203c357?ixlib=rb-4.0.3&auto=format&fit=crop&w=1000&q=80',
|
|
63
|
-
uploadStatus: UploadStatus.UPLOADING,
|
|
64
|
-
containerClassName: 'w-[400px]',
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const ButtonView: any = {
|
|
69
|
-
render: (args) => <DropfileWrapper {...args} />,
|
|
70
|
-
args: {
|
|
71
|
-
view: 'button',
|
|
72
|
-
buttonLabel: 'Subir archivos',
|
|
73
|
-
showStatusBadge: true,
|
|
74
|
-
},
|
|
75
|
-
parameters: {
|
|
76
|
-
docs: {
|
|
77
|
-
description: {
|
|
78
|
-
story:
|
|
79
|
-
'Compact trigger button that opens the dropzone/preview inside a modal (`ITDialog`) — use this instead of wrapping `ITDropfile` in your own "open a modal" button.',
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export const ErrorState: any = {
|
|
86
|
-
render: (args) => <DropfileWrapper {...args} />,
|
|
87
|
-
args: {
|
|
88
|
-
showStatusBadge: true,
|
|
89
|
-
initialPreviewUrl: 'https://images.unsplash.com/photo-1575936123452-b67c3203c357?ixlib=rb-4.0.3&auto=format&fit=crop&w=1000&q=80',
|
|
90
|
-
uploadStatus: UploadStatus.ERROR,
|
|
91
|
-
containerClassName: 'w-[400px]',
|
|
92
|
-
},
|
|
93
|
-
};
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './formBuilder.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITFormBuilder
|
|
7
|
-
|
|
8
|
-
Dynamic form generator that renders fields from a JSON-like array. Integrates with
|
|
9
|
-
Formik + Yup, supports both a backward-compatible V1 (`fields`) and the powerful
|
|
10
|
-
Enterprise V2 (`config`) API, and exposes a `useFormBuilder()` hook for building
|
|
11
|
-
custom submit buttons, progress meters, and dirty-state indicators.
|
|
12
|
-
|
|
13
|
-
## When to use
|
|
14
|
-
|
|
15
|
-
- You want to drive a form from a declarative config (server-driven forms, CMS schemas).
|
|
16
|
-
- You need conditional fields (`renderWhen`), derived values (`onChangeAction`),
|
|
17
|
-
dynamic props (`dynamicProps`), or cascading selects.
|
|
18
|
-
- You need to render a custom React component as a field (`type: "custom"`).
|
|
19
|
-
|
|
20
|
-
## Props
|
|
21
|
-
|
|
22
|
-
| Prop | Type | Default | Required | Description |
|
|
23
|
-
|------|------|---------|----------|-------------|
|
|
24
|
-
| `fields` | `FieldConfig[]` | — | No | Legacy V1 field definitions. Kept for backward compatibility. |
|
|
25
|
-
| `config` | `FieldConfigV2[]` | — | No | V2 field configuration. Recommended. Shadows `fields` when both supplied. |
|
|
26
|
-
| `columns` | `number` | `12` | No | Grid column count (1–12). |
|
|
27
|
-
| `values` | `Record<string, unknown>` | — | Yes | Current form values keyed by field `name`. |
|
|
28
|
-
| `handleChange` | `(event) => void` | — | Yes | Change handler — pass Formik's `handleChange` directly. |
|
|
29
|
-
| `handleBlur` | `(event) => void` | — | Yes | Blur handler — pass Formik's `handleBlur` directly. |
|
|
30
|
-
| `touched` | `Record<string, boolean>` | — | Yes | Touch state keyed by field `name`. |
|
|
31
|
-
| `errors` | `Record<string, string>` | — | Yes | Errors keyed by field `name`. |
|
|
32
|
-
| `setFieldValue` | `(field, value, shouldValidate?) => Promise` | no-op | No | Required for V2 `onChangeAction` and `dynamicProps` side effects. |
|
|
33
|
-
| `setFieldTouched` | `(field, touched?, shouldValidate?) => Promise` | no-op | No | Programmatic touch. |
|
|
34
|
-
| `setFieldError` | `(field, message?) => void` | no-op | No | Programmatic field-level error. |
|
|
35
|
-
| `isSubmitting` | `boolean` | `false` | No | Surface submit state to the context. |
|
|
36
|
-
|
|
37
|
-
When both `config` and `fields` are supplied, `config` wins. When neither is supplied the
|
|
38
|
-
component renders an empty grid.
|
|
39
|
-
|
|
40
|
-
## FieldConfigV2 reference
|
|
41
|
-
|
|
42
|
-
| Field | Type | Description |
|
|
43
|
-
|-------|------|-------------|
|
|
44
|
-
| `type` | `"text" \| "number" \| "password" \| "email" \| "select" \| "date" \| "time" \| "section" \| "custom" \| "array"` | Field kind. |
|
|
45
|
-
| `name` | `string` | Matches the key in `values` / `errors` / `touched`. |
|
|
46
|
-
| `label` | `string` | Text rendered above the field (or as the section heading). |
|
|
47
|
-
| `column` | `number \| { sm?, md?, lg?, xl? }` | Grid span. Responsive object or single number. |
|
|
48
|
-
| `dependsOn` | `string[]` | Sibling field names watched by `renderWhen`/`dynamicProps`. |
|
|
49
|
-
| `renderWhen` | `(values) => boolean` | Hide this field when returns `false`. |
|
|
50
|
-
| `dynamicProps` | `(values) => Partial<FieldConfigV2>` | Compute per-render overrides (e.g. toggle `disabled`). |
|
|
51
|
-
| `validation` | `Yup.AnySchema` | Per-field Yup schema. |
|
|
52
|
-
| `asyncValidation` | `(value, values) => Promise<string \| null>` | Async validator returning an error message or `null`. |
|
|
53
|
-
| `onChangeAction` | `(value, context) => void \| Promise<void>` | Side-effect fired on change. Use to compute derived fields. |
|
|
54
|
-
| `options` | `Array \| () => Promise<Array>` | Sync or async options for `select`. Async → renders `ITSearchSelect`. |
|
|
55
|
-
| `component` | `React.ComponentType` | Renderer for `type: "custom"`. |
|
|
56
|
-
| `fields` | `FieldConfigV2[]` | Nested fields for `type: "section"` (or `array` placeholder). |
|
|
57
|
-
| `placeholder` | `string` | Placeholder text. |
|
|
58
|
-
| `required` | `boolean \| (values) => boolean` | Required flag. |
|
|
59
|
-
| `disabled` | `boolean \| (values) => boolean` | Disabled flag. |
|
|
60
|
-
| `readOnly` | `boolean` | Read-only flag. |
|
|
61
|
-
| `defaultValue` | `any` | Initial value. |
|
|
62
|
-
| `valueField` / `labelField` | `string` | Keys read off each option object. |
|
|
63
|
-
| `leftIcon` / `rightIcon` | `React.ReactNode` | Icon adornments. |
|
|
64
|
-
| `className` | `string` | Extra classes for the field's container. |
|
|
65
|
-
| `maxLength` / `minLength` | `number` | Length bounds for text/textarea. |
|
|
66
|
-
| `rows` | `number` | Rows for textarea-style inputs. |
|
|
67
|
-
| `formatNumber` | `boolean` | Apply thousand-separator formatting as the user types. |
|
|
68
|
-
| `currencyFormat` | `boolean` | Render a `$`-style currency treatment on numeric input. |
|
|
69
|
-
| `showHintLength` | `boolean` | Show a live character counter. |
|
|
70
|
-
|
|
71
|
-
## FieldConfig (V1) reference (legacy)
|
|
72
|
-
|
|
73
|
-
| Field | Type | Description |
|
|
74
|
-
|-------|------|-------------|
|
|
75
|
-
| `name` | `string` | Key in `values`/`errors`/`touched`. |
|
|
76
|
-
| `label` | `string` | Field label. |
|
|
77
|
-
| `type` | `"text" \| "number" \| "password" \| "select" \| "date"` | Input kind. |
|
|
78
|
-
| `placeholder` | `string` | Placeholder text. |
|
|
79
|
-
| `required` | `boolean` | Required flag. |
|
|
80
|
-
| `disabled` | `boolean` | Disabled flag. |
|
|
81
|
-
| `column` | `number` | Grid span. |
|
|
82
|
-
| `options` | `{ value, label }[]` | Options for `select`. |
|
|
83
|
-
| `leftIcon` / `rightIcon` | `React.ReactNode` | Icon adornments. |
|
|
84
|
-
| `valueField` / `labelField` | `string` | Keys read off each option object. |
|
|
85
|
-
| `maxLength` / `minLength` | `number` | Length bounds. |
|
|
86
|
-
| `rows` | `number` | Rows for multi-line inputs. |
|
|
87
|
-
| `formatNumber` | `boolean` | Thousand-separator formatting. |
|
|
88
|
-
| `currencyFormat` | `boolean` | Currency-style numeric input. |
|
|
89
|
-
| `showHintLength` | `boolean` | Live character counter. |
|
|
90
|
-
| `validation` | `Yup.AnySchema` | Per-field Yup schema. |
|
|
91
|
-
| `onChangeAction` | `(value, setFieldValue) => void` | Side-effect fired on change. |
|
|
92
|
-
|
|
93
|
-
## Usage
|
|
94
|
-
|
|
95
|
-
### 1. Minimal Formik + Yup form (V2)
|
|
96
|
-
|
|
97
|
-
```tsx
|
|
98
|
-
import { Formik } from "formik";
|
|
99
|
-
import * as Yup from "yup";
|
|
100
|
-
import { ITFormBuilder } from "@axzydev/axzy_ui_system";
|
|
101
|
-
import type { FieldConfigV2 } from "@axzydev/axzy_ui_system";
|
|
102
|
-
|
|
103
|
-
const schema = Yup.object({
|
|
104
|
-
email: Yup.string().email().required(),
|
|
105
|
-
password: Yup.string().min(8).required(),
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const config: FieldConfigV2[] = [
|
|
109
|
-
{ name: "email", label: "Email", type: "email", required: true, column: 6 },
|
|
110
|
-
{ name: "password", label: "Password", type: "password", required: true, column: 6 },
|
|
111
|
-
];
|
|
112
|
-
|
|
113
|
-
<Formik
|
|
114
|
-
initialValues={{ email: "", password: "" }}
|
|
115
|
-
validationSchema={schema}
|
|
116
|
-
onSubmit={(values) => console.log(values)}
|
|
117
|
-
>
|
|
118
|
-
{(p) => (
|
|
119
|
-
<form onSubmit={p.handleSubmit}>
|
|
120
|
-
<ITFormBuilder
|
|
121
|
-
config={config}
|
|
122
|
-
values={p.values}
|
|
123
|
-
handleChange={p.handleChange}
|
|
124
|
-
handleBlur={p.handleBlur}
|
|
125
|
-
touched={p.touched}
|
|
126
|
-
errors={p.errors}
|
|
127
|
-
setFieldValue={p.setFieldValue}
|
|
128
|
-
/>
|
|
129
|
-
<button type="submit">Submit</button>
|
|
130
|
-
</form>
|
|
131
|
-
)}
|
|
132
|
-
</Formik>
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### 2. Conditional + derived fields
|
|
136
|
-
|
|
137
|
-
```tsx
|
|
138
|
-
const config: FieldConfigV2[] = [
|
|
139
|
-
{
|
|
140
|
-
name: "country",
|
|
141
|
-
label: "País",
|
|
142
|
-
type: "select",
|
|
143
|
-
required: true,
|
|
144
|
-
options: [{ value: "MX", label: "México" }, { value: "US", label: "USA" }],
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "rfc",
|
|
148
|
-
label: "RFC",
|
|
149
|
-
type: "text",
|
|
150
|
-
required: true,
|
|
151
|
-
dependsOn: ["country"],
|
|
152
|
-
renderWhen: (v) => v.country === "MX",
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
name: "subtotal",
|
|
156
|
-
label: "Subtotal",
|
|
157
|
-
type: "number",
|
|
158
|
-
currencyFormat: true,
|
|
159
|
-
onChangeAction: (val, ctx) => {
|
|
160
|
-
const n = parseFloat(String(val).replace(/,/g, "")) || 0;
|
|
161
|
-
ctx.setFieldValue("total", (n * 1.16).toFixed(2));
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
{ name: "total", label: "Total", type: "number", disabled: true, currencyFormat: true },
|
|
165
|
-
];
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### 3. Async / cascading options
|
|
169
|
-
|
|
170
|
-
```tsx
|
|
171
|
-
{
|
|
172
|
-
name: "city",
|
|
173
|
-
label: "Ciudad",
|
|
174
|
-
type: "select",
|
|
175
|
-
options: async () => {
|
|
176
|
-
const res = await fetch(`/api/cities?country=${values.country}`);
|
|
177
|
-
return res.json();
|
|
178
|
-
},
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
Async option lists use `ITSearchSelect` underneath and render a spinner fallback
|
|
183
|
-
while loading (`data-testid="field-loading-{name}"`).
|
|
184
|
-
|
|
185
|
-
### 4. Custom component
|
|
186
|
-
|
|
187
|
-
```tsx
|
|
188
|
-
const ConfirmToggle = ({ value, onChange, label }) => (
|
|
189
|
-
<label>
|
|
190
|
-
<input type="checkbox" checked={!!value} onChange={(e) => onChange(e.target.checked)} />
|
|
191
|
-
{label}
|
|
192
|
-
</label>
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
{
|
|
196
|
-
name: "confirm",
|
|
197
|
-
label: "Acepto términos",
|
|
198
|
-
type: "custom",
|
|
199
|
-
component: ConfirmToggle,
|
|
200
|
-
defaultValue: false,
|
|
201
|
-
}
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
### 5. Section grouping
|
|
205
|
-
|
|
206
|
-
```tsx
|
|
207
|
-
{
|
|
208
|
-
name: "identity",
|
|
209
|
-
label: "Personal Information",
|
|
210
|
-
type: "section",
|
|
211
|
-
fields: [
|
|
212
|
-
{ name: "firstName", label: "First Name", type: "text" },
|
|
213
|
-
{ name: "lastName", label: "Last Name", type: "text" },
|
|
214
|
-
],
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### 6. Custom submit button via `useFormBuilder`
|
|
219
|
-
|
|
220
|
-
```tsx
|
|
221
|
-
import { useFormBuilder } from "@axzydev/axzy_ui_system";
|
|
222
|
-
|
|
223
|
-
const SubmitButton = () => {
|
|
224
|
-
const { progress, isSubmitting } = useFormBuilder();
|
|
225
|
-
return (
|
|
226
|
-
<button type="submit" disabled={progress < 100 || isSubmitting}>
|
|
227
|
-
{isSubmitting ? "Saving…" : `Submit (${progress}%)`}
|
|
228
|
-
</button>
|
|
229
|
-
);
|
|
230
|
-
};
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
`useFormBuilder` must be rendered inside the `<ITFormBuilder>` subtree (so the
|
|
234
|
-
V2 provider must be active). It throws a clear error if used outside.
|
|
235
|
-
|
|
236
|
-
## Notes
|
|
237
|
-
|
|
238
|
-
- The component is fully controlled — it does not own form state. Pass values
|
|
239
|
-
and handlers from Formik (or any state holder of your choice).
|
|
240
|
-
- V1 and V2 can coexist on a single page; mixing both on the same `<ITFormBuilder>`
|
|
241
|
-
is not supported — `config` wins.
|
|
242
|
-
- The V2 registry of registered fields is exposed via `useFormBuilder` and via
|
|
243
|
-
`useITFormBuilderContext().getAllFieldConfigs()`.
|
|
244
|
-
- `validation`/`asyncValidation` are NOT applied automatically — wire them to
|
|
245
|
-
Yup at the Formik root, or run them manually inside `onChangeAction`.
|
|
246
|
-
|
|
247
|
-
## Stories
|
|
248
|
-
|
|
249
|
-
<Primary />
|
|
250
|
-
<Controls />
|
|
251
|
-
<Stories />
|