laif-ds 0.2.43 → 0.2.45

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 (98) hide show
  1. package/dist/_virtual/index6.js +2 -2
  2. package/dist/_virtual/index7.js +2 -2
  3. package/dist/agent-docs/components/Accordion.md +157 -0
  4. package/dist/agent-docs/components/Alert.md +95 -0
  5. package/dist/agent-docs/components/AlertDialog.md +126 -0
  6. package/dist/agent-docs/components/AppEditor.md +90 -0
  7. package/dist/agent-docs/components/AppForm.md +242 -0
  8. package/dist/agent-docs/components/AppMultipleSelectDropdown.md +38 -0
  9. package/dist/agent-docs/components/AppRadioGroup.md +223 -0
  10. package/dist/agent-docs/components/AppSelect.md +427 -0
  11. package/dist/agent-docs/components/AppSidebar.md +122 -0
  12. package/dist/agent-docs/components/AppStepper.md +77 -0
  13. package/dist/agent-docs/components/AspectRatio.md +87 -0
  14. package/dist/agent-docs/components/AsyncSelect.md +127 -0
  15. package/dist/agent-docs/components/AudioVisualizer.md +41 -0
  16. package/dist/agent-docs/components/Avatar.md +113 -0
  17. package/dist/agent-docs/components/Badge.md +118 -0
  18. package/dist/agent-docs/components/Breadcrumb.md +78 -0
  19. package/dist/agent-docs/components/Button.md +129 -0
  20. package/dist/agent-docs/components/Calendar.md +222 -0
  21. package/dist/agent-docs/components/Card.md +147 -0
  22. package/dist/agent-docs/components/Carousel.md +129 -0
  23. package/dist/agent-docs/components/Chart.md +75 -0
  24. package/dist/agent-docs/components/Chat.md +109 -0
  25. package/dist/agent-docs/components/ChatMessage.md +61 -0
  26. package/dist/agent-docs/components/Checkbox.md +135 -0
  27. package/dist/agent-docs/components/CircularProgress.md +49 -0
  28. package/dist/agent-docs/components/CodeHighlighter.md +31 -0
  29. package/dist/agent-docs/components/Collapsible.md +95 -0
  30. package/dist/agent-docs/components/Command.md +142 -0
  31. package/dist/agent-docs/components/Confirmer.md +175 -0
  32. package/dist/agent-docs/components/ContextMenu.md +191 -0
  33. package/dist/agent-docs/components/CopyButton.md +26 -0
  34. package/dist/agent-docs/components/DataCrossTable.md +94 -0
  35. package/dist/agent-docs/components/DataTable.md +254 -0
  36. package/dist/agent-docs/components/DatePicker.md +109 -0
  37. package/dist/agent-docs/components/Dialog.md +125 -0
  38. package/dist/agent-docs/components/Drawer.md +127 -0
  39. package/dist/agent-docs/components/DropdownMenu.md +57 -0
  40. package/dist/agent-docs/components/FilePreview.md +99 -0
  41. package/dist/agent-docs/components/FilePreviewer.md +139 -0
  42. package/dist/agent-docs/components/FileUploader.md +129 -0
  43. package/dist/agent-docs/components/Form.md +62 -0
  44. package/dist/agent-docs/components/FormComposer.md +137 -0
  45. package/dist/agent-docs/components/GanttChart.md +122 -0
  46. package/dist/agent-docs/components/HoverCard.md +37 -0
  47. package/dist/agent-docs/components/Icon.md +99 -0
  48. package/dist/agent-docs/components/Input.md +138 -0
  49. package/dist/agent-docs/components/InputOtp.md +40 -0
  50. package/dist/agent-docs/components/InputSelector.md +97 -0
  51. package/dist/agent-docs/components/InterruptPrompt.md +32 -0
  52. package/dist/agent-docs/components/Label.md +28 -0
  53. package/dist/agent-docs/components/MarkdownRenderer.md +36 -0
  54. package/dist/agent-docs/components/Menubar.md +164 -0
  55. package/dist/agent-docs/components/MessageInput.md +131 -0
  56. package/dist/agent-docs/components/MessageList.md +96 -0
  57. package/dist/agent-docs/components/MultipleSelector.md +146 -0
  58. package/dist/agent-docs/components/NavigationMenu.md +51 -0
  59. package/dist/agent-docs/components/Pagination.md +55 -0
  60. package/dist/agent-docs/components/Popover.md +103 -0
  61. package/dist/agent-docs/components/Progress.md +30 -0
  62. package/dist/agent-docs/components/PromptSuggestions.md +33 -0
  63. package/dist/agent-docs/components/RadioGroup.md +90 -0
  64. package/dist/agent-docs/components/Resizable.md +35 -0
  65. package/dist/agent-docs/components/ResizePrompt.md +13 -0
  66. package/dist/agent-docs/components/ScrollArea.md +49 -0
  67. package/dist/agent-docs/components/SecurePdfViewer.md +38 -0
  68. package/dist/agent-docs/components/Select.md +132 -0
  69. package/dist/agent-docs/components/Separator.md +32 -0
  70. package/dist/agent-docs/components/Sheet.md +40 -0
  71. package/dist/agent-docs/components/ShikiHighlighter.md +31 -0
  72. package/dist/agent-docs/components/Sidebar.md +85 -0
  73. package/dist/agent-docs/components/Skeleton.md +29 -0
  74. package/dist/agent-docs/components/Slider.md +58 -0
  75. package/dist/agent-docs/components/Sonner.md +21 -0
  76. package/dist/agent-docs/components/Spinner.md +139 -0
  77. package/dist/agent-docs/components/Stepper.md +67 -0
  78. package/dist/agent-docs/components/Switch.md +42 -0
  79. package/dist/agent-docs/components/Table.md +63 -0
  80. package/dist/agent-docs/components/TableSkeleton.md +46 -0
  81. package/dist/agent-docs/components/Tabs.md +86 -0
  82. package/dist/agent-docs/components/TextArea.md +52 -0
  83. package/dist/agent-docs/components/ThemeSwitcher.md +69 -0
  84. package/dist/agent-docs/components/Toaster.md +23 -0
  85. package/dist/agent-docs/components/Toggle.md +31 -0
  86. package/dist/agent-docs/components/ToggleGroup.md +30 -0
  87. package/dist/agent-docs/components/Tooltip.md +91 -0
  88. package/dist/agent-docs/components/TypingIndicator.md +21 -0
  89. package/dist/agent-docs/components/Typo.md +65 -0
  90. package/dist/agent-docs/components/WeeklyCalendar.md +64 -0
  91. package/dist/agent-docs/components-list.md +144 -0
  92. package/dist/components/ui/spinner.js +67 -0
  93. package/dist/index.d.ts +11 -0
  94. package/dist/index.js +363 -361
  95. package/dist/node_modules/eventemitter3/index2.js +1 -1
  96. package/dist/node_modules/style-to-object/cjs/index.js +1 -1
  97. package/dist/styles.v3.css +1 -1
  98. package/package.json +3 -2
