@axzydev/axzy_ui_system 1.2.6 → 1.2.8
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/dist/index.cjs +777 -535
- 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 +1470 -87
- package/dist/index.d.ts +1470 -87
- package/dist/index.js +799 -555
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/App.tsx +19 -54
- package/src/components/alert/alert.doc.mdx +48 -0
- package/src/components/alert/alert.props.ts +7 -0
- package/src/components/alert/alert.tsx +8 -0
- package/src/components/avatar/avatar.doc.mdx +48 -0
- package/src/components/avatar/avatar.props.ts +8 -0
- package/src/components/avatar/avatar.tsx +25 -5
- package/src/components/badget/badget.doc.mdx +46 -0
- package/src/components/badget/badget.props.ts +6 -0
- package/src/components/badget/badget.tsx +11 -0
- package/src/components/breadcrumbs/breadcrumbs.doc.mdx +57 -0
- package/src/components/breadcrumbs/breadcrumbs.props.ts +6 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +12 -0
- package/src/components/button/button.doc.mdx +59 -0
- package/src/components/button/button.props.ts +12 -0
- package/src/components/button/button.tsx +11 -0
- package/src/components/calendar/calendar.doc.mdx +75 -0
- package/src/components/calendar/calendar.props.ts +27 -7
- package/src/components/calendar/calendar.tsx +13 -0
- package/src/components/card/card.doc.mdx +54 -0
- package/src/components/card/card.props.ts +11 -0
- package/src/components/card/card.tsx +13 -0
- package/src/components/checkbox/checkbox.doc.mdx +54 -0
- package/src/components/checkbox/checkbox.props.ts +7 -0
- package/src/components/checkbox/checkbox.tsx +9 -0
- package/src/components/confirm-dialog/confirm-dialog.doc.mdx +60 -0
- package/src/components/confirm-dialog/confirm-dialog.props.ts +9 -0
- package/src/components/confirm-dialog/confirm-dialog.tsx +19 -0
- package/src/components/data-table/ITDataTable.doc.mdx +59 -0
- package/src/components/data-table/dataTable.props.ts +15 -0
- package/src/components/data-table/dataTable.tsx +178 -73
- package/src/components/date-picker/date-picker.doc.mdx +65 -0
- package/src/components/date-picker/date-picker.props.ts +17 -0
- package/src/components/date-picker/datePicker.tsx +31 -1
- package/src/components/dialog/dialog.doc.mdx +54 -0
- package/src/components/dialog/dialog.props.ts +7 -0
- package/src/components/dialog/dialog.tsx +26 -0
- package/src/components/divider/divider.doc.mdx +42 -0
- package/src/components/divider/divider.props.ts +5 -0
- package/src/components/divider/divider.tsx +16 -0
- package/src/components/drawer/drawer.doc.mdx +59 -0
- package/src/components/drawer/drawer.props.ts +9 -0
- package/src/components/drawer/drawer.tsx +20 -0
- package/src/components/dropfile/dropfile.doc.mdx +59 -0
- package/src/components/dropfile/dropfile.props.ts +41 -0
- package/src/components/dropfile/dropfile.tsx +21 -33
- package/src/components/empty-state/empty-state.doc.mdx +50 -0
- package/src/components/empty-state/empty-state.props.ts +5 -0
- package/src/components/empty-state/empty-state.tsx +16 -0
- package/src/components/flex/flex.doc.mdx +59 -0
- package/src/components/flex/flex.props.ts +13 -0
- package/src/components/flex/flex.tsx +15 -0
- package/src/components/form-builder/fieldRenderer.tsx +52 -2
- package/src/components/form-builder/formBuilder.doc.mdx +124 -0
- package/src/components/form-builder/formBuilder.props.ts +12 -2
- package/src/components/form-builder/formBuilder.tsx +31 -0
- package/src/components/form-header/form-header.doc.mdx +38 -0
- package/src/components/form-header/form-header.props.ts +3 -0
- package/src/components/form-header/form-header.stories.tsx +53 -0
- package/src/components/form-header/form-header.tsx +11 -0
- package/src/components/grid/grid.doc.mdx +54 -0
- package/src/components/grid/grid.props.ts +13 -0
- package/src/components/grid/grid.tsx +26 -2
- package/src/components/image/image.doc.mdx +44 -0
- package/src/components/image/image.props.ts +5 -0
- package/src/components/image/image.stories.tsx +49 -0
- package/src/components/image/image.tsx +19 -0
- package/src/components/input/input.doc.mdx +70 -0
- package/src/components/input/input.props.ts +34 -2
- package/src/components/input/input.tsx +29 -0
- package/src/components/layout/layout.doc.mdx +51 -0
- package/src/components/layout/layout.props.ts +5 -0
- package/src/components/layout/layout.tsx +41 -17
- package/src/components/loader/loader.doc.mdx +43 -0
- package/src/components/loader/loader.props.ts +4 -0
- package/src/components/loader/loader.tsx +17 -0
- package/src/components/navbar/navbar.doc.mdx +77 -0
- package/src/components/navbar/navbar.props.ts +37 -1
- package/src/components/navbar/navbar.stories.tsx +84 -0
- package/src/components/navbar/navbar.tsx +78 -46
- package/src/components/page/page.doc.mdx +80 -0
- package/src/components/page/page.props.ts +25 -0
- package/src/components/page/page.tsx +35 -7
- package/src/components/page-header/page-header.doc.mdx +54 -0
- package/src/components/page-header/page-header.props.ts +11 -0
- package/src/components/page-header/page-header.stories.tsx +14 -0
- package/src/components/page-header/page-header.tsx +50 -15
- package/src/components/pagination/pagination.doc.mdx +62 -0
- package/src/components/pagination/pagination.props.ts +11 -32
- package/src/components/pagination/pagination.tsx +17 -0
- package/src/components/popover/popover.doc.mdx +53 -0
- package/src/components/popover/popover.props.ts +8 -0
- package/src/components/popover/popover.tsx +13 -0
- package/src/components/progress/progress.doc.mdx +48 -0
- package/src/components/progress/progress.props.ts +8 -0
- package/src/components/progress/progress.tsx +9 -0
- package/src/components/radio/radio.doc.mdx +62 -0
- package/src/components/radio/radio.props.ts +11 -0
- package/src/components/radio/radio.tsx +18 -0
- package/src/components/search-select/search-select.doc.mdx +72 -0
- package/src/components/search-select/search-select.props.ts +23 -18
- package/src/components/search-select/search-select.tsx +27 -2
- package/src/components/searchTable/searchTable.doc.mdx +79 -0
- package/src/components/searchTable/searchTable.props.ts +42 -3
- package/src/components/searchTable/searchTable.stories.tsx +74 -0
- package/src/components/searchTable/searchTable.tsx +23 -0
- package/src/components/segmented-control/segmented-control.doc.mdx +60 -0
- package/src/components/segmented-control/segmented-control.props.ts +12 -0
- package/src/components/segmented-control/segmented-control.tsx +15 -0
- package/src/components/select/select.doc.mdx +75 -0
- package/src/components/select/select.props.ts +22 -0
- package/src/components/select/select.tsx +2 -5
- package/src/components/sidebar/sidebar.doc.mdx +86 -0
- package/src/components/sidebar/sidebar.props.ts +22 -0
- package/src/components/sidebar/sidebar.tsx +22 -0
- package/src/components/skeleton/skeleton.doc.mdx +43 -0
- package/src/components/skeleton/skeleton.props.ts +8 -0
- package/src/components/skeleton/skeleton.tsx +10 -0
- package/src/components/slide/slide.doc.mdx +46 -0
- package/src/components/slide/slide.props.ts +11 -24
- package/src/components/slide/slide.tsx +10 -1
- package/src/components/slider/slider.doc.mdx +49 -0
- package/src/components/slider/slider.props.ts +9 -0
- package/src/components/slider/slider.tsx +15 -0
- package/src/components/stack/stack.doc.mdx +126 -0
- package/src/components/stack/stack.props.ts +18 -0
- package/src/components/stack/stack.stories.tsx +221 -16
- package/src/components/stack/stack.tsx +21 -0
- package/src/components/stat-card/stat-card.doc.mdx +48 -0
- package/src/components/stat-card/stat-card.props.ts +9 -0
- package/src/components/stat-card/stat-card.tsx +10 -0
- package/src/components/stepper/stepper.doc.mdx +54 -0
- package/src/components/stepper/stepper.props.ts +11 -1
- package/src/components/stepper/stepper.tsx +15 -0
- package/src/components/table/table.doc.mdx +58 -0
- package/src/components/table/table.props.ts +17 -0
- package/src/components/table/table.tsx +199 -84
- package/src/components/tabs/tabs.doc.mdx +52 -0
- package/src/components/tabs/tabs.props.ts +11 -0
- package/src/components/tabs/tabs.tsx +14 -0
- package/src/components/text/text.doc.mdx +41 -0
- package/src/components/text/text.props.ts +5 -0
- package/src/components/text/text.stories.tsx +67 -0
- package/src/components/text/text.tsx +10 -0
- package/src/components/textarea/textarea.doc.mdx +64 -0
- package/src/components/textarea/textarea.props.ts +11 -0
- package/src/components/textarea/textarea.tsx +16 -0
- package/src/components/theme-provider/themeProvider.doc.mdx +75 -0
- package/src/components/theme-provider/themeProvider.props.ts +3 -0
- package/src/components/theme-provider/themeProvider.stories.tsx +59 -0
- package/src/components/theme-provider/themeProvider.tsx +14 -0
- package/src/components/time-picker/timePicker.doc.mdx +68 -0
- package/src/components/time-picker/timePicker.props.ts +14 -0
- package/src/components/time-picker/timePicker.tsx +22 -1
- package/src/components/toast/toast.doc.mdx +50 -0
- package/src/components/toast/toast.props.ts +5 -0
- package/src/components/toast/toast.tsx +21 -0
- package/src/components/tooltip/tooltip.doc.mdx +47 -0
- package/src/components/tooltip/tooltip.props.ts +6 -0
- package/src/components/tooltip/tooltip.tsx +19 -0
- package/src/components/topbar/topbar.doc.mdx +69 -0
- package/src/components/topbar/topbar.props.ts +15 -0
- package/src/components/topbar/topbar.tsx +38 -0
- package/src/components/triple-filter/tripleFilter.doc.mdx +62 -0
- package/src/components/triple-filter/tripleFilter.props.ts +7 -0
- package/src/components/triple-filter/tripleFilter.tsx +32 -0
- package/src/index.css +17 -0
- package/src/showcases/DataShowcases.tsx +529 -45
- package/src/showcases/FormShowcases.tsx +399 -29
- package/src/showcases/HomeShowcase.tsx +252 -272
- package/src/showcases/LayoutPrimitivesShowcases.tsx +1224 -248
- package/src/showcases/PageShowcases.tsx +868 -151
- package/src/showcases/ShowcaseLayout.tsx +237 -73
- package/src/showcases/StructureShowcases.tsx +1039 -97
- package/src/types/table.types.ts +1 -1
- package/src/utils/styles.ts +2 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './formBuilder.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# ITFormBuilder
|
|
7
|
+
|
|
8
|
+
A dynamic form generator that renders fields from JSON-like configuration (V1 or V2). Integrates with Formik and Yup for validation. Supports conditional rendering, calculated fields, grid layout, async validation, and custom components.
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
|------|------|---------|-------------|
|
|
14
|
+
| `fields` | `FieldConfig[]` | — | Legacy V1 field definitions (backward compatible). |
|
|
15
|
+
| `config` | `FieldConfigV2[]` | — | V2 field configuration array with conditional logic, dynamic props, and grid layout. |
|
|
16
|
+
| `columns` | `number` | — | Number of grid columns (1–12). |
|
|
17
|
+
| `values` | `any` | — | Current form values keyed by field name. |
|
|
18
|
+
| `handleChange` | `(event) => void` | — | Change handler for input, select, and textarea elements. |
|
|
19
|
+
| `handleBlur` | `(event) => void` | — | Blur handler for input, select, and textarea elements. |
|
|
20
|
+
| `touched` | `any` | — | Touch state keyed by field name. |
|
|
21
|
+
| `errors` | `any` | — | Validation errors keyed by field name. |
|
|
22
|
+
| `setFieldValue` | `(field, value, shouldValidate?) => Promise<void>` | — | Programmatically set a field value. |
|
|
23
|
+
| `setFieldTouched` | `(field, touched?, shouldValidate?) => Promise<void>` | — | Programmatically mark a field as touched. |
|
|
24
|
+
| `setFieldError` | `(field, message?) => void` | — | Programmatically set a field-level error. |
|
|
25
|
+
| `isSubmitting` | `boolean` | — | Whether the form is currently submitting. |
|
|
26
|
+
|
|
27
|
+
### FieldConfigV2 Key Properties
|
|
28
|
+
|
|
29
|
+
| Property | Type | Description |
|
|
30
|
+
|----------|------|-------------|
|
|
31
|
+
| `type` | `"text" \| "number" \| "password" \| "email" \| "select" \| "date" \| "time" \| "checkbox" \| "radio" \| "array" \| "section" \| "custom"` | Field input type. |
|
|
32
|
+
| `column` | `number \| { sm?, md?, lg?, xl? }` | Grid column span (responsive object or single number). |
|
|
33
|
+
| `dependsOn` | `string[]` | Sibling field names to watch for conditional re-evaluation. |
|
|
34
|
+
| `renderWhen` | `(values) => boolean` | When false, the field is not rendered or submitted. |
|
|
35
|
+
| `dynamicProps` | `(values) => Partial<FieldConfigV2>` | Dynamically override field props based on form state. |
|
|
36
|
+
| `validation` | `Yup.AnySchema` | Per-field Yup validation schema. |
|
|
37
|
+
| `asyncValidation` | `(value, values) => Promise<string \| null>` | Async per-field validation returning error string. |
|
|
38
|
+
| `onChangeAction` | `(val, context) => void \| Promise<void>` | Lifecycle hook for side effects (e.g., calculate totals). |
|
|
39
|
+
| `options` | `Array \| () => Promise<Array>` | Select/radio options, sync or async. |
|
|
40
|
+
| `component` | `React.ComponentType` | Custom renderer for `type: "custom"`. |
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { ITFormBuilder } from '@axzydev/axzy_ui_system';
|
|
46
|
+
import { Formik } from 'formik';
|
|
47
|
+
import * as Yup from 'yup';
|
|
48
|
+
|
|
49
|
+
const schema = Yup.object({
|
|
50
|
+
email: Yup.string().email("Invalid email").required("Required"),
|
|
51
|
+
password: Yup.string().min(8).required("Required"),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const fields = [
|
|
55
|
+
{ name: "email", label: "Email", type: "email", required: true, column: { sm: 12 } },
|
|
56
|
+
{ name: "password", label: "Password", type: "password", required: true, column: { sm: 12 } },
|
|
57
|
+
{
|
|
58
|
+
name: "subtotal",
|
|
59
|
+
label: "Subtotal",
|
|
60
|
+
type: "number",
|
|
61
|
+
currencyFormat: true,
|
|
62
|
+
column: { sm: 12, md: 4 },
|
|
63
|
+
onChangeAction: (val, { setFieldValue }) => {
|
|
64
|
+
const num = parseFloat(val) || 0;
|
|
65
|
+
setFieldValue("total", (num * 1.16).toFixed(2));
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "total",
|
|
70
|
+
label: "Total",
|
|
71
|
+
type: "number",
|
|
72
|
+
currencyFormat: true,
|
|
73
|
+
disabled: true,
|
|
74
|
+
column: { sm: 12, md: 4 },
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "rfc",
|
|
78
|
+
label: "RFC",
|
|
79
|
+
type: "text",
|
|
80
|
+
dependsOn: ["country"],
|
|
81
|
+
renderWhen: (vals) => vals.country === "MX",
|
|
82
|
+
required: true,
|
|
83
|
+
column: { sm: 12, md: 6 },
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
<Formik
|
|
88
|
+
initialValues={{ email: "", password: "", subtotal: "", total: "", rfc: "" }}
|
|
89
|
+
validationSchema={schema}
|
|
90
|
+
onSubmit={handleSubmit}
|
|
91
|
+
>
|
|
92
|
+
{(formikProps) => (
|
|
93
|
+
<form onSubmit={formikProps.handleSubmit}>
|
|
94
|
+
<ITFormBuilder
|
|
95
|
+
config={fields}
|
|
96
|
+
columns={12}
|
|
97
|
+
values={formikProps.values}
|
|
98
|
+
handleChange={formikProps.handleChange}
|
|
99
|
+
handleBlur={formikProps.handleBlur}
|
|
100
|
+
touched={formikProps.touched}
|
|
101
|
+
errors={formikProps.errors}
|
|
102
|
+
setFieldValue={formikProps.setFieldValue}
|
|
103
|
+
/>
|
|
104
|
+
<button type="submit">Submit</button>
|
|
105
|
+
</form>
|
|
106
|
+
)}
|
|
107
|
+
</Formik>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Notes
|
|
111
|
+
|
|
112
|
+
- Supports both legacy V1 (`fields` prop) and enterprise V2 (`config` prop) field configurations.
|
|
113
|
+
- V2 fields support a powerful rules engine: `dependsOn`, `renderWhen`, and `dynamicProps` for conditional behavior.
|
|
114
|
+
- `onChangeAction` enables real-time field calculations and cross-field updates.
|
|
115
|
+
- Grid layout uses a responsive 12-column system with per-breakpoint column span configuration.
|
|
116
|
+
- Field types include `section` (grouping with collapsible regions) and `array` (dynamic repeatable lists).
|
|
117
|
+
- Fully Formik-compatible — requires Formik context wrapping for state management.
|
|
118
|
+
- `custom` type allows injecting arbitrary React components for complete layout control.
|
|
119
|
+
|
|
120
|
+
## Stories
|
|
121
|
+
|
|
122
|
+
<Primary />
|
|
123
|
+
<Controls />
|
|
124
|
+
<Stories />
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { FieldConfig, FieldConfigV2 } from "@/types/field.types";
|
|
2
2
|
|
|
3
3
|
export interface ITFormBuilderProps {
|
|
4
|
-
|
|
4
|
+
/** Legacy field definitions (V1). Use `config` for the V2 architecture instead */
|
|
5
5
|
fields?: FieldConfig[];
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/** V2 field configuration array. Preferred over the legacy `fields` prop */
|
|
8
8
|
config?: FieldConfigV2[];
|
|
9
9
|
|
|
10
|
+
/** Number of grid columns (1-12) */
|
|
10
11
|
columns?: number;
|
|
12
|
+
/** Current form values keyed by field name */
|
|
11
13
|
values: any;
|
|
14
|
+
/** Change handler for input, select, and textarea elements */
|
|
12
15
|
handleChange: (
|
|
13
16
|
event:
|
|
14
17
|
| React.ChangeEvent<HTMLInputElement>
|
|
@@ -16,6 +19,7 @@ export interface ITFormBuilderProps {
|
|
|
16
19
|
| React.ChangeEvent<HTMLSelectElement>
|
|
17
20
|
| { target: { name: string; value: any } }
|
|
18
21
|
) => void;
|
|
22
|
+
/** Blur handler for input, select, and textarea elements */
|
|
19
23
|
handleBlur: (
|
|
20
24
|
event:
|
|
21
25
|
| React.FocusEvent<HTMLInputElement>
|
|
@@ -23,21 +27,27 @@ export interface ITFormBuilderProps {
|
|
|
23
27
|
| React.FocusEvent<HTMLTextAreaElement, Element>
|
|
24
28
|
| { target: { name: string; value: any } }
|
|
25
29
|
) => void;
|
|
30
|
+
/** Touch state keyed by field name */
|
|
26
31
|
touched: any;
|
|
32
|
+
/** Validation errors keyed by field name */
|
|
27
33
|
errors: any;
|
|
34
|
+
/** Programmatically set a field value */
|
|
28
35
|
setFieldValue?: (
|
|
29
36
|
field: string,
|
|
30
37
|
value: any,
|
|
31
38
|
shouldValidate?: boolean
|
|
32
39
|
) => Promise<void | any>;
|
|
40
|
+
/** Programmatically mark a field as touched */
|
|
33
41
|
setFieldTouched?: (
|
|
34
42
|
field: string,
|
|
35
43
|
touched?: boolean,
|
|
36
44
|
shouldValidate?: boolean
|
|
37
45
|
) => Promise<void | any>;
|
|
46
|
+
/** Programmatically set a field-level error message */
|
|
38
47
|
setFieldError?: (
|
|
39
48
|
field: string,
|
|
40
49
|
message: string | undefined
|
|
41
50
|
) => void;
|
|
51
|
+
/** Whether the form is currently submitting */
|
|
42
52
|
isSubmitting?: boolean;
|
|
43
53
|
}
|
|
@@ -20,6 +20,37 @@ function buildDependentValues(
|
|
|
20
20
|
return deps;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Dynamic form generator from field definitions with validation support.
|
|
25
|
+
* Renders a responsive grid of inputs, selects, and date pickers based on
|
|
26
|
+
* the provided field configuration. Supports both legacy (`fields`) and
|
|
27
|
+
* V2 (`config`) field definition formats.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* <ITFormBuilder
|
|
31
|
+
* fields={[
|
|
32
|
+
* { name: "email", label: "Email", type: "text", required: true, column: 6 },
|
|
33
|
+
* { name: "role", label: "Role", type: "select", options: [{ id: 1, label: "Admin" }], column: 6 },
|
|
34
|
+
* ]}
|
|
35
|
+
* values={formValues}
|
|
36
|
+
* handleChange={handleChange}
|
|
37
|
+
* handleBlur={handleBlur}
|
|
38
|
+
* touched={touched}
|
|
39
|
+
* errors={errors}
|
|
40
|
+
* columns={12}
|
|
41
|
+
* />
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* <ITFormBuilder
|
|
45
|
+
* config={v2FieldConfigs}
|
|
46
|
+
* values={formValues}
|
|
47
|
+
* handleChange={handleChange}
|
|
48
|
+
* handleBlur={handleBlur}
|
|
49
|
+
* touched={touched}
|
|
50
|
+
* errors={errors}
|
|
51
|
+
* isSubmitting={loading}
|
|
52
|
+
* />
|
|
53
|
+
*/
|
|
23
54
|
export default function ITFormBuilder({
|
|
24
55
|
fields,
|
|
25
56
|
config,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './form-header.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# ITFormHeader
|
|
7
|
+
|
|
8
|
+
A colored header bar for modal dialogs and form containers. Displays a title centered on a primary-colored background, with an optional close (X) button on the right side.
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
|------|------|---------|-------------|
|
|
14
|
+
| `title` | `string` | required | Header title text, centered in the bar. |
|
|
15
|
+
| `onClose` | `() => void` | `undefined` | Optional close button handler. When provided, an X button renders. |
|
|
16
|
+
| `className` | `string` | `undefined` | Additional CSS classes applied to the container. |
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { ITFormHeader } from '@axzydev/axzy_ui_system';
|
|
22
|
+
|
|
23
|
+
<ITFormHeader title="Edit Record" />
|
|
24
|
+
<ITFormHeader title="Confirm" onClose={() => handleClose()} />
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Notes
|
|
28
|
+
|
|
29
|
+
- Uses the theme primary color as the background.
|
|
30
|
+
- The title truncates with ellipsis when it overflows the available width.
|
|
31
|
+
- Close button is only rendered when `onClose` is provided.
|
|
32
|
+
- Intended for use inside modals, drawers, or form panels.
|
|
33
|
+
|
|
34
|
+
## Stories
|
|
35
|
+
|
|
36
|
+
<Primary />
|
|
37
|
+
<Controls />
|
|
38
|
+
<Stories />
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import ITFormHeader from './form-header';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Components/Feedback/ITFormHeader',
|
|
6
|
+
component: ITFormHeader,
|
|
7
|
+
parameters: { layout: 'centered' },
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
argTypes: {
|
|
10
|
+
title: { control: 'text', description: 'The title displayed in the header' },
|
|
11
|
+
onClose: { control: false, description: 'Optional close button handler' },
|
|
12
|
+
className: { control: 'text', description: 'Additional CSS classes' },
|
|
13
|
+
},
|
|
14
|
+
} satisfies Meta<typeof ITFormHeader>;
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof meta>;
|
|
18
|
+
|
|
19
|
+
export const Default: Story = {
|
|
20
|
+
args: { title: 'Form Header' },
|
|
21
|
+
render: (args) => (
|
|
22
|
+
<div className="w-80">
|
|
23
|
+
<ITFormHeader {...args} />
|
|
24
|
+
</div>
|
|
25
|
+
),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const WithClose: Story = {
|
|
29
|
+
args: { title: 'Editable Form' },
|
|
30
|
+
render: (args) => (
|
|
31
|
+
<div className="w-80">
|
|
32
|
+
<ITFormHeader {...args} onClose={() => alert('Close clicked')} />
|
|
33
|
+
</div>
|
|
34
|
+
),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const LongTitle: Story = {
|
|
38
|
+
args: { title: 'Confirmación de Auditoría de Expediente Clínico' },
|
|
39
|
+
render: (args) => (
|
|
40
|
+
<div className="w-80">
|
|
41
|
+
<ITFormHeader {...args} />
|
|
42
|
+
</div>
|
|
43
|
+
),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const ShortTitle: Story = {
|
|
47
|
+
args: { title: 'Edit' },
|
|
48
|
+
render: (args) => (
|
|
49
|
+
<div className="w-80">
|
|
50
|
+
<ITFormHeader {...args} />
|
|
51
|
+
</div>
|
|
52
|
+
),
|
|
53
|
+
};
|
|
@@ -4,6 +4,17 @@ import { useITThemeSafe } from "../theme-provider/themeProvider";
|
|
|
4
4
|
import { getContrastTextColor } from "@/utils/color.utils";
|
|
5
5
|
import ITText from "@/components/text/text";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Colored header bar for modals and forms with an optional close button.
|
|
9
|
+
* Uses the theme's primary color as the background and automatically
|
|
10
|
+
* calculates a contrasting text color for readability.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <ITFormHeader title="Create User" onClose={() => setOpen(false)} />
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <ITFormHeader title="Details" className="rounded-none" />
|
|
17
|
+
*/
|
|
7
18
|
export default function ITFormHeader({
|
|
8
19
|
title,
|
|
9
20
|
onClose,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './grid.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# ITGrid
|
|
7
|
+
|
|
8
|
+
A responsive 12-column CSS grid system for building flexible layouts. Supports grid container and item modes, configurable column spans per breakpoint, and customizable gap spacing.
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
|------|------|---------|-------------|
|
|
14
|
+
| `children` | `ReactNode` | `undefined` | Child elements rendered inside the grid. |
|
|
15
|
+
| `container` | `boolean` | `false` | When true, renders as a CSS grid parent. |
|
|
16
|
+
| `item` | `boolean` | `false` | When true, renders as a CSS grid child with column span. |
|
|
17
|
+
| `spacing` | `number` | `undefined` | Gap between children in units of 0.25rem. Container only. |
|
|
18
|
+
| `columns` | `number` | `12` | Number of grid columns (1-12). Container only. |
|
|
19
|
+
| `xs` | `number` | `undefined` | Column span at base breakpoint (mobile). Falls back to `sm`. |
|
|
20
|
+
| `sm` | `number` | `undefined` | Column span at the `sm` breakpoint. |
|
|
21
|
+
| `md` | `number` | `undefined` | Column span at the `md` breakpoint. |
|
|
22
|
+
| `lg` | `number` | `undefined` | Column span at the `lg` breakpoint. |
|
|
23
|
+
| `xl` | `number` | `undefined` | Column span at the `xl` breakpoint. |
|
|
24
|
+
| `className` | `string` | `undefined` | Additional CSS classes. |
|
|
25
|
+
| `style` | `CSSProperties` | `undefined` | Inline styles. |
|
|
26
|
+
| `as` | `ElementType` | `'div'` | Custom HTML element type to render instead of div. |
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { ITGrid } from '@axzydev/axzy_ui_system';
|
|
32
|
+
|
|
33
|
+
<ITGrid container spacing={3}>
|
|
34
|
+
<ITGrid item xs={12} md={8}>
|
|
35
|
+
<div>Main content</div>
|
|
36
|
+
</ITGrid>
|
|
37
|
+
<ITGrid item xs={12} md={4}>
|
|
38
|
+
<div>Sidebar</div>
|
|
39
|
+
</ITGrid>
|
|
40
|
+
</ITGrid>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Notes
|
|
44
|
+
|
|
45
|
+
- Uses CSS Grid under the hood with responsive breakpoint classes.
|
|
46
|
+
- Omitting both `container` and `item` renders a plain `div` with no grid behavior.
|
|
47
|
+
- Breakpoint spans cascade down: if `lg` is not set, it inherits `md`, then `sm`, then `xs`.
|
|
48
|
+
- `spacing` multiplies by 0.25rem internally (spacing={2} = 0.5rem gap).
|
|
49
|
+
|
|
50
|
+
## Stories
|
|
51
|
+
|
|
52
|
+
<Primary />
|
|
53
|
+
<Controls />
|
|
54
|
+
<Stories />
|
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
import { ReactNode, CSSProperties, ElementType } from "react";
|
|
2
2
|
|
|
3
3
|
export interface ITGridProps {
|
|
4
|
+
/** Child elements */
|
|
4
5
|
children?: ReactNode;
|
|
6
|
+
/** Render as a grid container (CSS grid parent) */
|
|
5
7
|
container?: boolean;
|
|
8
|
+
/** Render as a grid item (CSS grid child). If neither `container` nor `item` is set, renders a plain div */
|
|
6
9
|
item?: boolean;
|
|
10
|
+
/** Gap between grid children in units of 0.25rem. Only applies when `container` is true */
|
|
7
11
|
spacing?: number;
|
|
12
|
+
/** Number of grid columns (1-12). Only applies when `container` is true */
|
|
8
13
|
columns?: number;
|
|
14
|
+
/** Column span at the base breakpoint (mobile). Falls back to `sm` if not set */
|
|
9
15
|
xs?: number;
|
|
16
|
+
/** Column span at the `sm` breakpoint */
|
|
10
17
|
sm?: number;
|
|
18
|
+
/** Column span at the `md` breakpoint */
|
|
11
19
|
md?: number;
|
|
20
|
+
/** Column span at the `lg` breakpoint */
|
|
12
21
|
lg?: number;
|
|
22
|
+
/** Column span at the `xl` breakpoint */
|
|
13
23
|
xl?: number;
|
|
24
|
+
/** Additional CSS classes */
|
|
14
25
|
className?: string;
|
|
26
|
+
/** Inline styles */
|
|
15
27
|
style?: CSSProperties;
|
|
28
|
+
/** Custom HTML element type to render instead of the default `div` */
|
|
16
29
|
as?: ElementType;
|
|
17
30
|
}
|
|
@@ -13,6 +13,30 @@ function breakpointSpan(span: number | undefined, bp: string, cols: number) {
|
|
|
13
13
|
return `${bp}:col-span-${clamped}`;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function gridColsClass(cols: number) {
|
|
17
|
+
const clamped = Math.min(Math.max(cols, 1), 12);
|
|
18
|
+
return `grid-cols-${clamped}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Responsive 12-column CSS grid layout system.
|
|
23
|
+
* Renders as a grid container when `container` is true, as a column-spanning
|
|
24
|
+
* item when `item` is true. Supports breakpoint-aware column spans and
|
|
25
|
+
* configurable spacing between items.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* <ITGrid container columns={12} spacing={4}>
|
|
29
|
+
* <ITGrid item xs={12} md={6}>Sidebar</ITGrid>
|
|
30
|
+
* <ITGrid item xs={12} md={6}>Content</ITGrid>
|
|
31
|
+
* </ITGrid>
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* <ITGrid container columns={3} spacing={2} as="section">
|
|
35
|
+
* <ITGrid item>Card 1</ITGrid>
|
|
36
|
+
* <ITGrid item>Card 2</ITGrid>
|
|
37
|
+
* <ITGrid item>Card 3</ITGrid>
|
|
38
|
+
* </ITGrid>
|
|
39
|
+
*/
|
|
16
40
|
export default function ITGrid({
|
|
17
41
|
children,
|
|
18
42
|
container,
|
|
@@ -31,9 +55,8 @@ export default function ITGrid({
|
|
|
31
55
|
if (container) {
|
|
32
56
|
return (
|
|
33
57
|
<Component
|
|
34
|
-
className={clsx("grid", className)}
|
|
58
|
+
className={clsx("grid", gridColsClass(columns), className)}
|
|
35
59
|
style={{
|
|
36
|
-
gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
|
|
37
60
|
gap: spacing > 0 ? `${spacing * 0.25}rem` : undefined,
|
|
38
61
|
...style,
|
|
39
62
|
}}
|
|
@@ -47,6 +70,7 @@ export default function ITGrid({
|
|
|
47
70
|
return (
|
|
48
71
|
<Component
|
|
49
72
|
className={clsx(
|
|
73
|
+
"col-span-full",
|
|
50
74
|
colSpanClass(xs ?? sm, columns),
|
|
51
75
|
sm !== undefined && breakpointSpan(sm, "sm", columns),
|
|
52
76
|
md !== undefined && breakpointSpan(md, "md", columns),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './image.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# ITImage
|
|
7
|
+
|
|
8
|
+
An image component with automatic fallback on load error. Uses a native `<img>` element with an error boundary that swaps the source to a fallback URL when the primary image fails to load.
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
|------|------|---------|-------------|
|
|
14
|
+
| `src` | `string` | required | Source URL of the image. |
|
|
15
|
+
| `alt` | `string` | `undefined` | Alt text for accessibility. |
|
|
16
|
+
| `className` | `string` | `undefined` | Additional CSS classes for the wrapper. |
|
|
17
|
+
| `fallback` | `string` | `undefined` | Fallback image URL shown when `src` fails to load. |
|
|
18
|
+
| `onClick` | `() => void` | `undefined` | Click handler on the image. |
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { ITImage } from '@axzydev/axzy_ui_system';
|
|
24
|
+
|
|
25
|
+
<ITImage
|
|
26
|
+
src="https://example.com/photo.jpg"
|
|
27
|
+
alt="Profile photo"
|
|
28
|
+
fallback="https://example.com/default-avatar.jpg"
|
|
29
|
+
/>
|
|
30
|
+
<ITImage src="https://example.com/logo.png" />
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- Handles `onerror` internally to swap to the `fallback` URL.
|
|
36
|
+
- The wrapper is an inline-block `div` with full width/height for responsive sizing within a sized parent.
|
|
37
|
+
- If no `fallback` is provided and the image errors, the broken image icon is shown.
|
|
38
|
+
- Uses `object-cover` to fill the container while maintaining aspect ratio.
|
|
39
|
+
|
|
40
|
+
## Stories
|
|
41
|
+
|
|
42
|
+
<Primary />
|
|
43
|
+
<Controls />
|
|
44
|
+
<Stories />
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
export interface ITImageProps {
|
|
2
|
+
/** Source URL of the image */
|
|
2
3
|
src: string;
|
|
4
|
+
/** Alt text for accessibility */
|
|
3
5
|
alt?: string;
|
|
6
|
+
/** Additional CSS classes */
|
|
4
7
|
className?: string;
|
|
8
|
+
/** Fallback image URL shown when the primary `src` fails to load */
|
|
5
9
|
fallback?: string;
|
|
10
|
+
/** Click handler */
|
|
6
11
|
onClick?: () => void;
|
|
7
12
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import ITImage from './image';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Components/Data Display/ITImage',
|
|
6
|
+
component: ITImage,
|
|
7
|
+
parameters: { layout: 'centered' },
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
argTypes: {
|
|
10
|
+
src: { control: 'text', description: 'Image source URL' },
|
|
11
|
+
alt: { control: 'text', description: 'Alternative text for accessibility' },
|
|
12
|
+
fallback: { control: 'text', description: 'Fallback image URL shown when the primary src fails to load' },
|
|
13
|
+
className: { control: 'text', description: 'Additional CSS classes for the wrapper' },
|
|
14
|
+
onClick: { control: false, description: 'Click handler' },
|
|
15
|
+
},
|
|
16
|
+
} satisfies Meta<typeof ITImage>;
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof meta>;
|
|
20
|
+
|
|
21
|
+
const containerStyle = { width: 256, height: 192 };
|
|
22
|
+
|
|
23
|
+
export const Default: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
src: 'https://picsum.photos/256/192',
|
|
26
|
+
alt: 'Random image',
|
|
27
|
+
className: 'rounded-lg overflow-hidden',
|
|
28
|
+
},
|
|
29
|
+
render: (args) => <div style={containerStyle}><ITImage {...args} /></div>,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const WithFallbackError: Story = {
|
|
33
|
+
args: {
|
|
34
|
+
src: 'https://invalid-url/does-not-exist.jpg',
|
|
35
|
+
alt: 'Broken image',
|
|
36
|
+
fallback: 'https://picsum.photos/256/192?grayscale',
|
|
37
|
+
className: 'rounded-lg overflow-hidden',
|
|
38
|
+
},
|
|
39
|
+
render: (args) => <div style={containerStyle}><ITImage {...args} /></div>,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const SquareAspectRatio: Story = {
|
|
43
|
+
args: {
|
|
44
|
+
src: 'https://picsum.photos/200/200',
|
|
45
|
+
alt: 'Square image',
|
|
46
|
+
className: 'rounded-full overflow-hidden',
|
|
47
|
+
},
|
|
48
|
+
render: (args) => <div style={{ width: 128, height: 128 }}><ITImage {...args} /></div>,
|
|
49
|
+
};
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { ITImageProps } from "./image.props";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Image component with automatic fallback on load error.
|
|
6
|
+
* Displays the primary `src` image and gracefully switches to the
|
|
7
|
+
* `fallback` image if loading fails.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <ITImage
|
|
11
|
+
* src="https://example.com/photo.jpg"
|
|
12
|
+
* fallback="/images/placeholder.png"
|
|
13
|
+
* alt="User photo"
|
|
14
|
+
* />
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <ITImage
|
|
18
|
+
* src="/assets/logo.svg"
|
|
19
|
+
* alt="Company Logo"
|
|
20
|
+
* className="w-32 h-32 rounded-full"
|
|
21
|
+
* />
|
|
22
|
+
*/
|
|
4
23
|
const ITImage = ({
|
|
5
24
|
src,
|
|
6
25
|
alt,
|