@axzydev/axzy_ui_system 1.4.8 → 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 +1826 -1351
- 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 +115 -14
- package/dist/index.d.ts +115 -14
- package/dist/index.js +1481 -1010
- 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.tsx +30 -28
- 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.tsx +31 -25
- 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 +7 -1
- 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 +103 -87
- 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/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 -140
- 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 -132
- 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,52 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import ITFormHeader from '@/components/molecules/form-header/form-header';
|
|
3
|
-
|
|
4
|
-
const meta = {
|
|
5
|
-
title: 'Components/Feedback/ITFormHeader',
|
|
6
|
-
component: ITFormHeader,
|
|
7
|
-
parameters: { layout: 'centered' },
|
|
8
|
-
argTypes: {
|
|
9
|
-
title: { control: 'text', description: 'The title displayed in the header' },
|
|
10
|
-
onClose: { control: false, description: 'Optional close button handler' },
|
|
11
|
-
className: { control: 'text', description: 'Additional CSS classes' },
|
|
12
|
-
},
|
|
13
|
-
} satisfies Meta<typeof ITFormHeader>;
|
|
14
|
-
|
|
15
|
-
export default meta;
|
|
16
|
-
type Story = StoryObj<typeof meta>;
|
|
17
|
-
|
|
18
|
-
export const Default: Story = {
|
|
19
|
-
args: { title: 'Form Header' },
|
|
20
|
-
render: (args) => (
|
|
21
|
-
<div className="w-80">
|
|
22
|
-
<ITFormHeader {...args} />
|
|
23
|
-
</div>
|
|
24
|
-
),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const WithClose: Story = {
|
|
28
|
-
args: { title: 'Editable Form' },
|
|
29
|
-
render: (args) => (
|
|
30
|
-
<div className="w-80">
|
|
31
|
-
<ITFormHeader {...args} onClose={() => alert('Close clicked')} />
|
|
32
|
-
</div>
|
|
33
|
-
),
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const LongTitle: Story = {
|
|
37
|
-
args: { title: 'Confirmación de Auditoría de Expediente Clínico' },
|
|
38
|
-
render: (args) => (
|
|
39
|
-
<div className="w-80">
|
|
40
|
-
<ITFormHeader {...args} />
|
|
41
|
-
</div>
|
|
42
|
-
),
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const ShortTitle: Story = {
|
|
46
|
-
args: { title: 'Edit' },
|
|
47
|
-
render: (args) => (
|
|
48
|
-
<div className="w-80">
|
|
49
|
-
<ITFormHeader {...args} />
|
|
50
|
-
</div>
|
|
51
|
-
),
|
|
52
|
-
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './masked-input.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITMaskedInput
|
|
7
|
-
|
|
8
|
-
Input con máscara de formato: defines un patrón y el usuario solo escribe los caracteres útiles; los separadores se insertan solos y los huecos se pintan con un carácter de relleno.
|
|
9
|
-
|
|
10
|
-
## Props
|
|
11
|
-
|
|
12
|
-
| Prop | Type | Default | Description |
|
|
13
|
-
|------|------|---------|-------------|
|
|
14
|
-
| `name` | `string` | required | Nombre del campo para formularios. |
|
|
15
|
-
| `mask` | `string` | required | Patrón: `9`=dígito, `A`=letra (mayúscula), `a`=letra, `x`=alfanumérico, `*`=cualquiera. Cualquier otro carácter es un separador literal auto-insertado. |
|
|
16
|
-
| `value` | `string` | — | Valor limpio (raw): solo caracteres útiles, sin separadores ni relleno. |
|
|
17
|
-
| `onChange` | `(e) => void` | required | `e.target.value` es el valor raw. |
|
|
18
|
-
| `onBlur` | `(e) => void` | — | Blur del input. |
|
|
19
|
-
| `onComplete` | `(value) => void` | — | Dispara cuando la máscara queda llena. |
|
|
20
|
-
| `pattern` | `RegExp` | — | Regex validada con full-match contra el raw en blur; si no cumple muestra error. |
|
|
21
|
-
| `placeholderChar` | `string` | `"_"` | Carácter pintado en slots vacíos. |
|
|
22
|
-
| `variant` | `ColorsTypes` | `"primary"` | Color de acento del tema. |
|
|
23
|
-
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Tamaño del input. |
|
|
24
|
-
| `label` | `string` | — | Etiqueta sobre el input. |
|
|
25
|
-
| `disabled` | `boolean` | `false` | Desactiva el input. |
|
|
26
|
-
| `required` | `boolean` | `false` | Marca el campo como requerido. |
|
|
27
|
-
| `touched` | `boolean` | `false` | Indica si el campo fue tocado. |
|
|
28
|
-
| `error` | `string \| boolean` | — | Estado de error. |
|
|
29
|
-
| `className` | `string` | — | Clases del wrapper externo. |
|
|
30
|
-
| `containerClassName` | `string` | — | Clases del contenedor del input. |
|
|
31
|
-
| `iconLeft` / `iconRight` | `ReactNode` | — | Iconos laterales. |
|
|
32
|
-
| `autoFocus` | `boolean` | `false` | Enfoca al montar. |
|
|
33
|
-
|
|
34
|
-
## Tokens del mask
|
|
35
|
-
|
|
36
|
-
| Token | Acepta |
|
|
37
|
-
|-------|--------|
|
|
38
|
-
| `9` | un dígito |
|
|
39
|
-
| `A` | una letra (se guarda en mayúsculas) |
|
|
40
|
-
| `a` | una letra (tal cual) |
|
|
41
|
-
| `x` | un carácter alfanumérico |
|
|
42
|
-
| `*` | cualquier carácter |
|
|
43
|
-
| cualquier otro | literal insertado solo (p.ej. `-`, `/`, `(`, `)`, espacio) |
|
|
44
|
-
|
|
45
|
-
## Usage
|
|
46
|
-
|
|
47
|
-
```tsx
|
|
48
|
-
import { ITMaskedInput } from '@axzydev/axzy_ui_system';
|
|
49
|
-
|
|
50
|
-
// Código de activación
|
|
51
|
-
<ITMaskedInput
|
|
52
|
-
name="code"
|
|
53
|
-
mask="xxxx-xxxx-xxxx"
|
|
54
|
-
label="Código"
|
|
55
|
-
onChange={(e) => setCode(e.target.value)}
|
|
56
|
-
/>
|
|
57
|
-
|
|
58
|
-
// Teléfono con validación regex sobre el valor limpio
|
|
59
|
-
<ITMaskedInput
|
|
60
|
-
name="phone"
|
|
61
|
-
mask="(999) 999-9999"
|
|
62
|
-
pattern={/^\d{10}$/}
|
|
63
|
-
onChange={(e) => setPhone(e.target.value)}
|
|
64
|
-
/>
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Notes
|
|
68
|
-
|
|
69
|
-
- ¿El valor? **Solo caracteres útiles**: escribir `ABC1-2345-6789` devuelve `ABC123456789` en `onChange`.
|
|
70
|
-
- El cursor salta a huecos vacíos con selección automática; borrar un separador lo vuelve a insertar.
|
|
71
|
-
- `pattern` valida contra el raw completo (full-match); el mensaje de error genérico es "Formato inválido" salvo que pases `error` como string.
|
|
72
|
-
- `onComplete` es ideal para tarjetas, CVV o códigos de un solo uso.
|
|
73
|
-
|
|
74
|
-
## Stories
|
|
75
|
-
|
|
76
|
-
<Primary />
|
|
77
|
-
<Controls />
|
|
78
|
-
<Stories />
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import type { Meta } from '@storybook/react';
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import ITMaskedInput from './masked-input';
|
|
4
|
-
|
|
5
|
-
const meta = {
|
|
6
|
-
title: 'Components/Form Elements/ITMaskedInput',
|
|
7
|
-
component: ITMaskedInput,
|
|
8
|
-
parameters: { layout: 'padded' },
|
|
9
|
-
argTypes: {
|
|
10
|
-
mask: { control: 'text' },
|
|
11
|
-
placeholderChar: { control: 'text' },
|
|
12
|
-
onChange: { action: 'changed' },
|
|
13
|
-
onComplete: { action: 'completed' },
|
|
14
|
-
disabled: { control: 'boolean' },
|
|
15
|
-
error: { control: 'text' },
|
|
16
|
-
variant: {
|
|
17
|
-
control: 'select',
|
|
18
|
-
options: ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'purple', 'gray'],
|
|
19
|
-
},
|
|
20
|
-
size: { control: 'select', options: ['sm', 'md', 'lg'] },
|
|
21
|
-
},
|
|
22
|
-
} satisfies Meta<typeof ITMaskedInput>;
|
|
23
|
-
|
|
24
|
-
export default meta;
|
|
25
|
-
|
|
26
|
-
function CodeMaskedWrapper(args: any) {
|
|
27
|
-
const [value, setValue] = useState<string>('');
|
|
28
|
-
return (
|
|
29
|
-
<div className="w-full max-w-xs">
|
|
30
|
-
<ITMaskedInput
|
|
31
|
-
{...args}
|
|
32
|
-
value={value}
|
|
33
|
-
onChange={(e) => {
|
|
34
|
-
setValue(e.target.value);
|
|
35
|
-
args.onChange(e);
|
|
36
|
-
}}
|
|
37
|
-
/>
|
|
38
|
-
<p className="mt-2 text-xs font-mono text-slate-500">
|
|
39
|
-
raw: {value || '(vacío)'}
|
|
40
|
-
</p>
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export const Alphanumeric: any = {
|
|
46
|
-
render: CodeMaskedWrapper,
|
|
47
|
-
args: {
|
|
48
|
-
name: 'code',
|
|
49
|
-
label: 'Código único',
|
|
50
|
-
mask: 'xxxx-xxxx-xxxx',
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const Phone: any = {
|
|
55
|
-
render: CodeMaskedWrapper,
|
|
56
|
-
args: {
|
|
57
|
-
name: 'phone',
|
|
58
|
-
label: 'Teléfono',
|
|
59
|
-
mask: '(999) 999-9999',
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export const CreditCard: any = {
|
|
64
|
-
render: CodeMaskedWrapper,
|
|
65
|
-
args: {
|
|
66
|
-
name: 'card',
|
|
67
|
-
label: 'Número de tarjeta',
|
|
68
|
-
mask: '9999-9999-9999-9999',
|
|
69
|
-
onComplete: undefined,
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const PhoneValidatedWrapper = (args: any) => {
|
|
74
|
-
const [value, setValue] = useState<string>('5512345678');
|
|
75
|
-
const [complete, setComplete] = useState<string | null>(null);
|
|
76
|
-
return (
|
|
77
|
-
<div className="w-full max-w-xs">
|
|
78
|
-
<ITMaskedInput
|
|
79
|
-
{...args}
|
|
80
|
-
value={value}
|
|
81
|
-
onChange={(e) => {
|
|
82
|
-
setValue(e.target.value);
|
|
83
|
-
args.onChange(e);
|
|
84
|
-
setComplete(null);
|
|
85
|
-
}}
|
|
86
|
-
onComplete={(v) => setComplete(v)}
|
|
87
|
-
/>
|
|
88
|
-
{complete && (
|
|
89
|
-
<p className="mt-2 text-xs font-mono text-emerald-600">
|
|
90
|
-
¡Completo! raw: {complete}
|
|
91
|
-
</p>
|
|
92
|
-
)}
|
|
93
|
-
</div>
|
|
94
|
-
);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export const WithPattern: any = {
|
|
98
|
-
render: PhoneValidatedWrapper,
|
|
99
|
-
args: {
|
|
100
|
-
name: 'validated_phone',
|
|
101
|
-
label: 'Teléfono válido (regex)',
|
|
102
|
-
mask: '999-999-9999',
|
|
103
|
-
pattern: /^\d{9}$/,
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
export const Sizes: any = {
|
|
108
|
-
render: () => (
|
|
109
|
-
<div className="flex flex-col gap-4 w-full max-w-xs">
|
|
110
|
-
<ITMaskedInput name="sz_sm" label="Small" mask="xxxx-xxxx" size="sm" onChange={() => {}} />
|
|
111
|
-
<ITMaskedInput name="sz_md" label="Medium" mask="xxxx-xxxx" size="md" onChange={() => {}} />
|
|
112
|
-
<ITMaskedInput name="sz_lg" label="Large" mask="xxxx-xxxx" size="lg" onChange={() => {}} />
|
|
113
|
-
</div>
|
|
114
|
-
),
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
export const Disabled: any = {
|
|
118
|
-
args: {
|
|
119
|
-
name: 'disabled_code',
|
|
120
|
-
label: 'Deshabilitado',
|
|
121
|
-
mask: 'xxxx-xxxx',
|
|
122
|
-
value: 'abcd',
|
|
123
|
-
disabled: true,
|
|
124
|
-
onChange: () => {},
|
|
125
|
-
},
|
|
126
|
-
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './multi-select.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITMultiSelect
|
|
7
|
-
|
|
8
|
-
Multi-value select with searchable dropdown, removable chips, and keyboard navigation.
|
|
9
|
-
|
|
10
|
-
## Props
|
|
11
|
-
|
|
12
|
-
| Prop | Type | Default | Description |
|
|
13
|
-
|------|------|---------|-------------|
|
|
14
|
-
| `options` | `ITMultiSelectOption[]` | — | Available options `{ label, value, ...custom }`. |
|
|
15
|
-
| `value` | `(string \| number)[]` | — | Selected values (controlled). |
|
|
16
|
-
| `onChange` | `(values, options) => void` | — | Fired with the next selected values. |
|
|
17
|
-
| `label` | `string` | — | Label above the control. |
|
|
18
|
-
| `placeholder` | `string` | `"Selecciona opciones"` | Placeholder when empty. |
|
|
19
|
-
| `valueField` | `string` | `"value"` | Field used as the option value. |
|
|
20
|
-
| `labelField` | `string` | `"label"` | Field used as the option label. |
|
|
21
|
-
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Control size. |
|
|
22
|
-
| `maxVisibleChips` | `number` | `3` | Chips shown before collapsing into `+N`. |
|
|
23
|
-
| `clearable` | `boolean` | `true` | Shows a clear-all (X) button. |
|
|
24
|
-
| `searchable` | `boolean` | `true` | Enables the search input. |
|
|
25
|
-
| `onSearch` | `(query) => void` | — | Server-side search callback. |
|
|
26
|
-
| `isLoading` | `boolean` | `false` | Loading state for remote options. |
|
|
27
|
-
| `noResultsMessage` | `string` | `"No se encontraron resultados"` | Empty-results message. |
|
|
28
|
-
| `renderOption` | `(option, { isSelected, searchTerm }) => ReactNode` | — | Custom option template. |
|
|
29
|
-
| `disabled` / `readOnly` / `required` / `touched` / `error` | — | — | Standard form states. |
|
|
30
|
-
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
import { ITMultiSelect } from '@axzydev/axzy_ui_system';
|
|
35
|
-
|
|
36
|
-
<ITMultiSelect
|
|
37
|
-
label="Skills"
|
|
38
|
-
options={skills}
|
|
39
|
-
value={selected}
|
|
40
|
-
onChange={(values) => setSelected(values)}
|
|
41
|
-
maxVisibleChips={3}
|
|
42
|
-
/>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Notes
|
|
46
|
-
|
|
47
|
-
- Keyboard: `ArrowUp`/`ArrowDown` navigate, `Enter` toggles, `Backspace` removes the last chip, `Esc` closes.
|
|
48
|
-
- `role="combobox"` + `role="listbox"` (`aria-multiselectable`) for accessibility.
|
|
49
|
-
- The dropdown is portaled, so it is not clipped inside cards or `overflow: hidden` ancestors.
|
|
50
|
-
|
|
51
|
-
## Stories
|
|
52
|
-
|
|
53
|
-
<Primary />
|
|
54
|
-
<Controls />
|
|
55
|
-
<Stories />
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import ITMultiSelect from "@/components/molecules/multi-select/multi-select";
|
|
4
|
-
import { ITMultiSelectOption } from "./multi-select.props";
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof ITMultiSelect> = {
|
|
7
|
-
title: "Components/Form Elements/ITMultiSelect",
|
|
8
|
-
component: ITMultiSelect,
|
|
9
|
-
parameters: { layout: "centered" },
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export default meta;
|
|
13
|
-
type Story = StoryObj<typeof ITMultiSelect>;
|
|
14
|
-
|
|
15
|
-
const options: ITMultiSelectOption[] = [
|
|
16
|
-
{ value: "mx", label: "México" },
|
|
17
|
-
{ value: "es", label: "España" },
|
|
18
|
-
{ value: "co", label: "Colombia" },
|
|
19
|
-
{ value: "ar", label: "Argentina" },
|
|
20
|
-
{ value: "pe", label: "Perú" },
|
|
21
|
-
{ value: "cl", label: "Chile" },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const Wrapper = (args: any) => {
|
|
25
|
-
const [value, setValue] = useState<(string | number)[]>(args.value ?? []);
|
|
26
|
-
return (
|
|
27
|
-
<div className="w-[400px]">
|
|
28
|
-
<ITMultiSelect {...args} value={value} onChange={(v) => setValue(v)} />
|
|
29
|
-
</div>
|
|
30
|
-
);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const Default: Story = {
|
|
34
|
-
render: (args) => <Wrapper {...args} />,
|
|
35
|
-
args: { name: "countries", label: "Países", options, value: [] },
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const WithPreselected: Story = {
|
|
39
|
-
render: (args) => <Wrapper {...args} />,
|
|
40
|
-
args: { name: "countries", label: "Países", options, value: ["mx", "es", "co", "ar"] },
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const WithError: Story = {
|
|
44
|
-
render: (args) => <Wrapper {...args} />,
|
|
45
|
-
args: {
|
|
46
|
-
name: "countries",
|
|
47
|
-
label: "Países",
|
|
48
|
-
options,
|
|
49
|
-
value: [],
|
|
50
|
-
required: true,
|
|
51
|
-
touched: true,
|
|
52
|
-
error: true,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export const Disabled: Story = {
|
|
57
|
-
render: (args) => <Wrapper {...args} />,
|
|
58
|
-
args: { name: "countries", label: "Países", options, value: ["mx"], disabled: true },
|
|
59
|
-
};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './pagination.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITPagination
|
|
7
|
-
|
|
8
|
-
Page navigation with current/total pages display, first/last buttons, sibling page count control, and an optional items-per-page selector with summary text.
|
|
9
|
-
|
|
10
|
-
## Props
|
|
11
|
-
|
|
12
|
-
| Prop | Type | Default | Description |
|
|
13
|
-
|------|------|---------|-------------|
|
|
14
|
-
| `currentPage` | `number` | — | Current active page (1-indexed). |
|
|
15
|
-
| `totalPages` | `number` | — | Total number of pages available. |
|
|
16
|
-
| `onPageChange` | `(page: number) => void` | — | Callback fired when a page is clicked or prev/next is activated. |
|
|
17
|
-
| `siblingCount` | `number` | `1` | Number of visible page siblings before and after the current page. |
|
|
18
|
-
| `color` | `"primary" \| "secondary" \| "success" \| "danger" \| "warning" \| "info" \| "purple"` | `"primary"` | Semantic color for active page and buttons. |
|
|
19
|
-
| `className` | `string` | — | Additional CSS classes for the container. |
|
|
20
|
-
| `itemsPerPageOptions` | `number[]` | — | Available options for the items-per-page selector dropdown. |
|
|
21
|
-
| `itemsPerPage` | `number` | — | Current items per page value. Required if `itemsPerPageOptions` is provided. |
|
|
22
|
-
| `onItemsPerPageChange` | `(value: number) => void` | — | Callback fired when the items per page value is changed. |
|
|
23
|
-
| `totalItems` | `number` | — | Total number of items across all pages. Used for the "1-10 of 50" summary text. |
|
|
24
|
-
|
|
25
|
-
## Usage
|
|
26
|
-
|
|
27
|
-
```tsx
|
|
28
|
-
import { ITPagination } from '@axzydev/axzy_ui_system';
|
|
29
|
-
|
|
30
|
-
<ITPagination
|
|
31
|
-
currentPage={1}
|
|
32
|
-
totalPages={5}
|
|
33
|
-
onPageChange={(page) => setCurrentPage(page)}
|
|
34
|
-
/>
|
|
35
|
-
|
|
36
|
-
<ITPagination
|
|
37
|
-
currentPage={1}
|
|
38
|
-
totalPages={50}
|
|
39
|
-
siblingCount={2}
|
|
40
|
-
color="primary"
|
|
41
|
-
onPageChange={(page) => setCurrentPage(page)}
|
|
42
|
-
itemsPerPageOptions={[10, 20, 30, 50]}
|
|
43
|
-
itemsPerPage={10}
|
|
44
|
-
onItemsPerPageChange={(val) => setItemsPerPage(val)}
|
|
45
|
-
totalItems={500}
|
|
46
|
-
/>
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Notes
|
|
50
|
-
|
|
51
|
-
- First and last page buttons are always visible for quick navigation.
|
|
52
|
-
- Ellipsis indicators appear when sibling gaps exceed the page range.
|
|
53
|
-
- The `siblingCount` prop controls how many page numbers appear around the current page.
|
|
54
|
-
- All seven semantic colors are supported for the active page highlight.
|
|
55
|
-
- When `itemsPerPageOptions` is provided, a dropdown and summary text render alongside pagination.
|
|
56
|
-
- Compatible with server-side pagination via the `currentPage` and `onPageChange` controlled pattern.
|
|
57
|
-
|
|
58
|
-
## Stories
|
|
59
|
-
|
|
60
|
-
<Primary />
|
|
61
|
-
<Controls />
|
|
62
|
-
<Stories />
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import ITPagination from "@/components/molecules/pagination/pagination";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
|
|
5
|
-
const meta: Meta<typeof ITPagination> = {
|
|
6
|
-
title: "Components/Data Display/ITPagination",
|
|
7
|
-
component: ITPagination,
|
|
8
|
-
parameters: {
|
|
9
|
-
layout: "centered",
|
|
10
|
-
},
|
|
11
|
-
argTypes: {
|
|
12
|
-
currentPage: { control: "number" },
|
|
13
|
-
totalPages: { control: "number" },
|
|
14
|
-
siblingCount: { control: "number" },
|
|
15
|
-
color: {
|
|
16
|
-
control: "select",
|
|
17
|
-
options: ["primary", "secondary", "success", "danger", "warning", "info", "purple"],
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default meta;
|
|
23
|
-
type Story = StoryObj<typeof ITPagination>;
|
|
24
|
-
|
|
25
|
-
const PaginationWrapper = (args: any) => {
|
|
26
|
-
const [currentPage, setCurrentPage] = useState(args.currentPage || 1);
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<ITPagination
|
|
30
|
-
{...args}
|
|
31
|
-
currentPage={currentPage}
|
|
32
|
-
onPageChange={(page) => setCurrentPage(page)}
|
|
33
|
-
/>
|
|
34
|
-
);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const Default: Story = {
|
|
38
|
-
render: (args) => <PaginationWrapper {...args} />,
|
|
39
|
-
args: {
|
|
40
|
-
currentPage: 1,
|
|
41
|
-
totalPages: 5,
|
|
42
|
-
color: "primary",
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const ManyPages: Story = {
|
|
47
|
-
render: (args) => <PaginationWrapper {...args} />,
|
|
48
|
-
args: {
|
|
49
|
-
currentPage: 1,
|
|
50
|
-
totalPages: 50,
|
|
51
|
-
siblingCount: 1,
|
|
52
|
-
color: "primary",
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export const MiddlePageOpened: Story = {
|
|
57
|
-
render: (args) => <PaginationWrapper {...args} />,
|
|
58
|
-
args: {
|
|
59
|
-
currentPage: 25,
|
|
60
|
-
totalPages: 50,
|
|
61
|
-
siblingCount: 1,
|
|
62
|
-
color: "primary",
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export const WithItemsPerPage: Story = {
|
|
67
|
-
render: (args) => {
|
|
68
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
69
|
-
const [itemsPerPage, setItemsPerPage] = useState(10);
|
|
70
|
-
const totalItems = 500;
|
|
71
|
-
const totalPages = Math.ceil(totalItems / itemsPerPage);
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<ITPagination
|
|
75
|
-
{...args}
|
|
76
|
-
currentPage={currentPage}
|
|
77
|
-
totalPages={totalPages}
|
|
78
|
-
onPageChange={(page) => setCurrentPage(page)}
|
|
79
|
-
itemsPerPageOptions={[10, 20, 30, 50]}
|
|
80
|
-
itemsPerPage={itemsPerPage}
|
|
81
|
-
onItemsPerPageChange={(val) => {
|
|
82
|
-
setItemsPerPage(val);
|
|
83
|
-
setCurrentPage(1);
|
|
84
|
-
}}
|
|
85
|
-
totalItems={totalItems}
|
|
86
|
-
/>
|
|
87
|
-
);
|
|
88
|
-
},
|
|
89
|
-
args: {
|
|
90
|
-
color: "primary",
|
|
91
|
-
className: "w-[600px]" // Make it wide enough to see the layout
|
|
92
|
-
},
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export const Colors: Story = {
|
|
96
|
-
render: (args) => (
|
|
97
|
-
<div className="flex flex-col gap-4">
|
|
98
|
-
{(['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'purple'] as const).map((color) => (
|
|
99
|
-
<div key={color} className="flex gap-4 items-center">
|
|
100
|
-
<span className="w-20 text-sm font-bold text-gray-500 capitalize">{color}</span>
|
|
101
|
-
<PaginationWrapper {...args} color={color} />
|
|
102
|
-
</div>
|
|
103
|
-
))}
|
|
104
|
-
</div>
|
|
105
|
-
),
|
|
106
|
-
args: {
|
|
107
|
-
currentPage: 1,
|
|
108
|
-
totalPages: 5,
|
|
109
|
-
},
|
|
110
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './search-select.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITSearchSelect
|
|
7
|
-
|
|
8
|
-
Searchable dropdown select with support for local client-side filtering and remote API search. Includes validation error display, label support, and customizable field mapping.
|
|
9
|
-
|
|
10
|
-
## Props
|
|
11
|
-
|
|
12
|
-
| Prop | Type | Default | Description |
|
|
13
|
-
|------|------|---------|-------------|
|
|
14
|
-
| `name` | `string` | — | Name attribute for form integrations. |
|
|
15
|
-
| `label` | `string` | — | Label displayed above the select input. |
|
|
16
|
-
| `placeholder` | `string` | — | Placeholder text shown when no value is selected. |
|
|
17
|
-
| `value` | `string \| number` | — | Currently selected value (controlled). |
|
|
18
|
-
| `options` | `ITSearchSelectOption[]` | — | Array of options for static or remote data. `{ label, value, ...custom }`. |
|
|
19
|
-
| `valueField` | `string` | `"value"` | Field used as the option value. |
|
|
20
|
-
| `labelField` | `string` | `"label"` | Field used as the option display label. |
|
|
21
|
-
| `onChange` | `(value: string \| number, option?: ITSearchSelectOption) => void` | — | Callback fired when selection changes. |
|
|
22
|
-
| `onBlur` | `(e: FocusEvent<any>) => void` | — | Callback fired when input loses focus. |
|
|
23
|
-
| `disabled` | `boolean` | `false` | Whether the component is disabled. |
|
|
24
|
-
| `className` | `string` | — | Additional CSS classes for the container. |
|
|
25
|
-
| `touched` | `boolean` | — | Whether the field has been touched (for form validation). |
|
|
26
|
-
| `required` | `boolean` | `false` | Whether the field is required. Shows a red asterisk. |
|
|
27
|
-
| `error` | `string \| boolean` | — | Error message or boolean indicating an error state. |
|
|
28
|
-
| `readOnly` | `boolean` | `false` | Whether the field is read-only. |
|
|
29
|
-
| `onSearch` | `(query: string) => void` | — | Callback for server-side search. Receives the search query string. |
|
|
30
|
-
| `isLoading` | `boolean` | `false` | Whether options are being loaded from an external API. |
|
|
31
|
-
| `noResultsMessage` | `string` | `"No se encontraron resultados"` | Message displayed when no results match the search. |
|
|
32
|
-
| `renderOption` | `(option, state: { isSelected, searchTerm }) => ReactNode` | — | Custom template for each dropdown option. |
|
|
33
|
-
| `clearable` | `boolean` | `true` | Shows a clear (X) button inside the input. |
|
|
34
|
-
| `onClear` | `() => void` | — | Callback fired when the clear button is pressed. |
|
|
35
|
-
|
|
36
|
-
## Usage
|
|
37
|
-
|
|
38
|
-
```tsx
|
|
39
|
-
import { ITSearchSelect } from '@axzydev/axzy_ui_system';
|
|
40
|
-
|
|
41
|
-
<ITSearchSelect
|
|
42
|
-
name="user"
|
|
43
|
-
label="Select User"
|
|
44
|
-
placeholder="Search user..."
|
|
45
|
-
options={users}
|
|
46
|
-
value={selected}
|
|
47
|
-
onChange={(val) => setSelected(val)}
|
|
48
|
-
/>
|
|
49
|
-
|
|
50
|
-
<ITSearchSelect
|
|
51
|
-
name="remote"
|
|
52
|
-
label="API Search"
|
|
53
|
-
placeholder="Type to search..."
|
|
54
|
-
options={remoteOptions}
|
|
55
|
-
isLoading={loading}
|
|
56
|
-
onSearch={(query) => fetchResults(query)}
|
|
57
|
-
value={selected}
|
|
58
|
-
onChange={(val) => setSelected(val)}
|
|
59
|
-
/>
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Notes
|
|
63
|
-
|
|
64
|
-
- **Static mode**: provide an `options` array and the component filters client-side as the user types.
|
|
65
|
-
- **Remote mode**: provide an `onSearch` callback and manage `options`/`isLoading` externally for API-driven searches.
|
|
66
|
-
- `valueField` and `labelField` allow custom option object structures beyond `{ value, label }`.
|
|
67
|
-
- Validation states: `error` string displays inline, `touched` gates error visibility, `required` adds a red asterisk.
|
|
68
|
-
- `readOnly` mode renders the selected value as non-interactive text.
|
|
69
|
-
- Supports `className` for style overrides and width control.
|
|
70
|
-
- **Custom options**: `renderOption` replaces the default option rendering and receives `{ isSelected, searchTerm }`.
|
|
71
|
-
- **Clear button**: an (X) button appears inside the input when there is a search term or a selected value; `clearable={false}` disables it. Clearing resets the search and selection, and calls `onSearch("")` / `onClear()`.
|
|
72
|
-
|
|
73
|
-
## Stories
|
|
74
|
-
|
|
75
|
-
<Primary />
|
|
76
|
-
<Controls />
|
|
77
|
-
<Stories />
|