@@ -0,0 +1,427 @@
1
+ # AppSelect
2
+
3
+ ## Overview
4
+
5
+ A flexible select component supporting both single and multiple selection modes with advanced features including search, grouping, custom labels (JSX), clear actions, chips display, and optional item creation. Built on top of Command and Popover components.
6
+
7
+ ---
8
+
9
+ ## Types
10
+
11
+ ### AppSelectOption
12
+
13
+ ```ts
14
+ export interface AppSelectOption {
15
+ value: string | number; // Unique identifier for the option
16
+ label: string | React.ReactNode; // Display label (can be JSX for custom rendering)
17
+ disabled?: boolean; // Disables selection of this option
18
+ group?: string; // Group name for grouping options
19
+ fixed?: boolean; // In chip mode, prevents removal of this option
20
+ }
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Props
26
+
27
+ The component uses discriminated union types based on the `multiple` prop.
28
+
29
+ ### Base Props (Common to both modes)
30
+
31
+ | Prop | Type | Default | Description |
32
+ | -------------------- | ------------------------------ | ------------------------------------------------ | --------------------------------------------- |
33
+ | `options` | `AppSelectOption[]` | **required** | Array of selectable options |
34
+ | `placeholder` | `string` | `"Seleziona..."` | Text shown in trigger when no selection |
35
+ | `searchPlaceholder` | `string` | `"Cerca..."` | Placeholder for search input |
36
+ | `emptyPlaceholder` | `string` | `"Nessun risultato"` | Text shown when no options match search |
37
+ | `addItemPlaceholder` | `string` | `"Aggiungi"` | Text prefix for creating new items |
38
+ | `itemCountMessage` | `(selected: number) => string` | `(n) => "${n} elementi selezionati"` | Message function for selected count display |
39
+ | `maxSelectedMessage` | `(max: number) => string` | `(m) => "Puoi selezionare fino a ${m} elementi"` | Message shown when max selection reached |
40
+ | `label` | `string \| React.ReactNode` | `undefined` | Label displayed above the select |
41
+ | `className` | `string` | `""` | Additional Tailwind classes for the trigger |
42
+ | `wrpClassName` | `string` | `""` | Additional Tailwind classes for the wrapper |
43
+ | `searchable` | `boolean` | `false` | Enables search/filter functionality |
44
+ | `creatable` | `boolean` | `false` | Allows creating new options from search input |
45
+ | `disabled` | `boolean` | `false` | Disables the entire select component |
46
+ | `groupBy` | `keyof AppSelectOption` | `"group"` | Property key used to group options |
47
+ | `size` | `"sm" \| "default" \| "lg"` | `"default"` | Size variant affecting height and text size |
48
+ | `onClear` | `() => void` | `undefined` | Callback fired when clear button is clicked |
49
+
50
+ ### Single Select Props
51
+
52
+ ```ts
53
+ export type SingleSelectProps = BaseProps & {
54
+ multiple?: false; // Single selection mode (default)
55
+ value?: string | number; // Controlled value
56
+ defaultValue?: string | number; // Uncontrolled default value
57
+ onValueChange?: (value: string | number | undefined) => void; // Value change callback
58
+ isSingleSelectClearable?: boolean; // Shows clear button (default: false)
59
+ };
60
+ ```
61
+
62
+ ### Multi Select Props
63
+
64
+ ```ts
65
+ export type MultiSelectProps = BaseProps & {
66
+ multiple: true; // Multiple selection mode
67
+ value?: (string | number)[]; // Controlled values array
68
+ defaultValue?: (string | number)[]; // Uncontrolled default values
69
+ onValueChange?: (value: (string | number)[]) => void; // Value change callback
70
+ maxSelected?: number; // Maximum number of selectable items
71
+ showChipsInsteadOfCount?: boolean; // Display chips instead of count (default: false)
72
+ };
73
+ ```
74
+
75
+ ### Combined Type
76
+
77
+ ```ts
78
+ export type AppSelectProps = SingleSelectProps | MultiSelectProps;
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Prop Details
84
+
85
+ ### Size Variants
86
+
87
+ The `size` prop controls the trigger height and text size:
88
+
89
+ - **`sm`**: `min-h-8 h-8 text-xs py-1.5`
90
+ - **`default`**: `min-h-9 h-9 text-sm py-2`
91
+ - **`lg`**: `min-h-10 h-10 text-base py-2`
92
+
93
+ ### Custom Labels (JSX Support)
94
+
95
+ The `label` property in `AppSelectOption` supports both strings and React nodes, allowing for rich custom rendering with icons, badges, or any JSX content. When using JSX labels, the component properly handles them without wrapping issues (React 19 compatible).
96
+
97
+ ### Controlled vs Uncontrolled
98
+
99
+ - **Controlled**: Component is controlled when the `value` prop is provided (checked via `props.hasOwnProperty('value')`)
100
+ - **Uncontrolled**: Uses internal state when only `defaultValue` is provided
101
+ - The component remains in its initial mode throughout its lifecycle
102
+
103
+ ---
104
+
105
+ ## Behavior
106
+
107
+ ### Selection Modes
108
+
109
+ #### Single Select
110
+
111
+ - Clicking an option selects it and closes the popover
112
+ - Only one option can be selected at a time
113
+ - Clear button appears when `isSingleSelectClearable={true}` and a value is selected
114
+ - Clearing sets value to `undefined`
115
+
116
+ #### Multiple Select
117
+
118
+ - Clicking an option toggles its selection state
119
+ - Popover remains open for multiple selections
120
+ - Selected count or chips displayed in trigger
121
+ - Clear button always visible when selections exist
122
+ - Clearing sets value to empty array `[]`
123
+
124
+ ### Search Functionality
125
+
126
+ When `searchable={true}`:
127
+
128
+ - Search input appears at the top of the popover
129
+ - Options are filtered client-side based on label text
130
+ - Search is case-insensitive
131
+ - Empty state shows `emptyPlaceholder` when no matches
132
+
133
+ ### Creatable Options
134
+
135
+ When `creatable={true}`:
136
+
137
+ - Requires `searchable={true}` to work
138
+ - Shows "Aggiungi '[input]'" option when search text doesn't match existing options
139
+ - Selecting the create option adds the input text as a new value
140
+ - In single mode, closes popover after creation
141
+ - In multiple mode, keeps popover open for more selections
142
+
143
+ ### Grouping
144
+
145
+ When options have a `group` property:
146
+
147
+ - Options are automatically grouped under headings
148
+ - Groups are rendered in the order they appear in the options array
149
+ - Use `groupBy` prop to specify which property to group by (default: `"group"`)
150
+ - Options without a group value appear in an unnamed group
151
+
152
+ ### Max Selection Limit
153
+
154
+ In multiple mode with `maxSelected` set:
155
+
156
+ - Prevents selecting more than the specified number of items
157
+ - Unselected options become disabled when limit is reached
158
+ - Footer message appears showing the limit via `maxSelectedMessage`
159
+ - Selected items can still be deselected
160
+
161
+ ### Chips Display
162
+
163
+ In multiple mode with `showChipsInsteadOfCount={true}`:
164
+
165
+ - Shows individual badge chips for each selected item
166
+ - Each chip has an X button to remove the item
167
+ - Options with `fixed={true}` show chips without X button (cannot be removed)
168
+ - Chips are scrollable horizontally if they overflow
169
+
170
+ ### Disabled Options
171
+
172
+ Options with `disabled={true}`:
173
+
174
+ - Appear grayed out with reduced opacity
175
+ - Cannot be selected or deselected
176
+ - Cursor changes to `not-allowed`
177
+
178
+ ### Disabled Component
179
+
180
+ When `disabled={true}`:
181
+
182
+ - Entire component is non-interactive
183
+ - Trigger shows reduced opacity
184
+ - Popover cannot be opened
185
+ - Cursor changes to `not-allowed`
186
+
187
+ ---
188
+
189
+ ## Examples
190
+
191
+ ### Basic Single Select
192
+
193
+ ```tsx
194
+ import { AppSelect } from "laif-ds";
195
+ import { useState } from "react";
196
+
197
+ const options = [
198
+ { value: "react", label: "React" },
199
+ { value: "vue", label: "Vue" },
200
+ { value: "angular", label: "Angular" },
201
+ ];
202
+
203
+ export function BasicSelect() {
204
+ const [value, setValue] = useState<string | number | undefined>();
205
+
206
+ return (
207
+ <AppSelect
208
+ options={options}
209
+ value={value}
210
+ onValueChange={setValue}
211
+ placeholder="Select a framework"
212
+ label="Framework"
213
+ />
214
+ );
215
+ }
216
+ ```
217
+
218
+ ### Multiple Select with Search and Chips
219
+
220
+ ```tsx
221
+ import { AppSelect } from "laif-ds";
222
+ import { useState } from "react";
223
+
224
+ const options = [
225
+ { value: 1, label: "React" },
226
+ { value: 2, label: "Vue" },
227
+ { value: 3, label: "Angular" },
228
+ { value: 4, label: "Svelte" },
229
+ ];
230
+
231
+ export function MultiSelectWithChips() {
232
+ const [values, setValues] = useState<(string | number)[]>([]);
233
+
234
+ return (
235
+ <AppSelect
236
+ multiple
237
+ options={options}
238
+ value={values}
239
+ onValueChange={setValues}
240
+ placeholder="Select frameworks"
241
+ label="Frameworks"
242
+ searchable
243
+ showChipsInsteadOfCount
244
+ />
245
+ );
246
+ }
247
+ ```
248
+
249
+ ### Grouped Options with Max Selection
250
+
251
+ ```tsx
252
+ import { AppSelect } from "laif-ds";
253
+ import { useState } from "react";
254
+
255
+ const options = [
256
+ { value: "react", label: "React", group: "Frontend" },
257
+ { value: "vue", label: "Vue", group: "Frontend" },
258
+ { value: "node", label: "Node.js", group: "Backend" },
259
+ { value: "django", label: "Django", group: "Backend" },
260
+ ];
261
+
262
+ export function GroupedSelect() {
263
+ const [values, setValues] = useState<(string | number)[]>([]);
264
+
265
+ return (
266
+ <AppSelect
267
+ multiple
268
+ options={options}
269
+ value={values}
270
+ onValueChange={setValues}
271
+ placeholder="Select up to 2 technologies"
272
+ label="Tech Stack"
273
+ groupBy="group"
274
+ maxSelected={2}
275
+ searchable
276
+ />
277
+ );
278
+ }
279
+ ```
280
+
281
+ ### Creatable Select
282
+
283
+ ```tsx
284
+ import { AppSelect } from "laif-ds";
285
+ import { useState } from "react";
286
+
287
+ const initialOptions = [
288
+ { value: "tag1", label: "Tag 1" },
289
+ { value: "tag2", label: "Tag 2" },
290
+ ];
291
+
292
+ export function CreatableSelect() {
293
+ const [values, setValues] = useState<(string | number)[]>([]);
294
+
295
+ return (
296
+ <AppSelect
297
+ multiple
298
+ options={initialOptions}
299
+ value={values}
300
+ onValueChange={setValues}
301
+ placeholder="Create or select tags"
302
+ label="Tags"
303
+ searchable
304
+ creatable
305
+ showChipsInsteadOfCount
306
+ />
307
+ );
308
+ }
309
+ ```
310
+
311
+ ### Custom JSX Labels
312
+
313
+ ```tsx
314
+ import { AppSelect } from "laif-ds";
315
+ import { useState } from "react";
316
+
317
+ const options = [
318
+ {
319
+ value: "react",
320
+ label: (
321
+ <div className="flex items-center gap-2">
322
+ <span className="text-blue-600">⚛</span>
323
+ React
324
+ </div>
325
+ ),
326
+ },
327
+ {
328
+ value: "vue",
329
+ label: (
330
+ <div className="flex items-center gap-2">
331
+ <span className="text-green-600">●</span>
332
+ Vue
333
+ </div>
334
+ ),
335
+ },
336
+ {
337
+ value: "angular",
338
+ label: (
339
+ <div className="flex items-center gap-2">
340
+ <span className="text-red-600">▲</span>
341
+ Angular
342
+ </div>
343
+ ),
344
+ },
345
+ ];
346
+
347
+ export function CustomLabelsSelect() {
348
+ const [value, setValue] = useState<string | number | undefined>();
349
+
350
+ return (
351
+ <AppSelect
352
+ options={options}
353
+ value={value}
354
+ onValueChange={setValue}
355
+ placeholder="Select a framework"
356
+ label="Framework with Icons"
357
+ />
358
+ );
359
+ }
360
+ ```
361
+
362
+ ### Clearable Single Select
363
+
364
+ ```tsx
365
+ import { AppSelect } from "laif-ds";
366
+ import { useState } from "react";
367
+
368
+ const options = [
369
+ { value: 1, label: "Option 1" },
370
+ { value: 2, label: "Option 2" },
371
+ { value: 3, label: "Option 3" },
372
+ ];
373
+
374
+ export function ClearableSelect() {
375
+ const [value, setValue] = useState<string | number | undefined>(1);
376
+
377
+ return (
378
+ <AppSelect
379
+ options={options}
380
+ value={value}
381
+ onValueChange={setValue}
382
+ placeholder="Select an option"
383
+ label="Status"
384
+ isSingleSelectClearable
385
+ onClear={() => console.log("Cleared!")}
386
+ />
387
+ );
388
+ }
389
+ ```
390
+
391
+ ### With Disabled Options
392
+
393
+ ```tsx
394
+ import { AppSelect } from "laif-ds";
395
+ import { useState } from "react";
396
+
397
+ const options = [
398
+ { value: "it", label: "Italia" },
399
+ { value: "fr", label: "Francia" },
400
+ { value: "de", label: "Germania" },
401
+ { value: "uk", label: "Regno Unito", disabled: true },
402
+ ];
403
+
404
+ export function SelectWithDisabled() {
405
+ const [value, setValue] = useState<string | number | undefined>();
406
+
407
+ return (
408
+ <AppSelect
409
+ options={options}
410
+ value={value}
411
+ onValueChange={setValue}
412
+ placeholder="Select a country"
413
+ label="Country"
414
+ />
415
+ );
416
+ }
417
+ ```
418
+
419
+ ---
420
+
421
+ ## Notes
422
+
423
+ - **React 19 Compatible**: Properly handles JSX labels without ref warnings
424
+ - **Responsive Width**: Popover automatically matches trigger width
425
+ - **Keyboard Navigation**: Full keyboard support via Command component
426
+ - **Accessibility**: Proper ARIA attributes and focus management
427
+ - **Performance**: Efficient rendering with useMemo for computed values
@@ -0,0 +1,122 @@
1
+ # AppSidebar
2
+
3
+ ## Overview
4
+
5
+ High-level app sidebar built on top of `Sidebar` primitives. Renders navigation groups, nested items, header/footer content, optional versions area and an optional rail for resizing/collapsing.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ | Prop | Type | Default | Description |
12
+ | ------------------ | ------------------------------------ | ----------- | ----------- |
13
+ | `navigation` | `NavGroup[]` | **required**| Main navigation groups. |
14
+ | `navigationFooter` | `NavGroup[]` | `undefined` | Footer navigation groups. |
15
+ | `versions` | `string[]` | `undefined` | Optional versions list. |
16
+ | `defaultVersion` | `string` | `undefined` | Default selected version. |
17
+ | `headerContent` | `React.ReactNode` | `undefined` | Custom content at the top. |
18
+ | `footerContent` | `React.ReactNode` | `undefined` | Custom content at the bottom. |
19
+ | `showRail` | `boolean` | `true` | Show the draggable sidebar rail. |
20
+ | `linkComponent` | `React.ComponentType<any>` | `undefined` | Custom link component for items. |
21
+ | `linkProps` | `Record<string, any>` | `{}` | Extra props passed to the link component. |
22
+
23
+ `NavGroup` → `{ title: string; url?: string; items: NavItem[] }`
24
+
25
+ `NavItem` → `{ title: string; url: string; isActive?: boolean; iconName?: IconName; subItems?: NavSubItem[] }`
26
+
27
+ `NavSubItem` → `{ title: string; url: string; isActive?: boolean; iconName?: IconName }`
28
+
29
+ Inherits other props from `Sidebar` via `React.ComponentProps<typeof Sidebar>`.
30
+
31
+ ---
32
+
33
+ ## Behavior
34
+
35
+ - **Collapsible groups**: Clicking items with `subItems` toggles nested lists.
36
+ - **Active state**: `isActive` highlights and expands relevant items/groups.
37
+ - **Links**: Use `linkComponent` for framework routers (e.g., Next.js `Link`).
38
+ - **Rail**: `showRail` displays a thin draggable handle to collapse/expand.
39
+
40
+ ---
41
+
42
+ ## Examples
43
+
44
+ ### Basic
45
+
46
+ ```tsx
47
+ import { SidebarProvider, SidebarTrigger } from "laif-ds";
48
+ import { AppSidebar } from "laif-ds";
49
+
50
+ const navigation = [
51
+ {
52
+ title: "Generale",
53
+ items: [
54
+ { title: "Dashboard", url: "#", isActive: true, iconName: "Home" },
55
+ { title: "Utenti", url: "#", iconName: "Users" },
56
+ {
57
+ title: "Messaggi",
58
+ url: "#",
59
+ iconName: "MessageSquare",
60
+ subItems: [
61
+ { title: "Inbox", url: "#inbox", iconName: "Inbox" },
62
+ { title: "Inviati", url: "#sent", iconName: "Send" },
63
+ ],
64
+ },
65
+ ],
66
+ },
67
+ ];
68
+
69
+ export function Layout() {
70
+ return (
71
+ <SidebarProvider>
72
+ <div className="flex h-[100vh] overflow-hidden">
73
+ <AppSidebar navigation={navigation} showRail />
74
+ <div className="flex-1 overflow-auto p-4">
75
+ <SidebarTrigger />
76
+ {/* Page content */}
77
+ </div>
78
+ </div>
79
+ </SidebarProvider>
80
+ );
81
+ }
82
+ ```
83
+
84
+ ### With Header/Footer Content
85
+
86
+ ```tsx
87
+ import { Button, Input } from "laif-ds";
88
+
89
+ export function WithHeaderFooter() {
90
+ return (
91
+ <SidebarProvider>
92
+ <div className="flex h-[100vh] overflow-hidden">
93
+ <AppSidebar
94
+ navigation={[]}
95
+ headerContent={
96
+ <div className="p-4">
97
+ <Input iconLeft="Search" placeholder="Cerca..." className="bg-d-background pl-8" />
98
+ </div>
99
+ }
100
+ footerContent={
101
+ <div className="border-d-border border-t p-4">
102
+ <Button variant="ghost" className="w-full justify-start" iconLeft="Settings">
103
+ Impostazioni
104
+ </Button>
105
+ </div>
106
+ }
107
+ />
108
+ <div className="flex-1 overflow-auto p-4" />
109
+ </div>
110
+ </SidebarProvider>
111
+ );
112
+ }
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Notes
118
+
119
+ - **Routing**: Prefer `linkComponent` to avoid full page reloads (e.g., `next/link`).
120
+ - **Icons**: Use `laif-ds` `Icon` by passing `iconName` in navigation items.
121
+ - **Accessibility**: Sidebar primitives manage keyboard navigation and focus.
122
+
@@ -0,0 +1,77 @@
1
+ # AppStepper
2
+
3
+ ## Overview
4
+
5
+ High-level stepper built on `Stepper` primitives. Renders labeled steps with indicators and panels, supports horizontal/vertical layouts, separators, controlled navigation and custom click behavior.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ | Prop | Type | Default | Description |
12
+ | ------------------------ | ------------------------------------------------ | ------------- | ----------- |
13
+ | `steps` | `{ id: number; label: ReactNode; component: ReactNode; completed?; disabled?; loading?; }[]` | **required** | Steps to render (id is the step value). |
14
+ | `align` | `"horizontal" | "vertical"` | `"horizontal"` | Layout orientation. |
15
+ | `size` | `"sm" | "md"` | `"sm"` | Indicator/title sizing. |
16
+ | `showSeparators` | `boolean` | `true` | Show separators between steps. |
17
+ | `value` | `number` | first step id | Current step value (controlled). |
18
+ | `onValueChange` | `(value: number) => void` | `undefined` | Called when step changes. |
19
+ | `defaultStep` | `number` | `undefined` | Initial step if `value` is not provided. |
20
+ | `allowStepNavigation` | `boolean` | `true` | If `false`, steps are not clickable. |
21
+ | `allowClickOnlyCompleted`| `boolean` | `false` | If `true`, only completed steps are clickable. |
22
+ | `onStepClick` | `(step, index) => void` | `undefined` | Custom click handler; if provided, handles activation manually. |
23
+ | `indicators` | `{ active?; completed?; inactive?; loading? }` | `undefined` | Custom indicator content per state. |
24
+
25
+ Inherits the rest of `StepperProps` (e.g., `orientation` is controlled by `align`).
26
+
27
+ ---
28
+
29
+ ## Behavior
30
+
31
+ - **Controlled**: Always passes a `value` to `Stepper`. Update via `onValueChange`.
32
+ - **Clickable steps**: Governed by `allowStepNavigation` and `allowClickOnlyCompleted`.
33
+ - **Indicators**: Customize the indicator content through `indicators`.
34
+
35
+ ---
36
+
37
+ ## Examples
38
+
39
+ ```tsx
40
+ import * as React from "react";
41
+ import { AppStepper } from "laif-ds";
42
+
43
+ const steps = [
44
+ { id: 1, label: "Account Setup", component: <div>Step 1</div> },
45
+ { id: 2, label: "Profile Information", component: <div>Step 2</div> },
46
+ { id: 3, label: "Preferences", component: <div>Step 3</div> },
47
+ ] as const;
48
+
49
+ export function HorizontalStepper() {
50
+ const [current, setCurrent] = React.useState(1);
51
+ return (
52
+ <AppStepper
53
+ steps={steps}
54
+ value={current}
55
+ onValueChange={setCurrent}
56
+ align="horizontal"
57
+ size="md"
58
+ showSeparators
59
+ />
60
+ );
61
+ }
62
+
63
+ export function VerticalStepper() {
64
+ const [current, setCurrent] = React.useState(1);
65
+ return (
66
+ <AppStepper steps={steps} value={current} onValueChange={setCurrent} align="vertical" />
67
+ );
68
+ }
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Notes
74
+
75
+ - **Accessibility**: Based on `Stepper` primitives which manage keyboard and focus.
76
+ - **Custom click logic**: Provide `onStepClick` to intercept clicks (e.g., validation before navigation).
77
+