laif-ds 0.2.44 → 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.
- package/dist/_virtual/index4.js +5 -5
- package/dist/_virtual/index5.js +5 -5
- package/dist/_virtual/index6.js +2 -2
- package/dist/_virtual/index7.js +2 -2
- package/dist/agent-docs/components/Accordion.md +157 -0
- package/dist/agent-docs/components/Alert.md +95 -0
- package/dist/agent-docs/components/AlertDialog.md +126 -0
- package/dist/agent-docs/components/AppEditor.md +90 -0
- package/dist/agent-docs/components/AppForm.md +242 -0
- package/dist/agent-docs/components/AppMultipleSelectDropdown.md +38 -0
- package/dist/agent-docs/components/AppRadioGroup.md +223 -0
- package/dist/agent-docs/components/AppSelect.md +427 -0
- package/dist/agent-docs/components/AppSidebar.md +122 -0
- package/dist/agent-docs/components/AppStepper.md +77 -0
- package/dist/agent-docs/components/AspectRatio.md +87 -0
- package/dist/agent-docs/components/AsyncSelect.md +127 -0
- package/dist/agent-docs/components/AudioVisualizer.md +41 -0
- package/dist/agent-docs/components/Avatar.md +113 -0
- package/dist/agent-docs/components/Badge.md +118 -0
- package/dist/agent-docs/components/Breadcrumb.md +78 -0
- package/dist/agent-docs/components/Button.md +129 -0
- package/dist/agent-docs/components/Calendar.md +222 -0
- package/dist/agent-docs/components/Card.md +147 -0
- package/dist/agent-docs/components/Carousel.md +129 -0
- package/dist/agent-docs/components/Chart.md +75 -0
- package/dist/agent-docs/components/Chat.md +109 -0
- package/dist/agent-docs/components/ChatMessage.md +61 -0
- package/dist/agent-docs/components/Checkbox.md +135 -0
- package/dist/agent-docs/components/CircularProgress.md +49 -0
- package/dist/agent-docs/components/CodeHighlighter.md +31 -0
- package/dist/agent-docs/components/Collapsible.md +95 -0
- package/dist/agent-docs/components/Command.md +142 -0
- package/dist/agent-docs/components/Confirmer.md +175 -0
- package/dist/agent-docs/components/ContextMenu.md +191 -0
- package/dist/agent-docs/components/CopyButton.md +26 -0
- package/dist/agent-docs/components/DataCrossTable.md +94 -0
- package/dist/agent-docs/components/DataTable.md +254 -0
- package/dist/agent-docs/components/DatePicker.md +109 -0
- package/dist/agent-docs/components/Dialog.md +125 -0
- package/dist/agent-docs/components/Drawer.md +127 -0
- package/dist/agent-docs/components/DropdownMenu.md +57 -0
- package/dist/agent-docs/components/FilePreview.md +99 -0
- package/dist/agent-docs/components/FilePreviewer.md +139 -0
- package/dist/agent-docs/components/FileUploader.md +129 -0
- package/dist/agent-docs/components/Form.md +62 -0
- package/dist/agent-docs/components/FormComposer.md +137 -0
- package/dist/agent-docs/components/GanttChart.md +122 -0
- package/dist/agent-docs/components/HoverCard.md +37 -0
- package/dist/agent-docs/components/Icon.md +99 -0
- package/dist/agent-docs/components/Input.md +138 -0
- package/dist/agent-docs/components/InputOtp.md +40 -0
- package/dist/agent-docs/components/InputSelector.md +97 -0
- package/dist/agent-docs/components/InterruptPrompt.md +32 -0
- package/dist/agent-docs/components/Label.md +28 -0
- package/dist/agent-docs/components/MarkdownRenderer.md +36 -0
- package/dist/agent-docs/components/Menubar.md +164 -0
- package/dist/agent-docs/components/MessageInput.md +131 -0
- package/dist/agent-docs/components/MessageList.md +96 -0
- package/dist/agent-docs/components/MultipleSelector.md +146 -0
- package/dist/agent-docs/components/NavigationMenu.md +51 -0
- package/dist/agent-docs/components/Pagination.md +55 -0
- package/dist/agent-docs/components/Popover.md +103 -0
- package/dist/agent-docs/components/Progress.md +30 -0
- package/dist/agent-docs/components/PromptSuggestions.md +33 -0
- package/dist/agent-docs/components/RadioGroup.md +90 -0
- package/dist/agent-docs/components/Resizable.md +35 -0
- package/dist/agent-docs/components/ResizePrompt.md +13 -0
- package/dist/agent-docs/components/ScrollArea.md +49 -0
- package/dist/agent-docs/components/SecurePdfViewer.md +38 -0
- package/dist/agent-docs/components/Select.md +132 -0
- package/dist/agent-docs/components/Separator.md +32 -0
- package/dist/agent-docs/components/Sheet.md +40 -0
- package/dist/agent-docs/components/ShikiHighlighter.md +31 -0
- package/dist/agent-docs/components/Sidebar.md +85 -0
- package/dist/agent-docs/components/Skeleton.md +29 -0
- package/dist/agent-docs/components/Slider.md +58 -0
- package/dist/agent-docs/components/Sonner.md +21 -0
- package/dist/agent-docs/components/Spinner.md +139 -0
- package/dist/agent-docs/components/Stepper.md +67 -0
- package/dist/agent-docs/components/Switch.md +42 -0
- package/dist/agent-docs/components/Table.md +63 -0
- package/dist/agent-docs/components/TableSkeleton.md +46 -0
- package/dist/agent-docs/components/Tabs.md +86 -0
- package/dist/agent-docs/components/TextArea.md +52 -0
- package/dist/agent-docs/components/ThemeSwitcher.md +69 -0
- package/dist/agent-docs/components/Toaster.md +23 -0
- package/dist/agent-docs/components/Toggle.md +31 -0
- package/dist/agent-docs/components/ToggleGroup.md +30 -0
- package/dist/agent-docs/components/Tooltip.md +91 -0
- package/dist/agent-docs/components/TypingIndicator.md +21 -0
- package/dist/agent-docs/components/Typo.md +65 -0
- package/dist/agent-docs/components/WeeklyCalendar.md +64 -0
- package/dist/agent-docs/components-list.md +144 -0
- package/dist/node_modules/eventemitter3/index2.js +1 -1
- package/dist/node_modules/hast-util-to-jsx-runtime/lib/index.js +1 -1
- package/dist/node_modules/style-to-object/cjs/index.js +1 -1
- package/dist/node_modules/unified/lib/index.js +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# InputSelector
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Compact numeric selector with increment/decrement buttons, value bounds, and subtle animations. Useful for choosing small integer quantities (e.g., seats, guests).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| ------------------ | -------------------- | --------- | -------------------------------------------- |
|
|
13
|
+
| `value` | `number` | `1` | Current numeric value. |
|
|
14
|
+
| `onChange` | `(value: number) => void` | `undefined` | Called with the new value. |
|
|
15
|
+
| `min` | `number` | `1` | Minimum allowed value. |
|
|
16
|
+
| `max` | `number` | `4` | Maximum allowed value. |
|
|
17
|
+
| `className` | `string` | `""` | Wrapper classes. |
|
|
18
|
+
| `buttonClassName` | `string` | `""` | Classes for +/- buttons. |
|
|
19
|
+
| `counterClassName` | `string` | `""` | Classes for the numeric counter. |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Behavior
|
|
24
|
+
|
|
25
|
+
- **Controlled**: `value` is controlled; emits `onChange(newValue)` on clicks within bounds.
|
|
26
|
+
- **Bounds**: At min or max, the component vibrates (subtle shake animation) instead of changing value.
|
|
27
|
+
- **A11y**: Buttons are real `<button>` elements with clear `+`/`-` labels.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Examples
|
|
32
|
+
|
|
33
|
+
### Basic
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { useState } from "react";
|
|
37
|
+
import { InputSelector } from "laif-ds";
|
|
38
|
+
|
|
39
|
+
export function BasicSelector() {
|
|
40
|
+
const [value, setValue] = useState(2);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<InputSelector value={value} onChange={setValue} min={1} max={4} />
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Controlled
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useState } from "react";
|
|
52
|
+
import { InputSelector } from "laif-ds";
|
|
53
|
+
|
|
54
|
+
export function ControlledSelector() {
|
|
55
|
+
const [value, setValue] = useState(2);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="flex flex-col items-center gap-2">
|
|
59
|
+
<InputSelector value={value} onChange={setValue} min={1} max={6} />
|
|
60
|
+
<div className="text-d-secondary-foreground text-sm">
|
|
61
|
+
Current value: {value}
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Custom Styling
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { useState } from "react";
|
|
72
|
+
import { InputSelector } from "laif-ds";
|
|
73
|
+
|
|
74
|
+
export function CustomStyledSelector() {
|
|
75
|
+
const [value, setValue] = useState(2);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<InputSelector
|
|
79
|
+
value={value}
|
|
80
|
+
onChange={setValue}
|
|
81
|
+
min={1}
|
|
82
|
+
max={4}
|
|
83
|
+
className="bg-d-secondary/10 p-6 rounded-xl"
|
|
84
|
+
buttonClassName="bg-d-primary text-d-primary-foreground hover:bg-d-primary/90 border-0"
|
|
85
|
+
counterClassName="text-d-primary font-bold"
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Notes
|
|
94
|
+
|
|
95
|
+
- **Bounds UX**: The slight vibration on bound hit provides feedback without changing the value.
|
|
96
|
+
- **Styling**: Prefer design tokens (`bg-d-*`, `text-d-*`) over raw colors.
|
|
97
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# InterruptPrompt
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Animated prompt that appears to allow interrupting an action (e.g., hitting Enter twice). Built with Framer Motion.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Description |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| `isOpen` | `boolean` | Whether the prompt is visible |
|
|
14
|
+
| `close` | `() => void` | Close handler |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Example
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { useState } from "react";
|
|
22
|
+
import { InterruptPrompt } from "laif-ds";
|
|
23
|
+
|
|
24
|
+
export function Demo() {
|
|
25
|
+
const [open, setOpen] = useState(true);
|
|
26
|
+
return (
|
|
27
|
+
<div className="relative h-32">
|
|
28
|
+
<InterruptPrompt isOpen={open} close={() => setOpen(false)} />
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Label
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Accessible label component built on Radix Label with default spacing and disabled styles.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
Extends `@radix-ui/react-label` Root props.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Label, Input } from "laif-ds";
|
|
19
|
+
|
|
20
|
+
export function LabeledInput() {
|
|
21
|
+
return (
|
|
22
|
+
<div className="grid gap-2">
|
|
23
|
+
<Label htmlFor="email">Email</Label>
|
|
24
|
+
<Input id="email" type="email" placeholder="you@example.com" />
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# MarkdownRenderer
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Renders Markdown with GitHub-flavored Markdown (GFM) and async syntax highlighting using Shiki. Includes Copy button for code blocks.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { MarkdownRenderer } from "laif-ds";
|
|
13
|
+
|
|
14
|
+
const content = `
|
|
15
|
+
# Hello
|
|
16
|
+
|
|
17
|
+
Some ` + "`code`" + ` and a list:
|
|
18
|
+
|
|
19
|
+
- Item A
|
|
20
|
+
- Item B
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
export function Doc() {
|
|
24
|
+
return <MarkdownRenderer>{content}</MarkdownRenderer>;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Supports headings, lists, tables, links, blockquotes, and inline code
|
|
29
|
+
- Code blocks highlighted when a language class is provided (e.g., `language-ts`)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- Uses `react-markdown` + `remark-gfm`
|
|
36
|
+
- Code highlighting falls back to plain `<pre>` if language is unsupported
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Menubar
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Top-level horizontal application menu built on Radix Menubar. Supports nested submenus, checkbox and radio items, separators, and keyboard navigation.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Subcomponents & Props
|
|
10
|
+
|
|
11
|
+
- **Menubar**: Root container. Extends `@radix-ui/react-menubar` Root props.
|
|
12
|
+
- **MenubarMenu**: Wraps a single menu.
|
|
13
|
+
- **MenubarTrigger**: Button that opens its menu.
|
|
14
|
+
- **MenubarContent**: The floating panel with items.
|
|
15
|
+
- `align`: `start | center | end` (default `start`)
|
|
16
|
+
- `alignOffset`: `number` (default `-4`)
|
|
17
|
+
- `sideOffset`: `number` (default `8`)
|
|
18
|
+
- **MenubarItem**: Clickable action item.
|
|
19
|
+
- `variant`: `"default" | "destructive"` (default `"default"`)
|
|
20
|
+
- `inset`: `boolean` (indent the item)
|
|
21
|
+
- **MenubarCheckboxItem**: Checkbox item.
|
|
22
|
+
- `checked`: `boolean`
|
|
23
|
+
- **MenubarRadioGroup**: Groups radio items.
|
|
24
|
+
- `value`, `onValueChange`: controlled selection
|
|
25
|
+
- **MenubarRadioItem**: Radio item in a group.
|
|
26
|
+
- **MenubarLabel**: Non-interactive label.
|
|
27
|
+
- **MenubarSeparator**: Horizontal separator.
|
|
28
|
+
- **MenubarShortcut**: Right-aligned keyboard shortcut hint.
|
|
29
|
+
- **MenubarSub / MenubarSubTrigger / MenubarSubContent**: Submenu primitives.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Behavior
|
|
34
|
+
|
|
35
|
+
- **Keyboard navigation**: Arrow keys to move between triggers and items, Enter/Space to select.
|
|
36
|
+
- **States**: Triggers reflect open/focus states. `variant="destructive"` styles an item for dangerous actions.
|
|
37
|
+
- **Accessibility**: Proper roles and aria attributes via Radix primitives.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
### Basic
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import {
|
|
47
|
+
Menubar,
|
|
48
|
+
MenubarMenu,
|
|
49
|
+
MenubarTrigger,
|
|
50
|
+
MenubarContent,
|
|
51
|
+
MenubarItem,
|
|
52
|
+
MenubarSeparator,
|
|
53
|
+
MenubarSub,
|
|
54
|
+
MenubarSubTrigger,
|
|
55
|
+
MenubarSubContent,
|
|
56
|
+
MenubarShortcut,
|
|
57
|
+
} from "laif-ds";
|
|
58
|
+
|
|
59
|
+
export function BasicMenubar() {
|
|
60
|
+
return (
|
|
61
|
+
<Menubar>
|
|
62
|
+
<MenubarMenu>
|
|
63
|
+
<MenubarTrigger>File</MenubarTrigger>
|
|
64
|
+
<MenubarContent>
|
|
65
|
+
<MenubarItem>
|
|
66
|
+
New Tab <MenubarShortcut>⌘T</MenubarShortcut>
|
|
67
|
+
</MenubarItem>
|
|
68
|
+
<MenubarItem>
|
|
69
|
+
New Window <MenubarShortcut>⌘N</MenubarShortcut>
|
|
70
|
+
</MenubarItem>
|
|
71
|
+
<MenubarSeparator />
|
|
72
|
+
<MenubarSub>
|
|
73
|
+
<MenubarSubTrigger>Share</MenubarSubTrigger>
|
|
74
|
+
<MenubarSubContent>
|
|
75
|
+
<MenubarItem>Email Link</MenubarItem>
|
|
76
|
+
<MenubarItem>Messages</MenubarItem>
|
|
77
|
+
<MenubarItem>Notes</MenubarItem>
|
|
78
|
+
</MenubarSubContent>
|
|
79
|
+
</MenubarSub>
|
|
80
|
+
<MenubarSeparator />
|
|
81
|
+
<MenubarItem>
|
|
82
|
+
Print... <MenubarShortcut>⌘P</MenubarShortcut>
|
|
83
|
+
</MenubarItem>
|
|
84
|
+
</MenubarContent>
|
|
85
|
+
</MenubarMenu>
|
|
86
|
+
</Menubar>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### With Groups and Radios
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import {
|
|
95
|
+
Menubar,
|
|
96
|
+
MenubarMenu,
|
|
97
|
+
MenubarTrigger,
|
|
98
|
+
MenubarContent,
|
|
99
|
+
MenubarLabel,
|
|
100
|
+
MenubarRadioGroup,
|
|
101
|
+
MenubarRadioItem,
|
|
102
|
+
MenubarSeparator,
|
|
103
|
+
} from "laif-ds";
|
|
104
|
+
|
|
105
|
+
export function MenubarWithGroups() {
|
|
106
|
+
return (
|
|
107
|
+
<Menubar>
|
|
108
|
+
<MenubarMenu>
|
|
109
|
+
<MenubarTrigger>Options</MenubarTrigger>
|
|
110
|
+
<MenubarContent>
|
|
111
|
+
<MenubarLabel>Theme</MenubarLabel>
|
|
112
|
+
<MenubarSeparator />
|
|
113
|
+
<MenubarRadioGroup value="light">
|
|
114
|
+
<MenubarRadioItem value="light">Light</MenubarRadioItem>
|
|
115
|
+
<MenubarRadioItem value="dark">Dark</MenubarRadioItem>
|
|
116
|
+
<MenubarRadioItem value="system">System</MenubarRadioItem>
|
|
117
|
+
</MenubarRadioGroup>
|
|
118
|
+
</MenubarContent>
|
|
119
|
+
</MenubarMenu>
|
|
120
|
+
</Menubar>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Destructive Item
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import {
|
|
129
|
+
Menubar,
|
|
130
|
+
MenubarMenu,
|
|
131
|
+
MenubarTrigger,
|
|
132
|
+
MenubarContent,
|
|
133
|
+
MenubarItem,
|
|
134
|
+
MenubarSeparator,
|
|
135
|
+
MenubarShortcut,
|
|
136
|
+
} from "laif-ds";
|
|
137
|
+
|
|
138
|
+
export function DestructiveExample() {
|
|
139
|
+
return (
|
|
140
|
+
<Menubar>
|
|
141
|
+
<MenubarMenu>
|
|
142
|
+
<MenubarTrigger>Actions</MenubarTrigger>
|
|
143
|
+
<MenubarContent>
|
|
144
|
+
<MenubarItem>Copy <MenubarShortcut>⌘C</MenubarShortcut></MenubarItem>
|
|
145
|
+
<MenubarItem>Paste <MenubarShortcut>⌘V</MenubarShortcut></MenubarItem>
|
|
146
|
+
<MenubarSeparator />
|
|
147
|
+
<MenubarItem variant="destructive">
|
|
148
|
+
Delete <MenubarShortcut>⌘⌫</MenubarShortcut>
|
|
149
|
+
</MenubarItem>
|
|
150
|
+
</MenubarContent>
|
|
151
|
+
</MenubarMenu>
|
|
152
|
+
</Menubar>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Notes
|
|
160
|
+
|
|
161
|
+
- **Composition**: Combine subcomponents to build complex menus.
|
|
162
|
+
- **Shortcuts**: Use `MenubarShortcut` for right-aligned hints.
|
|
163
|
+
- **A11y**: Labels and roles are handled by Radix primitives and DS styling.
|
|
164
|
+
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# MessageInput
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Chat composer with autosizing textarea, optional file attachments, voice input (record/transcribe), and intelligent Enter-to-send behavior with interruption prompts.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
Extends native `<textarea>` props.
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
| ------------------ | ---------------------------------------------- | ---------- | ----------- |
|
|
15
|
+
| `value` | `string` | **required** | Controlled text value. |
|
|
16
|
+
| `isGenerating` | `boolean` | `false` | If true, shows stop button and may display interrupt prompt. |
|
|
17
|
+
| `submitOnEnter` | `boolean` | `true` | Press Enter to submit (Shift+Enter for newline). |
|
|
18
|
+
| `stop` | `() => void` | `undefined`| Stop generation handler (used with `isGenerating`). |
|
|
19
|
+
| `enableInterrupt` | `boolean` | `true` | If true, pressing Enter while generating shows confirm to interrupt. |
|
|
20
|
+
| `transcribeAudio` | `(blob: Blob) => Promise<string>` | `undefined`| Optional audio-to-text function. |
|
|
21
|
+
| `allowAttachments` | `boolean` | `false` | Enable file attachments UI. |
|
|
22
|
+
| `files` | `File[] | null` | `null` | Current attached files (when `allowAttachments`). |
|
|
23
|
+
| `setFiles` | `React.Dispatch<React.SetStateAction<File[] | null>>` | `undefined`| Setter for attachments. |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Behavior
|
|
28
|
+
|
|
29
|
+
- **Enter to submit**: If `submitOnEnter` and not `shiftKey`, calls `form.requestSubmit()`.
|
|
30
|
+
- **Interrupt flow**: If `isGenerating` and `stop` and `enableInterrupt`, pressing Enter shows a prompt to confirm stopping the generation and sending the new message.
|
|
31
|
+
- **Autosize**: Textarea grows up to a max height, then scrolls.
|
|
32
|
+
- **Attachments**: Drag & drop, paste files; long pasted text (> 500 chars) becomes a text file. Uses `FilePreview` to show chips.
|
|
33
|
+
- **Voice input**: If supported, toggles microphone recording; shows visualizer while recording and a "transcribing" overlay after.
|
|
34
|
+
- **Actions**: Right-aligned action buttons: attach, mic, send/stop.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
### Basic
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import * as React from "react";
|
|
44
|
+
import { MessageInput } from "laif-ds";
|
|
45
|
+
|
|
46
|
+
export function BasicComposer() {
|
|
47
|
+
const [value, setValue] = React.useState("");
|
|
48
|
+
const onSubmit = (e: React.FormEvent) => {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
console.log("Messaggio inviato:", value);
|
|
51
|
+
setValue("");
|
|
52
|
+
};
|
|
53
|
+
return (
|
|
54
|
+
<form onSubmit={onSubmit} className="w-full max-w-2xl">
|
|
55
|
+
<MessageInput value={value} onChange={(e) => setValue(e.target.value)} isGenerating={false} />
|
|
56
|
+
</form>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### With Attachments
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import * as React from "react";
|
|
65
|
+
import { MessageInput } from "laif-ds";
|
|
66
|
+
|
|
67
|
+
export function WithAttachments() {
|
|
68
|
+
const [value, setValue] = React.useState("");
|
|
69
|
+
const [files, setFiles] = React.useState<File[] | null>(null);
|
|
70
|
+
const onSubmit = (e: React.FormEvent) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
console.log("Messaggio inviato:", value, files);
|
|
73
|
+
setValue("");
|
|
74
|
+
setFiles(null);
|
|
75
|
+
};
|
|
76
|
+
return (
|
|
77
|
+
<form onSubmit={onSubmit} className="w-full max-w-2xl">
|
|
78
|
+
<MessageInput
|
|
79
|
+
value={value}
|
|
80
|
+
onChange={(e) => setValue(e.target.value)}
|
|
81
|
+
isGenerating={false}
|
|
82
|
+
allowAttachments
|
|
83
|
+
files={files}
|
|
84
|
+
setFiles={setFiles}
|
|
85
|
+
placeholder="Scrivi un messaggio o trascina file qui..."
|
|
86
|
+
/>
|
|
87
|
+
</form>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Generating + Interrupt
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import * as React from "react";
|
|
96
|
+
import { MessageInput } from "laif-ds";
|
|
97
|
+
|
|
98
|
+
export function Generating() {
|
|
99
|
+
const [value, setValue] = React.useState("");
|
|
100
|
+
const [isGenerating, setIsGenerating] = React.useState(true);
|
|
101
|
+
const stop = () => setIsGenerating(false);
|
|
102
|
+
const onSubmit = (e: React.FormEvent) => {
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
if (isGenerating) return;
|
|
105
|
+
console.log("Messaggio inviato:", value);
|
|
106
|
+
setValue("");
|
|
107
|
+
setIsGenerating(true);
|
|
108
|
+
setTimeout(() => setIsGenerating(false), 3000);
|
|
109
|
+
};
|
|
110
|
+
return (
|
|
111
|
+
<form onSubmit={onSubmit} className="w-full max-w-2xl">
|
|
112
|
+
<MessageInput
|
|
113
|
+
value={value}
|
|
114
|
+
onChange={(e) => setValue(e.target.value)}
|
|
115
|
+
isGenerating={isGenerating}
|
|
116
|
+
stop={stop}
|
|
117
|
+
placeholder="L'AI sta generando una risposta..."
|
|
118
|
+
/>
|
|
119
|
+
</form>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Notes
|
|
127
|
+
|
|
128
|
+
- **File preview**: Uses `FilePreview` for attachment chips.
|
|
129
|
+
- **Paste handling**: Long text paste becomes a `.txt` file when attachments are enabled.
|
|
130
|
+
- **A11y**: Textarea has aria-label; action buttons have aria-labels as well.
|
|
131
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# MessageList
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Vertical list of chat messages with optional typing indicator. Renders each message via `ChatMessage` and supports per-message actions.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| ----------------- | -------------------------------------------------------------------- | ----------- | ----------- |
|
|
13
|
+
| `messages` | `Message[]` | `[]` | Array of messages to render. |
|
|
14
|
+
| `showTimeStamps` | `boolean` | `true` | Show timestamps on each message. |
|
|
15
|
+
| `isTyping` | `boolean` | `false` | Shows a typing indicator at the end of the list. |
|
|
16
|
+
| `messageOptions` | `AdditionalMessageOptions \| (message: Message) => AdditionalMessageOptions` | `undefined` | Additional props/actions per message (static or function of message). |
|
|
17
|
+
| `onEdit` | `(id: string, newContent: string) => void` | `undefined` | Called when a message enters edit mode and changes. |
|
|
18
|
+
| `onMessageSave` | `(id: string, content: string) => void` | `undefined` | Called when a message edit is saved. |
|
|
19
|
+
|
|
20
|
+
`AdditionalMessageOptions` mirrors `ChatMessageProps` except base `Message` fields.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Behavior
|
|
25
|
+
|
|
26
|
+
- **Per-message customization**: Pass `messageOptions` as a function to supply contextual actions.
|
|
27
|
+
- **Typing indicator**: `isTyping` renders `TypingIndicator` as the last item.
|
|
28
|
+
- **Composition**: Each message is passed to `ChatMessage` with merged props.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
### Default
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { MessageList } from "laif-ds";
|
|
38
|
+
|
|
39
|
+
export function Chat() {
|
|
40
|
+
const messages = [
|
|
41
|
+
{ id: "1", role: "user", content: "Ciao!", createdAt: new Date() },
|
|
42
|
+
{ id: "2", role: "assistant", content: "Come posso aiutarti?", createdAt: new Date() },
|
|
43
|
+
];
|
|
44
|
+
return (
|
|
45
|
+
<div className="border-d-border w-full max-w-2xl rounded-lg border p-4">
|
|
46
|
+
<MessageList messages={messages} showTimeStamps />
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### With Actions
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { Button, Icon } from "laif-ds";
|
|
56
|
+
import { MessageList } from "laif-ds";
|
|
57
|
+
|
|
58
|
+
export function ChatWithActions() {
|
|
59
|
+
const messages = [
|
|
60
|
+
{ id: "1", role: "user", content: "Spiegami il virtual DOM", createdAt: new Date() },
|
|
61
|
+
{ id: "2", role: "assistant", content: "Il Virtual DOM è...", createdAt: new Date() },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="border-d-border w-full max-w-2xl rounded-lg border p-4">
|
|
66
|
+
<MessageList
|
|
67
|
+
messages={messages}
|
|
68
|
+
messageOptions={(m) =>
|
|
69
|
+
m.role === "assistant"
|
|
70
|
+
? {
|
|
71
|
+
actions: (
|
|
72
|
+
<>
|
|
73
|
+
<Button variant="ghost" size="icon" className="h-6 w-6">
|
|
74
|
+
<Icon name="ThumbsUp" className="size-4" />
|
|
75
|
+
</Button>
|
|
76
|
+
<Button variant="ghost" size="icon" className="h-6 w-6">
|
|
77
|
+
<Icon name="ThumbsDown" className="size-4" />
|
|
78
|
+
</Button>
|
|
79
|
+
</>
|
|
80
|
+
),
|
|
81
|
+
}
|
|
82
|
+
: {}
|
|
83
|
+
}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Notes
|
|
93
|
+
|
|
94
|
+
- **Data model**: See `ChatMessage` for the `Message` shape and advanced features (tool invocations, reasoning parts, edits).
|
|
95
|
+
- **A11y**: Provide readable timestamps and roles; actions should include accessible labels.
|
|
96
|
+
|