laif-ds 0.2.75 → 0.2.77
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/CHANGELOG.md +27 -0
- package/dist/_virtual/index6.js +2 -2
- package/dist/_virtual/index7.js +2 -2
- package/dist/agent-docs/adoption-report.json +43 -39
- package/dist/agent-docs/components/AppCard.md +308 -0
- package/dist/agent-docs/components/AppForm.md +169 -358
- package/dist/agent-docs/components/DataTable.md +3 -0
- package/dist/agent-docs/components/FileUploader.md +7 -1
- package/dist/agent-docs/components-list.md +2 -0
- package/dist/agent-docs/manifest.json +110 -27
- package/dist/agent-docs/truncated-cell.md +342 -0
- package/dist/components/ui/app-card.js +115 -0
- package/dist/components/ui/app-form.js +322 -289
- package/dist/components/ui/card.js +20 -6
- package/dist/components/ui/file-uploader.js +86 -78
- package/dist/components/ui/tables/data-table/components/data-table-body.js +123 -115
- package/dist/components/ui/tables/data-table/components/data-table-header.js +6 -5
- package/dist/components/ui/tables/data-table/data-table.js +71 -69
- package/dist/components/ui/tables/data-table/data-table.utils.js +23 -15
- package/dist/components/ui/truncated-cell.js +100 -0
- package/dist/index.d.ts +212 -11
- package/dist/index.js +377 -373
- package/dist/node_modules/eventemitter3/index2.js +1 -1
- package/dist/node_modules/style-to-object/cjs/index.js +1 -1
- package/dist/styles.v3.css +1 -1
- package/package.json +1 -1
|
@@ -11,8 +11,10 @@ Dynamic form component that integrates with React Hook Form to provide a configu
|
|
|
11
11
|
### AppFormItem
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
export
|
|
15
|
-
label
|
|
14
|
+
export type AppFormItem<TAsyncOption = unknown> = {
|
|
15
|
+
/** Field label displayed above the component. */
|
|
16
|
+
label: string;
|
|
17
|
+
/** The type of form component to render. */
|
|
16
18
|
component:
|
|
17
19
|
| "input"
|
|
18
20
|
| "select"
|
|
@@ -24,29 +26,98 @@ export interface AppFormItem {
|
|
|
24
26
|
| "switch"
|
|
25
27
|
| "slider"
|
|
26
28
|
| "async"
|
|
27
|
-
| "async-multiple"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
29
|
+
| "async-multiple"
|
|
30
|
+
| "custom";
|
|
31
|
+
/** Field name used for React Hook Form state binding and validation. */
|
|
32
|
+
name: string;
|
|
33
|
+
/**
|
|
34
|
+
* HTML input type. Only applies when `component` is `"input"`.
|
|
35
|
+
* @example "text" | "email" | "password" | "number" | "url" | "search" | "tel"
|
|
36
|
+
*/
|
|
37
|
+
inputType?: ComponentProps<"input">["type"];
|
|
38
|
+
/** Initial value for the field. */
|
|
39
|
+
defaultValue?: string | boolean | number | string[] | Date | number[];
|
|
40
|
+
/** Options list for `select`, `multiselect`, and `radio` components. */
|
|
41
|
+
options?: AppSelectOption[];
|
|
42
|
+
/** Disables the field, preventing user interaction. @default false */
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
/** Placeholder text shown when no value is selected or entered. */
|
|
45
|
+
placeholder?: string;
|
|
46
|
+
/** Helper text displayed below the field. */
|
|
47
|
+
caption?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Enables range mode on the `datepicker` component when provided.
|
|
50
|
+
* The two dates define the selectable calendar boundaries.
|
|
51
|
+
*/
|
|
52
|
+
calendarRange?: [Date, Date];
|
|
53
|
+
/** Minimum value for the `slider` component. @default 0 */
|
|
54
|
+
min?: number;
|
|
55
|
+
/** Maximum value for the `slider` component. @default 100 */
|
|
56
|
+
max?: number;
|
|
57
|
+
/** Step increment for the `slider` component. @default 1 */
|
|
58
|
+
step?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Async data loader for `async` and `async-multiple` components.
|
|
61
|
+
* Called with the current search query; must return a promise of options.
|
|
62
|
+
*/
|
|
63
|
+
fetcher?: (query?: string) => Promise<TAsyncOption[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Custom render function for each option item in the async dropdown.
|
|
66
|
+
* Required for `async` and `async-multiple` components.
|
|
67
|
+
*/
|
|
68
|
+
renderOptionItem?: (option: TAsyncOption) => React.ReactNode;
|
|
69
|
+
/**
|
|
70
|
+
* Extracts the unique string value from an async option object.
|
|
71
|
+
* Required for `async` and `async-multiple` components.
|
|
72
|
+
*/
|
|
73
|
+
resolveOptionValue?: (option: TAsyncOption) => string;
|
|
74
|
+
/**
|
|
75
|
+
* Custom render function for the selected value chip/label.
|
|
76
|
+
* Required for `async` and `async-multiple` components.
|
|
77
|
+
*/
|
|
78
|
+
renderSelectedValue?: (option: TAsyncOption) => React.ReactNode;
|
|
79
|
+
/**
|
|
80
|
+
* Pre-loaded options used to hydrate the async select on mount,
|
|
81
|
+
* avoiding an initial fetch when the value is already known.
|
|
82
|
+
*/
|
|
83
|
+
initialOptions?: TAsyncOption[];
|
|
84
|
+
/** Custom node displayed when the async fetcher returns no results at all. */
|
|
85
|
+
notFound?: React.ReactNode;
|
|
86
|
+
/** Message shown when the async search query returns no matching results. */
|
|
87
|
+
noResultsMessage?: string;
|
|
88
|
+
/** Debounce delay in milliseconds for the async search input. @default 300 */
|
|
89
|
+
debounce?: number;
|
|
90
|
+
/** Allows the user to clear the selected value in the async select. @default false */
|
|
91
|
+
clearable?: boolean;
|
|
92
|
+
/** Extra props forwarded directly to the `DatePicker` component. */
|
|
93
|
+
datePickerProps?: Partial<DatePickerProps>;
|
|
94
|
+
/** Column span for the item in the grid. @default undefined (auto, or "full" for the last item) */
|
|
95
|
+
colSpan?: "1" | "2" | "3" | "full";
|
|
96
|
+
/** Icon on the left side. Only applies when `component` is `"input"`. */
|
|
97
|
+
iconLeft?: IconName;
|
|
98
|
+
/** Icon on the right side. Only applies when `component` is `"input"`. */
|
|
99
|
+
iconRight?: IconName;
|
|
100
|
+
/** Enables search/filter inside `select` and `multiselect` dropdowns. @default true */
|
|
101
|
+
searchable?: boolean;
|
|
102
|
+
/** Hides the label above the field. @default false */
|
|
103
|
+
hideLabel?: boolean;
|
|
104
|
+
/** Additional CSS class name applied to the item container div. */
|
|
105
|
+
className?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Additional props forwarded to the underlying UI component.
|
|
108
|
+
* Strongly typed based on the chosen `component` value.
|
|
109
|
+
*/
|
|
110
|
+
componentProps?: AppFormItemComponentProps[TComponent];
|
|
111
|
+
/**
|
|
112
|
+
* Custom render function for the component.
|
|
113
|
+
* Required when `component` is `"custom"`.
|
|
114
|
+
*/
|
|
115
|
+
render?: (props: {
|
|
116
|
+
field: ControllerRenderProps<FieldValues, string>;
|
|
117
|
+
error?: string;
|
|
118
|
+
label: React.ReactNode;
|
|
119
|
+
}) => React.ReactNode;
|
|
120
|
+
};
|
|
50
121
|
```
|
|
51
122
|
|
|
52
123
|
### Submit Button Inside vs Outside
|
|
@@ -103,12 +174,12 @@ export function SubmitInsideVsOutside() {
|
|
|
103
174
|
|
|
104
175
|
| Prop | Type | Default | Description |
|
|
105
176
|
| ------------------ | --------------------- | ------------ | -------------------------------------------------------- |
|
|
106
|
-
| `items` | `AppFormItem[]` | **required** | Array of
|
|
107
|
-
| `form` | `UseFormReturn<any>` | **required** | React Hook Form instance
|
|
177
|
+
| `items` | `AppFormItem[]` | **required** | Array of field configurations |
|
|
178
|
+
| `form` | `UseFormReturn<any>` | **required** | React Hook Form instance returned by `useForm` |
|
|
108
179
|
| `cols` | `"1" \| "2" \| "3"` | `"2"` | Number of grid columns |
|
|
109
|
-
| `submitText` | `string` | `"Invia"` | Text for submit button
|
|
110
|
-
| `onSubmit` | `(data: any) => void` | `undefined` |
|
|
111
|
-
| `isSubmitting` | `boolean` | `false` | Shows loading
|
|
180
|
+
| `submitText` | `string` | `"Invia"` | Text label for the internal submit button |
|
|
181
|
+
| `onSubmit` | `(data: any) => void` | `undefined` | Callback fired with validated form data on submission |
|
|
182
|
+
| `isSubmitting` | `boolean` | `false` | Shows loading spinner on the submit button |
|
|
112
183
|
| `showSubmitButton` | `boolean` | `false` | Renders an internal submit button at the end of the form |
|
|
113
184
|
|
|
114
185
|
---
|
|
@@ -117,9 +188,9 @@ export function SubmitInsideVsOutside() {
|
|
|
117
188
|
|
|
118
189
|
- **React Hook Form Integration**: Uses `Controller` from React Hook Form for each field
|
|
119
190
|
- **Validation Display**: Shows validation errors inline with each field
|
|
120
|
-
- **Grid Layout**: Automatically arranges fields in a responsive grid based on `cols` prop
|
|
191
|
+
- **Grid Layout**: Automatically arranges fields in a responsive grid based on `cols` prop. Use `colSpan` on items for fine-grained control.
|
|
121
192
|
- **Submit Button**: Rendered only when `showSubmitButton` is `true`. When shown, it is disabled when the form is invalid or pristine. Otherwise, manage submit externally with `form.handleSubmit(...)`.
|
|
122
|
-
- **Last Field Spanning**: The last field automatically spans full width
|
|
193
|
+
- **Last Field Spanning**: The last field automatically spans full width unless `colSpan` is explicitly set.
|
|
123
194
|
- **Error Highlighting**: Fields with errors get red border styling
|
|
124
195
|
|
|
125
196
|
---
|
|
@@ -128,360 +199,102 @@ export function SubmitInsideVsOutside() {
|
|
|
128
199
|
|
|
129
200
|
### input
|
|
130
201
|
|
|
131
|
-
Standard text input field
|
|
132
|
-
|
|
133
|
-
Standard text input field. When `component: "input"`, you can use the `inputType` property to control the underlying HTML input type (e.g. `"text"`, `"email"`, `"password"`, `"number"`, `"url"`).
|
|
134
|
-
|
|
135
|
-
For a complete showcase of different input types, see the Storybook story `UI/AppForm/DifferentInputTypes`.
|
|
202
|
+
Standard text input field. Supports `iconLeft` and `iconRight`.
|
|
136
203
|
|
|
137
|
-
|
|
204
|
+
When `component: "input"`, use the `inputType` property to control the underlying HTML input type (e.g. `"text"`, `"email"`, `"password"`, `"number"`, `"url"`).
|
|
138
205
|
|
|
139
|
-
|
|
206
|
+
### select / multiselect
|
|
140
207
|
|
|
141
|
-
|
|
208
|
+
Single or multiple selection dropdown using `AppSelect`. Supports `searchable: true`.
|
|
142
209
|
|
|
143
|
-
|
|
210
|
+
### custom
|
|
144
211
|
|
|
145
|
-
|
|
212
|
+
Allows rendering any arbitrary content within the form grid. Requires the `render` function.
|
|
146
213
|
|
|
147
|
-
|
|
214
|
+
```tsx
|
|
215
|
+
{
|
|
216
|
+
label: "Custom Section",
|
|
217
|
+
component: "custom",
|
|
218
|
+
name: "customInfo",
|
|
219
|
+
render: ({ field, error, label }) => (
|
|
220
|
+
<div className="p-4 border rounded">
|
|
221
|
+
{label}
|
|
222
|
+
<input {...field} className="border p-2" />
|
|
223
|
+
{error && <span className="text-red-500">{error}</span>}
|
|
224
|
+
</div>
|
|
225
|
+
),
|
|
226
|
+
colSpan: "full"
|
|
227
|
+
}
|
|
228
|
+
```
|
|
148
229
|
|
|
149
230
|
### async / async-multiple
|
|
150
231
|
|
|
151
|
-
Use `AsyncSelect` for server-side driven selects. `async`
|
|
152
|
-
|
|
153
|
-
- `fetcher`: funzione che restituisce `Promise<Option[]>`
|
|
154
|
-
- `renderOptionItem`, `resolveOptionValue`, `renderSelectedValue`: per gestire il rendering e la selezione
|
|
155
|
-
- `initialOptions` (opzionale ma consigliata) per idratare i valori preimpostati
|
|
156
|
-
- `defaultValue` va impostato nei `defaultValues` di React Hook Form
|
|
232
|
+
Use `AsyncSelect` for server-side driven selects. `async` handles a single string value, `async-multiple` an array of strings.
|
|
157
233
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```tsx
|
|
161
|
-
const items: AppFormItem[] = [
|
|
162
|
-
{
|
|
163
|
-
component: "async",
|
|
164
|
-
name: "business",
|
|
165
|
-
label: "Business (async)",
|
|
166
|
-
placeholder: "Seleziona un business",
|
|
167
|
-
fetcher: mockAsyncSelectFetcher,
|
|
168
|
-
initialOptions: asyncSelectMockUsers,
|
|
169
|
-
renderOptionItem: (user) => (
|
|
170
|
-
<div>
|
|
171
|
-
<strong>{user.name}</strong>
|
|
172
|
-
<span className="text-muted-foreground text-xs">{user.email}</span>
|
|
173
|
-
</div>
|
|
174
|
-
),
|
|
175
|
-
resolveOptionValue: (user) => user.id,
|
|
176
|
-
renderSelectedValue: (user) => user.name,
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
component: "async-multiple",
|
|
180
|
-
name: "team",
|
|
181
|
-
label: "Team (async)",
|
|
182
|
-
placeholder: "Seleziona i membri",
|
|
183
|
-
fetcher: mockAsyncSelectFetcher,
|
|
184
|
-
initialOptions: asyncSelectMockUsers,
|
|
185
|
-
renderOptionItem: (user) => user.name,
|
|
186
|
-
resolveOptionValue: (user) => user.id,
|
|
187
|
-
renderSelectedValue: (user) => user.name,
|
|
188
|
-
},
|
|
189
|
-
];
|
|
234
|
+
Required props for both: `fetcher`, `renderOptionItem`, `resolveOptionValue`, `renderSelectedValue`.
|
|
190
235
|
|
|
191
|
-
|
|
192
|
-
defaultValues: {
|
|
193
|
-
business: asyncSelectMockUsers[0]?.id ?? "",
|
|
194
|
-
team: asyncSelectMockUsers.slice(0, 2).map((u) => u.id),
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
```
|
|
236
|
+
### datepicker
|
|
198
237
|
|
|
199
|
-
|
|
238
|
+
Date picker component with optional range selection via `calendarRange`. Pass `datePickerProps` for locale, format, or other `DatePicker` customisation.
|
|
200
239
|
|
|
201
|
-
###
|
|
240
|
+
### radio / checkbox / switch / slider
|
|
202
241
|
|
|
203
|
-
|
|
242
|
+
Standard form components for various input types.
|
|
204
243
|
|
|
205
|
-
|
|
244
|
+
---
|
|
206
245
|
|
|
207
|
-
|
|
208
|
-
- `dateFormat`: Date format string (e.g., `"MM/dd/yyyy"`, `"dd/MM/yyyy"`)
|
|
209
|
-
- `numberOfMonths`: Number of months to display in the calendar
|
|
210
|
-
- `minDate`: Minimum selectable date
|
|
211
|
-
- `maxDate`: Maximum selectable date
|
|
212
|
-
- `firstDate`: First available date (disables dates before)
|
|
213
|
-
- `lastDate`: Last available date (disables dates after)
|
|
214
|
-
- `availableDates`: Array of specific dates that are selectable
|
|
215
|
-
- `showTime`: Show time picker columns (HH, MM)
|
|
216
|
-
- `withSeconds`: Show seconds column in the time picker (requires `showTime`)
|
|
217
|
-
- `minuteStep`: Minute step interval for the time picker
|
|
218
|
-
- `secondStep`: Second step interval for the time picker
|
|
219
|
-
- And other DatePicker props
|
|
246
|
+
## Examples
|
|
220
247
|
|
|
221
|
-
|
|
248
|
+
### Grid and Icons Example
|
|
222
249
|
|
|
223
250
|
```tsx
|
|
224
|
-
import { enUS } from "date-fns/locale";
|
|
225
|
-
|
|
226
251
|
const items: AppFormItem[] = [
|
|
227
252
|
{
|
|
228
|
-
label: "
|
|
229
|
-
component: "
|
|
230
|
-
name: "
|
|
231
|
-
|
|
232
|
-
datePickerProps: {
|
|
233
|
-
locale: enUS,
|
|
234
|
-
dateFormat: "MM/dd/yyyy HH:mm",
|
|
235
|
-
showTime: true,
|
|
236
|
-
},
|
|
253
|
+
label: "First Name",
|
|
254
|
+
component: "input",
|
|
255
|
+
name: "firstName",
|
|
256
|
+
colSpan: "1",
|
|
237
257
|
},
|
|
238
258
|
{
|
|
239
|
-
label: "
|
|
240
|
-
component: "
|
|
241
|
-
name: "
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
259
|
+
label: "Last Name",
|
|
260
|
+
component: "input",
|
|
261
|
+
name: "lastName",
|
|
262
|
+
colSpan: "1",
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
label: "Email",
|
|
266
|
+
component: "input",
|
|
267
|
+
name: "email",
|
|
268
|
+
iconLeft: "Mail",
|
|
269
|
+
colSpan: "full",
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
label: "Department",
|
|
273
|
+
component: "select",
|
|
274
|
+
name: "dept",
|
|
275
|
+
options: [
|
|
276
|
+
/* ... */
|
|
277
|
+
],
|
|
278
|
+
colSpan: "full",
|
|
249
279
|
},
|
|
250
280
|
];
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### radio
|
|
254
|
-
|
|
255
|
-
Radio button group with options
|
|
256
|
-
|
|
257
|
-
### checkbox
|
|
258
|
-
|
|
259
|
-
Single checkbox with label
|
|
260
|
-
|
|
261
|
-
### switch
|
|
262
|
-
|
|
263
|
-
Toggle switch with label and optional caption
|
|
264
|
-
|
|
265
|
-
### slider
|
|
266
|
-
|
|
267
|
-
Range slider with min/max/step configuration
|
|
268
|
-
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
## Examples
|
|
272
|
-
|
|
273
|
-
### Basic Form
|
|
274
|
-
|
|
275
|
-
```tsx
|
|
276
|
-
import { AppForm } from "laif-ds";
|
|
277
|
-
import { useForm } from "react-hook-form";
|
|
278
|
-
|
|
279
|
-
export function BasicForm() {
|
|
280
|
-
const form = useForm();
|
|
281
281
|
|
|
282
|
-
|
|
283
|
-
<AppForm
|
|
284
|
-
form={form}
|
|
285
|
-
items={[
|
|
286
|
-
{
|
|
287
|
-
label: "Name",
|
|
288
|
-
component: "input",
|
|
289
|
-
name: "name",
|
|
290
|
-
placeholder: "Enter your name",
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
label: "Email",
|
|
294
|
-
component: "input",
|
|
295
|
-
name: "email",
|
|
296
|
-
inputType: "email",
|
|
297
|
-
placeholder: "Enter your email",
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
label: "Message",
|
|
301
|
-
component: "textarea",
|
|
302
|
-
name: "message",
|
|
303
|
-
placeholder: "Enter your message",
|
|
304
|
-
},
|
|
305
|
-
]}
|
|
306
|
-
onSubmit={(data) => console.log(data)}
|
|
307
|
-
/>
|
|
308
|
-
);
|
|
309
|
-
}
|
|
282
|
+
return <AppForm form={form} items={items} cols="2" showSubmitButton />;
|
|
310
283
|
```
|
|
311
284
|
|
|
312
|
-
###
|
|
313
|
-
|
|
314
|
-
```tsx
|
|
315
|
-
import { AppForm } from "laif-ds";
|
|
316
|
-
import { useForm } from "react-hook-form";
|
|
317
|
-
import { zodResolver } from "@hookform/resolvers/zod";
|
|
318
|
-
import { z } from "zod";
|
|
319
|
-
|
|
320
|
-
const schema = z.object({
|
|
321
|
-
name: z.string().min(1, "Name is required"),
|
|
322
|
-
category: z.string(),
|
|
323
|
-
isActive: z.boolean(),
|
|
324
|
-
priority: z.number(),
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
export function FullFeatureForm() {
|
|
328
|
-
const form = useForm({
|
|
329
|
-
resolver: zodResolver(schema),
|
|
330
|
-
defaultValues: {
|
|
331
|
-
name: "",
|
|
332
|
-
category: "",
|
|
333
|
-
isActive: false,
|
|
334
|
-
priority: 5,
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
return (
|
|
339
|
-
<AppForm
|
|
340
|
-
form={form}
|
|
341
|
-
cols="2"
|
|
342
|
-
items={[
|
|
343
|
-
{
|
|
344
|
-
label: "Name",
|
|
345
|
-
component: "input",
|
|
346
|
-
name: "name",
|
|
347
|
-
placeholder: "Enter name",
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
label: "Category",
|
|
351
|
-
component: "select",
|
|
352
|
-
name: "category",
|
|
353
|
-
options: [
|
|
354
|
-
{ value: "tech", label: "Technology" },
|
|
355
|
-
{ value: "design", label: "Design" },
|
|
356
|
-
{ value: "marketing", label: "Marketing" },
|
|
357
|
-
],
|
|
358
|
-
},
|
|
359
|
-
{
|
|
360
|
-
label: "Active",
|
|
361
|
-
component: "switch",
|
|
362
|
-
name: "isActive",
|
|
363
|
-
caption: "Enable this option",
|
|
364
|
-
},
|
|
365
|
-
{
|
|
366
|
-
label: "Priority",
|
|
367
|
-
component: "slider",
|
|
368
|
-
name: "priority",
|
|
369
|
-
min: 1,
|
|
370
|
-
max: 10,
|
|
371
|
-
step: 1,
|
|
372
|
-
},
|
|
373
|
-
]}
|
|
374
|
-
submitText="Save"
|
|
375
|
-
onSubmit={(data) => console.log(data)}
|
|
376
|
-
/>
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
```
|
|
285
|
+
### Advanced componentProps
|
|
380
286
|
|
|
381
|
-
|
|
287
|
+
Use `componentProps` to pass specific properties to the underlying UI components that are not exposed directly in `AppFormItem`.
|
|
382
288
|
|
|
383
289
|
```tsx
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return (
|
|
394
|
-
<AppForm
|
|
395
|
-
form={form}
|
|
396
|
-
items={[
|
|
397
|
-
{
|
|
398
|
-
label: "Date Range",
|
|
399
|
-
component: "datepicker",
|
|
400
|
-
name: "dateRange",
|
|
401
|
-
calendarRange: [startDate, endDate],
|
|
402
|
-
},
|
|
403
|
-
]}
|
|
404
|
-
onSubmit={(data) => console.log(data)}
|
|
405
|
-
/>
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### External Form Control
|
|
411
|
-
|
|
412
|
-
You can access the form instance to programmatically control values, watch changes, and reset the form:
|
|
413
|
-
|
|
414
|
-
```tsx
|
|
415
|
-
import { AppForm, Button } from "laif-ds";
|
|
416
|
-
import { useForm } from "react-hook-form";
|
|
417
|
-
import { useState, useEffect } from "react";
|
|
418
|
-
|
|
419
|
-
export function ExternalControlForm() {
|
|
420
|
-
const [formValues, setFormValues] = useState({});
|
|
421
|
-
const [watchedValues, setWatchedValues] = useState({});
|
|
422
|
-
|
|
423
|
-
const form = useForm({
|
|
424
|
-
defaultValues: {
|
|
425
|
-
name: "",
|
|
426
|
-
email: "",
|
|
427
|
-
},
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
const { watch, setValue, reset } = form;
|
|
431
|
-
|
|
432
|
-
// Watch specific fields
|
|
433
|
-
const nameValue = watch("name");
|
|
434
|
-
const emailValue = watch("email");
|
|
435
|
-
|
|
436
|
-
// Auto-fill handler
|
|
437
|
-
const handleAutoFill = () => {
|
|
438
|
-
setValue("name", "Mario Rossi");
|
|
439
|
-
setValue("email", "mario@example.com");
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
// Reset handler
|
|
443
|
-
const handleReset = () => {
|
|
444
|
-
reset();
|
|
445
|
-
setFormValues({});
|
|
446
|
-
setWatchedValues({});
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
// Watch all form values
|
|
450
|
-
useEffect(() => {
|
|
451
|
-
const subscription = watch((values) => {
|
|
452
|
-
setWatchedValues(values);
|
|
453
|
-
});
|
|
454
|
-
return () => subscription.unsubscribe();
|
|
455
|
-
}, [watch]);
|
|
456
|
-
|
|
457
|
-
return (
|
|
458
|
-
<div>
|
|
459
|
-
<div className="mb-4 flex gap-2">
|
|
460
|
-
<Button type="button" variant="outline" onClick={handleAutoFill}>
|
|
461
|
-
Auto-fill
|
|
462
|
-
</Button>
|
|
463
|
-
<Button type="button" variant="outline" onClick={handleReset}>
|
|
464
|
-
Reset
|
|
465
|
-
</Button>
|
|
466
|
-
</div>
|
|
467
|
-
|
|
468
|
-
<AppForm
|
|
469
|
-
form={form}
|
|
470
|
-
items={[
|
|
471
|
-
{ label: "Name", component: "input", name: "name" },
|
|
472
|
-
{ label: "Email", component: "input", name: "email" },
|
|
473
|
-
]}
|
|
474
|
-
onSubmit={(data) => setFormValues(data)}
|
|
475
|
-
showSubmitButton
|
|
476
|
-
/>
|
|
477
|
-
|
|
478
|
-
<div className="mt-4">
|
|
479
|
-
<p>Name: {nameValue || "(empty)"}</p>
|
|
480
|
-
<p>Email: {emailValue || "(empty)"}</p>
|
|
481
|
-
<pre>{JSON.stringify(watchedValues, null, 2)}</pre>
|
|
482
|
-
</div>
|
|
483
|
-
</div>
|
|
484
|
-
);
|
|
290
|
+
{
|
|
291
|
+
label: "Bio",
|
|
292
|
+
component: "textarea",
|
|
293
|
+
name: "bio",
|
|
294
|
+
componentProps: {
|
|
295
|
+
rows: 10,
|
|
296
|
+
className: "resize-none"
|
|
297
|
+
}
|
|
485
298
|
}
|
|
486
299
|
```
|
|
487
300
|
|
|
@@ -490,7 +303,5 @@ export function ExternalControlForm() {
|
|
|
490
303
|
## Notes
|
|
491
304
|
|
|
492
305
|
- **React Hook Form Required**: This component requires React Hook Form to be installed and configured
|
|
493
|
-
- **Validation**: Use React Hook Form's resolver (e.g., Zod, Yup) for validation
|
|
494
306
|
- **Grid Layout**: The grid uses Tailwind's grid system with `grid-cols-{n}` classes
|
|
495
|
-
- **
|
|
496
|
-
- **Error Display**: Errors appear inline above each field and as border highlighting
|
|
307
|
+
- **Type Safety**: `componentProps` is strictly typed based on the `component` chosen.
|
|
@@ -32,6 +32,7 @@ Powerful table built on TanStack Table v8. Supports client-side and server-side
|
|
|
32
32
|
| `disableAutoPageSize` | `boolean` | `false` | Disable auto pageSize (still updates pageIndex). |
|
|
33
33
|
| `id` | `string` | `undefined` | Test/accessibility hook for the root element. |
|
|
34
34
|
| `data-testid` | `string` | `undefined` | Test identifier forwarded to the root element. |
|
|
35
|
+
| `rowClassName` | `string \| ((row) => string)` | `undefined` | Add custom CSS classes to table rows based on row data or state. |
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
@@ -56,6 +57,8 @@ type ColumnMeta = {
|
|
|
56
57
|
searchable?: boolean;
|
|
57
58
|
pinned?: "left" | "right";
|
|
58
59
|
listOptions?: { value: string; label: string }[];
|
|
60
|
+
cellClassName?: string | ((value: any, row: TData) => string);
|
|
61
|
+
headerClassName?: string;
|
|
59
62
|
};
|
|
60
63
|
```
|
|
61
64
|
|
|
@@ -20,7 +20,7 @@ Drag-and-drop uploader with keyboard activation, file type filtering, limits (co
|
|
|
20
20
|
| `maxTotalSize` | `number` (bytes) | `undefined` | Maximum total size of selected files. |
|
|
21
21
|
| `maxFiles` | `number` | `undefined` | Maximum number of files (when `multiple` is true). |
|
|
22
22
|
|
|
23
|
-
`AcceptItem` includes: `pdf | doc | docx | xls | xlsx | ppt | pptx | txt | csv | jpg | jpeg | png | gif | image | video | audio`.
|
|
23
|
+
`AcceptItem` includes: `pdf | doc | docx | xls | xlsx | ppt | pptx | txt | csv | jpg | jpeg | png | gif | image | video | audio | zip | rar | 7z | tar | gz | tgz`.
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
@@ -68,6 +68,12 @@ const exts: AcceptItem[] = [
|
|
|
68
68
|
"image",
|
|
69
69
|
"video",
|
|
70
70
|
"audio",
|
|
71
|
+
"zip",
|
|
72
|
+
"rar",
|
|
73
|
+
"7z",
|
|
74
|
+
"tar",
|
|
75
|
+
"gz",
|
|
76
|
+
"tgz",
|
|
71
77
|
];
|
|
72
78
|
|
|
73
79
|
export function MultiUploader() {
|
|
@@ -46,6 +46,7 @@ This document provides a complete mapping of all components available in the lai
|
|
|
46
46
|
### Layout & Structure Components
|
|
47
47
|
|
|
48
48
|
- **Accordion** - Collapsible content panels for organizing information hierarchically
|
|
49
|
+
- **AppCard** - Enhanced card component with variant styles, semantic states, size control, and loading skeleton support
|
|
49
50
|
- **AppSidebar** - Application sidebar navigation component
|
|
50
51
|
- **AppStepper** - Step-by-step progress indicator for multi-step processes
|
|
51
52
|
- **AspectRatio** - Container that maintains a specific aspect ratio for responsive layouts
|
|
@@ -85,6 +86,7 @@ This document provides a complete mapping of all components available in the lai
|
|
|
85
86
|
- **Pagination** - Page navigation component for paginated content
|
|
86
87
|
- **Table** - Basic table component with styling
|
|
87
88
|
- **TableSkeleton** - Loading skeleton for table components
|
|
89
|
+
- **TruncatedCell** - Text display component with automatic truncation detection and popover preview
|
|
88
90
|
- **Typo** - Typography component for consistent text styling
|
|
89
91
|
|
|
90
92
|
### Content & Media Components
|