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.
Files changed (34) hide show
  1. package/dist/_virtual/index6.js +2 -2
  2. package/dist/_virtual/index7.js +2 -2
  3. package/dist/agent-docs/components/AppForm.md +88 -10
  4. package/dist/agent-docs/components/AsyncSelect.md +94 -103
  5. package/dist/components/kanban.js +540 -0
  6. package/dist/components/ui/app-form.js +105 -72
  7. package/dist/components/ui/app-kanban.js +137 -0
  8. package/dist/components/ui/app-select.js +100 -87
  9. package/dist/components/ui/async-select.js +264 -278
  10. package/dist/index.d.ts +83 -29
  11. package/dist/index.js +77 -75
  12. package/dist/node_modules/@radix-ui/react-alert-dialog/dist/index.js +1 -1
  13. package/dist/node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot/dist/index.js +12 -0
  14. package/dist/node_modules/@radix-ui/react-collection/dist/index.js +1 -1
  15. package/dist/node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
  16. package/dist/node_modules/@radix-ui/react-dialog/dist/index.js +1 -1
  17. package/dist/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
  18. package/dist/node_modules/@radix-ui/react-menu/dist/index.js +1 -1
  19. package/dist/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
  20. package/dist/node_modules/@radix-ui/react-popover/dist/index.js +1 -1
  21. package/dist/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
  22. package/dist/node_modules/@radix-ui/react-primitive/dist/index.js +1 -1
  23. package/dist/node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
  24. package/dist/node_modules/@radix-ui/react-select/dist/index.js +1 -1
  25. package/dist/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot/dist/index.js +50 -0
  26. package/dist/node_modules/@radix-ui/react-slot/dist/index.js +47 -44
  27. package/dist/node_modules/@radix-ui/react-tooltip/dist/index.js +1 -1
  28. package/dist/node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot/dist/index.js +12 -0
  29. package/dist/node_modules/eventemitter3/index2.js +1 -1
  30. package/dist/node_modules/style-to-object/cjs/index.js +1 -1
  31. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +536 -502
  32. package/dist/styles.css +1 -1
  33. package/dist/styles.v3.css +1 -1
  34. package/package.json +4 -4
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- var e = {};
2
+ var e = { exports: {} };
3
3
  export {
4
- e as __exports
4
+ e as __module
5
5
  };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- var e = { exports: {} };
2
+ var e = {};
3
3
  export {
4
- e as __module
4
+ e as __exports
5
5
  };
@@ -22,8 +22,11 @@ export interface AppFormItem {
22
22
  | "datepicker"
23
23
  | "radio"
24
24
  | "switch"
25
- | "slider"; // Field type
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 | Type | Default | Description |
92
- | --------------- | -------------------------- | --------- | ---------------------------------------- |
93
- | `items` | `AppFormItem[]` | **required** | Array of form field configurations |
94
- | `form` | `UseFormReturn<any>` | **required** | React Hook Form instance |
95
- | `cols` | `"1" \| "2" \| "3"` | `"2"` | Number of grid columns |
96
- | `submitText` | `string` | `"Invia"` | Text for submit button |
97
- | `onSubmit` | `(data: any) => void` | `undefined` | Form submission callback |
98
- | `isSubmitting` | `boolean` | `false` | Shows loading state on submit button |
99
- | `showSubmitButton` | `boolean` | `false` | Renders an internal submit button at the end of the form |
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
- # AsyncSelect
2
-
3
- ## Overview
4
-
5
- Generic async select with search input, popover list, optional preload and 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
- | `preload` | `boolean` | `false` | Preload all data once; then client-filter using `filterFn`. |
15
- | `filterFn` | `(option: T, query: string) => boolean` | `undefined` | Custom client-side filter when `preload=true`. |
16
- | `renderOption` | `(option: T) => React.ReactNode` | **required**| How to render each option row. |
17
- | `getOptionValue` | `(option: T) => string` | **required**| Extract option id. |
18
- | `getDisplayValue` | `(option: T) => React.ReactNode` | **required**| Display value for trigger. |
19
- | `multiple` | `boolean` | `false` | Enable multi-selection. Controls `value` type. |
20
- | `value` | `string | string[]` | `undefined` | Controlled value. |
21
- | `onChange` | `(value: string | string[]) => void` | `undefined` | Change callback. |
22
- | `label` | `string | React.ReactNode` | `undefined` | Optional label above. |
23
- | `labelClassName` | `string` | `undefined` | Label classes. |
24
- | `placeholder` | `string` | `"Select..."` | Placeholder when empty. |
25
- | `disabled` | `boolean` | `false` | Disable trigger and input. |
26
- | `width` | `string | number | "auto"` | `200px` | Popover width; `auto` matches trigger width. |
27
- | `triggerClassName`| `string` | `undefined` | Extra classes for trigger button. |
28
- | `noResultsMessage`| `string` | `undefined` | Message when list is empty. |
29
- | `clearable` | `boolean` | `true` | Show clear icon when a value is set. |
30
- | `size` | `"sm" | "default" | "lg"` | `"default"` | Trigger size. |
31
- | `loadingSkeleton` | `React.ReactNode` | `undefined` | Custom loading skeleton list. |
32
- | `notFound` | `React.ReactNode` | `undefined` | Custom empty content. |
33
-
34
- ---
35
-
36
- ## Behavior
37
-
38
- - **Search**: Debounced input (0ms when `preload=true`, 300ms otherwise).
39
- - **Caching**: Results cached by query; reused when re-typing.
40
- - **Multiple**: Renders selected count or first label; supports checkbox UI per item.
41
- - **Clear**: Built-in clear icon (uses DS `Icon`), respects `clearable`.
42
- - **A11y**: Trigger focus ring and keyboard navigation via `cmdk`.
43
-
44
- ---
45
-
46
- ## Examples
47
-
48
- ### Preloaded
49
-
50
- ```tsx
51
- import * as React from "react";
52
- import { AsyncSelect } from "laif-ds";
53
-
54
- type User = { id: number; name: string; email: string };
55
-
56
- async function fetchUsers(query?: string): Promise<User[]> {
57
- const res = await fetch("https://jsonplaceholder.typicode.com/users");
58
- const data: User[] = await res.json();
59
- if (!query) return data;
60
- const q = query.toLowerCase();
61
- return data.filter((u) => u.name.toLowerCase().includes(q));
62
- }
63
-
64
- export function PreloadedUsers() {
65
- const [value, setValue] = React.useState("");
66
- return (
67
- <AsyncSelect<User>
68
- preload
69
- fetcher={fetchUsers}
70
- value={value}
71
- onChange={setValue}
72
- renderOption={(u) => (
73
- <div className="truncate">
74
- <div className="font-medium">{u.name}</div>
75
- <div className="text-d-muted-foreground text-xs">{u.email}</div>
76
- </div>
77
- )}
78
- getOptionValue={(u) => String(u.id)}
79
- getDisplayValue={(u) => u.name}
80
- placeholder="Select a user..."
81
- width="300px"
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
- ## Notes
123
-
124
- - **Trigger width**: Use `width="auto"` to match trigger width; or a fixed `number|string`.
125
- - **Filtering**: For big datasets prefer server search (no `preload`); for small datasets prefer `preload` + `filterFn`.
126
- - **Theming**: Uses DS token classes across trigger, list, and states.
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.