laif-ds 0.2.46 → 0.2.48
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/_virtual/index6.js +2 -2
- package/dist/_virtual/index7.js +2 -2
- package/dist/agent-docs/components/AppForm.md +88 -10
- package/dist/agent-docs/components/AsyncSelect.md +94 -103
- package/dist/components/kanban.js +540 -0
- package/dist/components/ui/app-form.js +105 -72
- package/dist/components/ui/app-kanban.js +137 -0
- package/dist/components/ui/app-select.js +100 -87
- package/dist/components/ui/async-select.js +264 -278
- package/dist/index.d.ts +83 -29
- package/dist/index.js +77 -75
- package/dist/node_modules/@radix-ui/react-alert-dialog/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot/dist/index.js +12 -0
- package/dist/node_modules/@radix-ui/react-collection/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
- package/dist/node_modules/@radix-ui/react-dialog/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
- package/dist/node_modules/@radix-ui/react-menu/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
- package/dist/node_modules/@radix-ui/react-popover/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
- package/dist/node_modules/@radix-ui/react-primitive/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
- package/dist/node_modules/@radix-ui/react-select/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
- package/dist/node_modules/@radix-ui/react-slot/dist/index.js +47 -44
- package/dist/node_modules/@radix-ui/react-tooltip/dist/index.js +1 -1
- package/dist/node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot/dist/index.js +12 -0
- package/dist/node_modules/eventemitter3/index2.js +1 -1
- package/dist/node_modules/style-to-object/cjs/index.js +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +536 -502
- package/dist/styles.css +1 -1
- package/dist/styles.v3.css +1 -1
- package/package.json +4 -4
package/dist/_virtual/index6.js
CHANGED
package/dist/_virtual/index7.js
CHANGED
|
@@ -22,8 +22,11 @@ export interface AppFormItem {
|
|
|
22
22
|
| "datepicker"
|
|
23
23
|
| "radio"
|
|
24
24
|
| "switch"
|
|
25
|
-
| "slider"
|
|
25
|
+
| "slider"
|
|
26
|
+
| "async"
|
|
27
|
+
| "async-multiple"; // Field type
|
|
26
28
|
name: string; // Field name (used for form state and validation)
|
|
29
|
+
inputType?: string; // HTML input type for "input" component (e.g. "text", "email", "password", "number")
|
|
27
30
|
defaultValue?: string | boolean | number | string[] | Date | number[]; // Initial value
|
|
28
31
|
options?: AppSelectOption[]; // Options for select/multiselect/radio
|
|
29
32
|
disabled?: boolean; // Disables the field
|
|
@@ -33,6 +36,15 @@ export interface AppFormItem {
|
|
|
33
36
|
min?: number; // Minimum value for slider
|
|
34
37
|
max?: number; // Maximum value for slider
|
|
35
38
|
step?: number; // Step value for slider
|
|
39
|
+
fetcher?: (query?: string) => Promise<any[]>; // Async select data loader
|
|
40
|
+
renderOptionItem?: (option: any) => React.ReactNode; // Customize render of async option
|
|
41
|
+
resolveOptionValue?: (option: any) => string; // Value extractor for async option
|
|
42
|
+
renderSelectedValue?: (option: any) => React.ReactNode; // Customize render of selected async option
|
|
43
|
+
initialOptions?: any[]; // Optional cache for async select hydration
|
|
44
|
+
notFound?: React.ReactNode;
|
|
45
|
+
noResultsMessage?: string;
|
|
46
|
+
debounce?: number;
|
|
47
|
+
clearable?: boolean;
|
|
36
48
|
}
|
|
37
49
|
```
|
|
38
50
|
|
|
@@ -88,15 +100,15 @@ export function SubmitInsideVsOutside() {
|
|
|
88
100
|
|
|
89
101
|
## Props
|
|
90
102
|
|
|
91
|
-
| Prop
|
|
92
|
-
|
|
|
93
|
-
| `items`
|
|
94
|
-
| `form`
|
|
95
|
-
| `cols`
|
|
96
|
-
| `submitText`
|
|
97
|
-
| `onSubmit`
|
|
98
|
-
| `isSubmitting`
|
|
99
|
-
| `showSubmitButton` | `boolean`
|
|
103
|
+
| Prop | Type | Default | Description |
|
|
104
|
+
| ------------------ | --------------------- | ------------ | -------------------------------------------------------- |
|
|
105
|
+
| `items` | `AppFormItem[]` | **required** | Array of form field configurations |
|
|
106
|
+
| `form` | `UseFormReturn<any>` | **required** | React Hook Form instance |
|
|
107
|
+
| `cols` | `"1" \| "2" \| "3"` | `"2"` | Number of grid columns |
|
|
108
|
+
| `submitText` | `string` | `"Invia"` | Text for submit button |
|
|
109
|
+
| `onSubmit` | `(data: any) => void` | `undefined` | Form submission callback |
|
|
110
|
+
| `isSubmitting` | `boolean` | `false` | Shows loading state on submit button |
|
|
111
|
+
| `showSubmitButton` | `boolean` | `false` | Renders an internal submit button at the end of the form |
|
|
100
112
|
|
|
101
113
|
---
|
|
102
114
|
|
|
@@ -114,30 +126,95 @@ export function SubmitInsideVsOutside() {
|
|
|
114
126
|
## Field Types
|
|
115
127
|
|
|
116
128
|
### input
|
|
129
|
+
|
|
117
130
|
Standard text input field
|
|
118
131
|
|
|
132
|
+
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"`).
|
|
133
|
+
|
|
134
|
+
For a complete showcase of different input types, see the Storybook story `UI/AppForm/DifferentInputTypes`.
|
|
135
|
+
|
|
119
136
|
### textarea
|
|
137
|
+
|
|
120
138
|
Multi-line text area
|
|
121
139
|
|
|
122
140
|
### select
|
|
141
|
+
|
|
123
142
|
Single selection dropdown using AppSelect
|
|
124
143
|
|
|
125
144
|
### multiselect
|
|
145
|
+
|
|
126
146
|
Multiple selection dropdown using AppSelect with `multiple` prop
|
|
127
147
|
|
|
148
|
+
### async / async-multiple
|
|
149
|
+
|
|
150
|
+
Use `AsyncSelect` for server-side driven selects. `async` gestisce un valore singolo, `async-multiple` un array di stringhe. Richiede i seguenti prop sull'item:
|
|
151
|
+
|
|
152
|
+
- `fetcher`: funzione che restituisce `Promise<Option[]>`
|
|
153
|
+
- `renderOptionItem`, `resolveOptionValue`, `renderSelectedValue`: per gestire il rendering e la selezione
|
|
154
|
+
- `initialOptions` (opzionale ma consigliata) per idratare i valori preimpostati
|
|
155
|
+
- `defaultValue` va impostato nei `defaultValues` di React Hook Form
|
|
156
|
+
|
|
157
|
+
Esempio:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
const items: AppFormItem[] = [
|
|
161
|
+
{
|
|
162
|
+
component: "async",
|
|
163
|
+
name: "business",
|
|
164
|
+
label: "Business (async)",
|
|
165
|
+
placeholder: "Seleziona un business",
|
|
166
|
+
fetcher: mockAsyncSelectFetcher,
|
|
167
|
+
initialOptions: asyncSelectMockUsers,
|
|
168
|
+
renderOptionItem: (user) => (
|
|
169
|
+
<div>
|
|
170
|
+
<strong>{user.name}</strong>
|
|
171
|
+
<span className="text-muted-foreground text-xs">{user.email}</span>
|
|
172
|
+
</div>
|
|
173
|
+
),
|
|
174
|
+
resolveOptionValue: (user) => user.id,
|
|
175
|
+
renderSelectedValue: (user) => user.name,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
component: "async-multiple",
|
|
179
|
+
name: "team",
|
|
180
|
+
label: "Team (async)",
|
|
181
|
+
placeholder: "Seleziona i membri",
|
|
182
|
+
fetcher: mockAsyncSelectFetcher,
|
|
183
|
+
initialOptions: asyncSelectMockUsers,
|
|
184
|
+
renderOptionItem: (user) => user.name,
|
|
185
|
+
resolveOptionValue: (user) => user.id,
|
|
186
|
+
renderSelectedValue: (user) => user.name,
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
const form = useForm({
|
|
191
|
+
defaultValues: {
|
|
192
|
+
business: asyncSelectMockUsers[0]?.id ?? "",
|
|
193
|
+
team: asyncSelectMockUsers.slice(0, 2).map((u) => u.id),
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Ricorda che il fetch parte solo quando il menu è aperto; eventuali valori iniziali devono essere già presenti in `initialOptions`.
|
|
199
|
+
|
|
128
200
|
### datepicker
|
|
201
|
+
|
|
129
202
|
Date picker component with optional range selection via `calendarRange`
|
|
130
203
|
|
|
131
204
|
### radio
|
|
205
|
+
|
|
132
206
|
Radio button group with options
|
|
133
207
|
|
|
134
208
|
### checkbox
|
|
209
|
+
|
|
135
210
|
Single checkbox with label
|
|
136
211
|
|
|
137
212
|
### switch
|
|
213
|
+
|
|
138
214
|
Toggle switch with label and optional caption
|
|
139
215
|
|
|
140
216
|
### slider
|
|
217
|
+
|
|
141
218
|
Range slider with min/max/step configuration
|
|
142
219
|
|
|
143
220
|
---
|
|
@@ -167,6 +244,7 @@ export function BasicForm() {
|
|
|
167
244
|
label: "Email",
|
|
168
245
|
component: "input",
|
|
169
246
|
name: "email",
|
|
247
|
+
inputType: "email",
|
|
170
248
|
placeholder: "Enter your email",
|
|
171
249
|
},
|
|
172
250
|
{
|
|
@@ -1,102 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| `
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
| `
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Multiple with Steps
|
|
88
|
-
|
|
89
|
-
```tsx
|
|
90
|
-
import * as React from "react";
|
|
91
|
-
import { AsyncSelect } from "laif-ds";
|
|
92
|
-
|
|
1
|
+
# AsyncSelect
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Generic async select with search input, popover list, server-side filtering, and optional multiple selection. Fully render-prop driven for option content and value extraction.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --------------------- | ------------------------------------- | ------------- | ----------------------------------------------------------------------------------- |
|
|
13
|
+
| `fetcher` | `(query?: string) => Promise<T[]>` | **required** | Async loader for options. Called on open and on search. |
|
|
14
|
+
| `renderOptionItem` | `(option: T) => React.ReactNode` | **required** | Custom renderer for each menu row. |
|
|
15
|
+
| `resolveOptionValue` | `(option: T) => string` | **required** | Returns the unique ID stored in `value`. |
|
|
16
|
+
| `renderSelectedValue` | `(option: T) => React.ReactNode` | **required** | Content shown in the trigger when selected. |
|
|
17
|
+
| `multiple` | `boolean` | `false` | Enables multi-selection and switches `value` to `string[]`. |
|
|
18
|
+
| `value` | `string \| string[] \| undefined` | `undefined` | Controlled value. |
|
|
19
|
+
| `onChange` | `(value: string \| string[]) => void` | `undefined` | Emits the next value when the selection changes. |
|
|
20
|
+
| `label` | `string \| React.ReactNode` | `undefined` | Optional label rendered above the trigger. |
|
|
21
|
+
| `placeholder` | `string` | `"Select..."` | Placeholder when no value is selected. |
|
|
22
|
+
| `disabled` | `boolean` | `false` | Disables trigger and input interactions. |
|
|
23
|
+
| `className` | `string` | `undefined` | Extra classes for the trigger button. |
|
|
24
|
+
| `wrpClassName` | `string` | `undefined` | Classes applied to the outer wrapper (use this to control width, e.g. `w-[200px]`). |
|
|
25
|
+
| `noResultsMessage` | `string` | `undefined` | Message shown inside the default empty state. |
|
|
26
|
+
| `clearable` | `boolean` | `true` | Shows the clear icon when a value is present. |
|
|
27
|
+
| `size` | `"sm" \| "default" \| "lg"` | `"default"` | Trigger size variant. |
|
|
28
|
+
| `notFound` | `React.ReactNode` | `undefined` | Custom fallback when there are no options. |
|
|
29
|
+
| `initialOptions` | `T[]` | `undefined` | Prefills cache/selection with a known options list. |
|
|
30
|
+
| `debounce` | `number` | `300` | Debounce delay (ms) before calling `fetcher`. |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Behavior
|
|
35
|
+
|
|
36
|
+
- **Search**: Debounced input (300ms) that always hits the provided `fetcher`.
|
|
37
|
+
- **Caching**: Results cached by query; reused when re-typing.
|
|
38
|
+
- **Multiple**: Renders selected count or first label; supports checkbox UI per item.
|
|
39
|
+
- **Clear**: Built-in clear icon (uses DS `Icon`), respects `clearable`.
|
|
40
|
+
- **A11y**: Trigger focus ring and keyboard navigation via `cmdk`.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Examples
|
|
45
|
+
|
|
46
|
+
### Multiple with Steps
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import * as React from "react";
|
|
50
|
+
import { AsyncSelect } from "laif-ds";
|
|
51
|
+
|
|
52
|
+
type Tag = { id: string; label: string };
|
|
53
|
+
const tags: Tag[] = [
|
|
54
|
+
{ id: "react", label: "React" },
|
|
55
|
+
{ id: "nextjs", label: "Next.js" },
|
|
56
|
+
{ id: "tailwind", label: "Tailwind" },
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
export function MultipleTags() {
|
|
60
|
+
const [value, setValue] = React.useState<string[]>([]);
|
|
61
|
+
const fetcher = async (q?: string) =>
|
|
62
|
+
!q ? tags : tags.filter((t) => t.label.toLowerCase().includes(q!.toLowerCase()));
|
|
63
|
+
return (
|
|
64
|
+
<AsyncSelect<Tag>
|
|
65
|
+
multiple
|
|
66
|
+
fetcher={fetcher}
|
|
67
|
+
value={value}
|
|
68
|
+
onChange={setValue}
|
|
69
|
+
renderOptionItem={(t) => t.label}
|
|
70
|
+
resolveOptionValue={(t) => t.id}
|
|
71
|
+
renderSelectedValue={(t) => t.label}
|
|
72
|
+
placeholder="Select tags..."
|
|
73
|
+
wrpClassName="w-[280px]"
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Notes
|
|
81
|
+
|
|
82
|
+
- **Trigger width**: Use `width="auto"` to match trigger width; or a fixed `number|string`.
|
|
83
|
+
- **Filtering**: Always handled server-side via `fetcher`, with cached responses per query.
|
|
84
|
+
- **Theming**: Uses DS token classes across trigger, list, and states.
|
|
93
85
|
type Tag = { id: string; label: string };
|
|
94
86
|
const tags: Tag[] = [
|
|
95
87
|
{ id: "react", label: "React" },
|
|
96
88
|
{ id: "nextjs", label: "Next.js" },
|
|
97
89
|
{ id: "tailwind", label: "Tailwind" },
|
|
98
90
|
];
|
|
99
|
-
|
|
91
|
+
|
|
100
92
|
export function MultipleTags() {
|
|
101
93
|
const [value, setValue] = React.useState<string[]>([]);
|
|
102
94
|
const fetcher = async (q?: string) =>
|
|
@@ -115,13 +107,12 @@
|
|
|
115
107
|
/>
|
|
116
108
|
);
|
|
117
109
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Notes
|
|
115
|
+
|
|
116
|
+
- **Trigger width**: Use `width="auto"` to match trigger width; or a fixed `number|string`.
|
|
117
|
+
- **Filtering**: Always handled server-side via `fetcher`, with cached responses per query.
|
|
118
|
+
- **Theming**: Uses DS token classes across trigger, list, and states.
|