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.
Files changed (98) hide show
  1. package/dist/_virtual/index4.js +5 -5
  2. package/dist/_virtual/index5.js +5 -5
  3. package/dist/_virtual/index6.js +2 -2
  4. package/dist/_virtual/index7.js +2 -2
  5. package/dist/agent-docs/components/Accordion.md +157 -0
  6. package/dist/agent-docs/components/Alert.md +95 -0
  7. package/dist/agent-docs/components/AlertDialog.md +126 -0
  8. package/dist/agent-docs/components/AppEditor.md +90 -0
  9. package/dist/agent-docs/components/AppForm.md +242 -0
  10. package/dist/agent-docs/components/AppMultipleSelectDropdown.md +38 -0
  11. package/dist/agent-docs/components/AppRadioGroup.md +223 -0
  12. package/dist/agent-docs/components/AppSelect.md +427 -0
  13. package/dist/agent-docs/components/AppSidebar.md +122 -0
  14. package/dist/agent-docs/components/AppStepper.md +77 -0
  15. package/dist/agent-docs/components/AspectRatio.md +87 -0
  16. package/dist/agent-docs/components/AsyncSelect.md +127 -0
  17. package/dist/agent-docs/components/AudioVisualizer.md +41 -0
  18. package/dist/agent-docs/components/Avatar.md +113 -0
  19. package/dist/agent-docs/components/Badge.md +118 -0
  20. package/dist/agent-docs/components/Breadcrumb.md +78 -0
  21. package/dist/agent-docs/components/Button.md +129 -0
  22. package/dist/agent-docs/components/Calendar.md +222 -0
  23. package/dist/agent-docs/components/Card.md +147 -0
  24. package/dist/agent-docs/components/Carousel.md +129 -0
  25. package/dist/agent-docs/components/Chart.md +75 -0
  26. package/dist/agent-docs/components/Chat.md +109 -0
  27. package/dist/agent-docs/components/ChatMessage.md +61 -0
  28. package/dist/agent-docs/components/Checkbox.md +135 -0
  29. package/dist/agent-docs/components/CircularProgress.md +49 -0
  30. package/dist/agent-docs/components/CodeHighlighter.md +31 -0
  31. package/dist/agent-docs/components/Collapsible.md +95 -0
  32. package/dist/agent-docs/components/Command.md +142 -0
  33. package/dist/agent-docs/components/Confirmer.md +175 -0
  34. package/dist/agent-docs/components/ContextMenu.md +191 -0
  35. package/dist/agent-docs/components/CopyButton.md +26 -0
  36. package/dist/agent-docs/components/DataCrossTable.md +94 -0
  37. package/dist/agent-docs/components/DataTable.md +254 -0
  38. package/dist/agent-docs/components/DatePicker.md +109 -0
  39. package/dist/agent-docs/components/Dialog.md +125 -0
  40. package/dist/agent-docs/components/Drawer.md +127 -0
  41. package/dist/agent-docs/components/DropdownMenu.md +57 -0
  42. package/dist/agent-docs/components/FilePreview.md +99 -0
  43. package/dist/agent-docs/components/FilePreviewer.md +139 -0
  44. package/dist/agent-docs/components/FileUploader.md +129 -0
  45. package/dist/agent-docs/components/Form.md +62 -0
  46. package/dist/agent-docs/components/FormComposer.md +137 -0
  47. package/dist/agent-docs/components/GanttChart.md +122 -0
  48. package/dist/agent-docs/components/HoverCard.md +37 -0
  49. package/dist/agent-docs/components/Icon.md +99 -0
  50. package/dist/agent-docs/components/Input.md +138 -0
  51. package/dist/agent-docs/components/InputOtp.md +40 -0
  52. package/dist/agent-docs/components/InputSelector.md +97 -0
  53. package/dist/agent-docs/components/InterruptPrompt.md +32 -0
  54. package/dist/agent-docs/components/Label.md +28 -0
  55. package/dist/agent-docs/components/MarkdownRenderer.md +36 -0
  56. package/dist/agent-docs/components/Menubar.md +164 -0
  57. package/dist/agent-docs/components/MessageInput.md +131 -0
  58. package/dist/agent-docs/components/MessageList.md +96 -0
  59. package/dist/agent-docs/components/MultipleSelector.md +146 -0
  60. package/dist/agent-docs/components/NavigationMenu.md +51 -0
  61. package/dist/agent-docs/components/Pagination.md +55 -0
  62. package/dist/agent-docs/components/Popover.md +103 -0
  63. package/dist/agent-docs/components/Progress.md +30 -0
  64. package/dist/agent-docs/components/PromptSuggestions.md +33 -0
  65. package/dist/agent-docs/components/RadioGroup.md +90 -0
  66. package/dist/agent-docs/components/Resizable.md +35 -0
  67. package/dist/agent-docs/components/ResizePrompt.md +13 -0
  68. package/dist/agent-docs/components/ScrollArea.md +49 -0
  69. package/dist/agent-docs/components/SecurePdfViewer.md +38 -0
  70. package/dist/agent-docs/components/Select.md +132 -0
  71. package/dist/agent-docs/components/Separator.md +32 -0
  72. package/dist/agent-docs/components/Sheet.md +40 -0
  73. package/dist/agent-docs/components/ShikiHighlighter.md +31 -0
  74. package/dist/agent-docs/components/Sidebar.md +85 -0
  75. package/dist/agent-docs/components/Skeleton.md +29 -0
  76. package/dist/agent-docs/components/Slider.md +58 -0
  77. package/dist/agent-docs/components/Sonner.md +21 -0
  78. package/dist/agent-docs/components/Spinner.md +139 -0
  79. package/dist/agent-docs/components/Stepper.md +67 -0
  80. package/dist/agent-docs/components/Switch.md +42 -0
  81. package/dist/agent-docs/components/Table.md +63 -0
  82. package/dist/agent-docs/components/TableSkeleton.md +46 -0
  83. package/dist/agent-docs/components/Tabs.md +86 -0
  84. package/dist/agent-docs/components/TextArea.md +52 -0
  85. package/dist/agent-docs/components/ThemeSwitcher.md +69 -0
  86. package/dist/agent-docs/components/Toaster.md +23 -0
  87. package/dist/agent-docs/components/Toggle.md +31 -0
  88. package/dist/agent-docs/components/ToggleGroup.md +30 -0
  89. package/dist/agent-docs/components/Tooltip.md +91 -0
  90. package/dist/agent-docs/components/TypingIndicator.md +21 -0
  91. package/dist/agent-docs/components/Typo.md +65 -0
  92. package/dist/agent-docs/components/WeeklyCalendar.md +64 -0
  93. package/dist/agent-docs/components-list.md +144 -0
  94. package/dist/node_modules/eventemitter3/index2.js +1 -1
  95. package/dist/node_modules/hast-util-to-jsx-runtime/lib/index.js +1 -1
  96. package/dist/node_modules/style-to-object/cjs/index.js +1 -1
  97. package/dist/node_modules/unified/lib/index.js +1 -1
  98. package/package.json +3 -2
@@ -0,0 +1,61 @@
1
+ # ChatMessage
2
+
3
+ ## Overview
4
+
5
+ Render a single chat message bubble with markdown, optional attachments preview, tool invocation blocks, reasoning collapsible, time stamps, actions and inline edit for assistant messages.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ | Prop | Type | Default | Description |
12
+ | --------------- | ------------------------ | ----------- | ----------- |
13
+ | `id` | `string` | **required**| Message id. |
14
+ | `role` | `"user" | "assistant" | (string)` | **required**| Role determines bubble style and alignment. |
15
+ | `content` | `string` | **required**| Message text (markdown supported). |
16
+ | `createdAt` | `Date` | `undefined` | Optional timestamp. |
17
+ | `experimental_attachments` | `{ url: string; name?: string; contentType?: string }[]` | `undefined` | Files to preview (user messages). |
18
+ | `toolInvocations` | `ToolInvocation[]` | `undefined` | Tool call states (`call`, `result`). |
19
+ | `parts` | `MessagePart[]` | `undefined` | Mixed message content (text/reasoning/tool-invocation). |
20
+ | `showTimeStamp` | `boolean` | `false` | Show `createdAt` under bubble. |
21
+ | `animation` | `"none" | "slide" | "scale" | "fade"` | `"scale"` | Entry animation.
22
+ | `actions` | `React.ReactNode` | `undefined` | Action buttons area (shown on hover). |
23
+ | `editable` | `boolean` | `false` | Force edit UI even without `onEdit`. |
24
+ | `onEdit` | `(newContent: string) => void` | `undefined` | Show edit UI on assistant messages. |
25
+ | `onMessageSave` | `(messageId: string, content: string) => void` | `undefined` | Save callback (rendered in action area). |
26
+
27
+ ---
28
+
29
+ ## Behavior
30
+
31
+ - **User vs Assistant**: Different bubble alignment and token styles.
32
+ - **Markdown**: Rendered via `MarkdownRenderer` with async suspense fallback.
33
+ - **Attachments**: User attachments rendered as `FilePreview` chips.
34
+ - **Tool calls**: `ToolInvocation` blocks show calling/result state with icons.
35
+ - **Edit**: Assistant messages can be edited inline (Enter save, Esc cancel).
36
+
37
+ ---
38
+
39
+ ## Examples
40
+
41
+ ```tsx
42
+ import { ChatMessage } from "laif-ds";
43
+
44
+ export function Examples() {
45
+ return (
46
+ <div className="space-y-4">
47
+ <ChatMessage id="u1" role="user" content="Hello" createdAt={new Date()} showTimeStamp />
48
+ <ChatMessage id="a1" role="assistant" content="Hi there!" createdAt={new Date()} showTimeStamp />
49
+ <ChatMessage id="a2" role="assistant" content={"**Bold** and `code`"} />
50
+ </div>
51
+ );
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Notes
58
+
59
+ - **Reasoning**: Use `parts` with `{ type: "reasoning", reasoning: string }` to show collapsible reasoning.
60
+ - **Actions**: Pass small `Button`s or icons (from `laif-ds`) via `actions`.
61
+
@@ -0,0 +1,135 @@
1
+ # Checkbox
2
+
3
+ ## Overview
4
+
5
+ Accessible checkbox with support for checked, unchecked, and indeterminate states. Keyboard focus styles and disabled state included.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ ### Checkbox (Root)
12
+
13
+ | Prop | Type | Default | Description |
14
+ | ------------------ | -------------------------------------- | ------------ | -------------------------------------------------- |
15
+ | `checked` | `boolean \| "indeterminate"` | `false` | Current state of the checkbox. |
16
+ | `disabled` | `boolean` | `false` | Disables interactions. |
17
+ | `onCheckedChange` | `(checked: boolean) => void` | `undefined` | Called when the state changes. |
18
+ | `id` | `string` | `undefined` | Useful when paired with a label's `htmlFor`. |
19
+ | `className` | `string` | `""` | Additional classes for size/layout. |
20
+
21
+ ---
22
+
23
+ ## Behavior
24
+
25
+ - **Indeterminate**: Use `checked="indeterminate"` to display a dash indicator.
26
+ - **Focus & invalid**: Visual feedback for focus and invalid states is included.
27
+ - **Labeling**: Pair with `Label` and `htmlFor` for accessible labeling.
28
+
29
+ ---
30
+
31
+ ## Examples
32
+
33
+ ### Default
34
+
35
+ ```tsx
36
+ import { Checkbox } from "laif-ds";
37
+ import { Label } from "laif-ds";
38
+
39
+ export function DefaultCheckbox() {
40
+ return (
41
+ <div className="flex items-center gap-2">
42
+ <Checkbox id="terms" />
43
+ <Label htmlFor="terms">Accept terms and conditions</Label>
44
+ </div>
45
+ );
46
+ }
47
+ ```
48
+
49
+ ### Indeterminate
50
+
51
+ ```tsx
52
+ import { Checkbox } from "laif-ds";
53
+ import { Label } from "laif-ds";
54
+
55
+ export function IndeterminateCheckbox() {
56
+ return (
57
+ <div className="flex items-center gap-2">
58
+ <Checkbox id="partial" checked="indeterminate" />
59
+ <Label htmlFor="partial">Partially selected options</Label>
60
+ </div>
61
+ );
62
+ }
63
+ ```
64
+
65
+ ### Disabled
66
+
67
+ ```tsx
68
+ import { Checkbox } from "laif-ds";
69
+ import { Label } from "laif-ds";
70
+
71
+ export function DisabledCheckbox() {
72
+ return (
73
+ <div className="flex items-center gap-2">
74
+ <Checkbox id="disabled" disabled />
75
+ <Label htmlFor="disabled">Accept terms and conditions</Label>
76
+ </div>
77
+ );
78
+ }
79
+ ```
80
+
81
+ ### Select All Pattern
82
+
83
+ ```tsx
84
+ import * as React from "react";
85
+ import { Checkbox } from "laif-ds";
86
+ import { Label } from "laif-ds";
87
+
88
+ export function SelectAllExample() {
89
+ const [items, setItems] = React.useState([
90
+ { id: "item1", label: "Item 1", checked: false },
91
+ { id: "item2", label: "Item 2", checked: true },
92
+ { id: "item3", label: "Item 3", checked: false },
93
+ ]);
94
+
95
+ const checkedCount = items.filter((i) => i.checked).length;
96
+ const selectAllState =
97
+ checkedCount === 0 ? false : checkedCount === items.length ? true : ("indeterminate" as const);
98
+
99
+ const handleSelectAll = () => {
100
+ const newChecked = selectAllState !== true;
101
+ setItems(items.map((i) => ({ ...i, checked: newChecked })));
102
+ };
103
+
104
+ return (
105
+ <div className="space-y-4">
106
+ <div className="flex items-center gap-2 border-b pb-2">
107
+ <Checkbox id="select-all" checked={selectAllState} onCheckedChange={handleSelectAll} />
108
+ <Label htmlFor="select-all">Select All ({checkedCount}/{items.length})</Label>
109
+ </div>
110
+ <div className="space-y-2 pl-6">
111
+ {items.map((item) => (
112
+ <div key={item.id} className="flex items-center gap-2">
113
+ <Checkbox
114
+ id={item.id}
115
+ checked={item.checked}
116
+ onCheckedChange={(checked) =>
117
+ setItems(items.map((i) => (i.id === item.id ? { ...i, checked: checked as boolean } : i)))
118
+ }
119
+ />
120
+ <Label htmlFor={item.id}>{item.label}</Label>
121
+ </div>
122
+ ))}
123
+ </div>
124
+ </div>
125
+ );
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Notes
132
+
133
+ - **Indicator**: A check icon is shown when `checked=true`, a dash for indeterminate.
134
+ - **Disabled**: Applies reduced opacity and disables pointer events.
135
+
@@ -0,0 +1,49 @@
1
+ # CircularProgress
2
+
3
+ ## Overview
4
+
5
+ SVG-based circular progress with customizable size, stroke widths, end-cap shape, and optional centered label.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ | Prop | Type | Default | Description |
12
+ | ------------------- | ------------------------------------ | ----------- | ----------- |
13
+ | `value` | `number` | **required**| Percentage [0-100]. |
14
+ | `renderLabel` | `(progress: number) => number|string`| `undefined` | Custom label renderer. |
15
+ | `size` | `number` | `100` | Diameter in px. |
16
+ | `strokeWidth` | `number` | `undefined` | Overrides both circle and progress stroke widths. |
17
+ | `circleStrokeWidth` | `number` | `10` | Base circle stroke width. |
18
+ | `progressStrokeWidth`| `number` | `10` | Progress stroke width. |
19
+ | `shape` | `"square" | "round"` | `"round"` | Stroke line cap. |
20
+ | `className` | `string` | `undefined` | Base circle classes. |
21
+ | `progressClassName` | `string` | `undefined` | Progress circle classes. |
22
+ | `labelClassName` | `string` | `undefined` | Center label classes. |
23
+ | `showLabel` | `boolean` | `false` | Show `{value}` (or `renderLabel(value)`) inside.
24
+
25
+ ---
26
+
27
+ ## Examples
28
+
29
+ ```tsx
30
+ import { CircularProgress } from "laif-ds";
31
+
32
+ export function Basic() {
33
+ return <CircularProgress value={65} size={100} showLabel />;
34
+ }
35
+
36
+ export function CustomLabel() {
37
+ return (
38
+ <CircularProgress value={42} size={120} showLabel renderLabel={(v) => `${v}%`} />
39
+ );
40
+ }
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Notes
46
+
47
+ - **Theming**: Base circle uses `stroke-d-primary/25`; progress uses `stroke-d-primary`.
48
+ - **Performance**: Pure SVG; safe to animate via CSS if needed.
49
+
@@ -0,0 +1,31 @@
1
+ # CodeHighlighter
2
+
3
+ ## Overview
4
+
5
+ Client-side code highlighter using Shiki with internal loading state and graceful fallback.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ | Prop | Type | Description |
12
+ | --- | --- | --- |
13
+ | `children` | `string` | Code string |
14
+ | `language` | `string` | Shiki language key |
15
+ | `className` | `string` | Optional classes for `<pre>` |
16
+
17
+ ---
18
+
19
+ ## Example
20
+
21
+ ```tsx
22
+ import CodeHighlighter from "laif-ds/CodeHighlighter";
23
+
24
+ export function CodeExample() {
25
+ return (
26
+ <CodeHighlighter language="tsx" className="rounded-md border p-3 text-sm">
27
+ {`export const x = (n: number) => n * 2`}
28
+ </CodeHighlighter>
29
+ );
30
+ }
31
+ ```
@@ -0,0 +1,95 @@
1
+ # Collapsible
2
+
3
+ ## Overview
4
+
5
+ A simple container that can show/hide content. Provides a trigger element and animated content area. Useful for progressive disclosure of details.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ ### Collapsible (Root)
12
+
13
+ | Prop | Type | Default | Description |
14
+ | -------------- | -------------------- | ----------- | --------------------------------------------- |
15
+ | `open` | `boolean` | `undefined` | Controlled open state. |
16
+ | `defaultOpen` | `boolean` | `false` | Uncontrolled initial open state. |
17
+ | `onOpenChange` | `(open: boolean) => void` | `undefined` | Called when open state changes. |
18
+ | `className` | `string` | `""` | Additional classes for the root. |
19
+
20
+ ### Subcomponents
21
+
22
+ - `CollapsibleTrigger`: The element that toggles visibility (can be used with `asChild`).
23
+ - `CollapsibleContent`: The collapsible content region.
24
+
25
+ ---
26
+
27
+ ## Behavior
28
+
29
+ - **Controlled**: Use `open` + `onOpenChange` to control state.
30
+ - **Uncontrolled**: Use `defaultOpen` for initial state.
31
+ - **Accessibility**: Works with button triggers and keyboard navigation.
32
+
33
+ ---
34
+
35
+ ## Examples
36
+
37
+ ### Basic
38
+
39
+ ```tsx
40
+ import { useState } from "react";
41
+ import { Button } from "laif-ds";
42
+ import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "laif-ds";
43
+
44
+ export function BasicCollapsible() {
45
+ const [isOpen, setIsOpen] = useState(false);
46
+ return (
47
+ <Collapsible open={isOpen} onOpenChange={setIsOpen} className="w-[350px] space-y-2">
48
+ <div className="flex items-center justify-between gap-4 px-4">
49
+ <h4 className="text-sm font-semibold">Details</h4>
50
+ <CollapsibleTrigger asChild>
51
+ <Button variant="ghost" size="sm">Toggle</Button>
52
+ </CollapsibleTrigger>
53
+ </div>
54
+ <CollapsibleContent className="space-y-2">
55
+ <div className="border-d-border rounded-md border px-4 py-3 text-sm">Item A</div>
56
+ <div className="border-d-border rounded-md border px-4 py-3 text-sm">Item B</div>
57
+ <div className="border-d-border rounded-md border px-4 py-3 text-sm">Item C</div>
58
+ </CollapsibleContent>
59
+ </Collapsible>
60
+ );
61
+ }
62
+ ```
63
+
64
+ ### Open by Default
65
+
66
+ ```tsx
67
+ import { useState } from "react";
68
+ import { Button } from "laif-ds";
69
+ import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "laif-ds";
70
+
71
+ export function OpenByDefault() {
72
+ const [isOpen, setIsOpen] = useState(true);
73
+ return (
74
+ <Collapsible open={isOpen} onOpenChange={setIsOpen} className="w-[350px] space-y-2">
75
+ <div className="flex items-center justify-between gap-4 px-4">
76
+ <h4 className="text-sm font-semibold">Details</h4>
77
+ <CollapsibleTrigger asChild>
78
+ <Button variant="ghost" size="sm">Toggle</Button>
79
+ </CollapsibleTrigger>
80
+ </div>
81
+ <CollapsibleContent className="space-y-2">
82
+ <div className="rounded-md border px-4 py-3 text-sm">This is additional information.</div>
83
+ </CollapsibleContent>
84
+ </Collapsible>
85
+ );
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Notes
92
+
93
+ - **asChild**: Wrap your own button/link as trigger while preserving styles.
94
+ - **Styling**: Use `className` on root/content to adjust spacing and borders.
95
+
@@ -0,0 +1,142 @@
1
+ # Command
2
+
3
+ ## Overview
4
+
5
+ Command palette and command list built on `cmdk`. Provides an input for filtering, groups, items, separators, and a dialog wrapper for modal usage.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ ### Command (Root)
12
+
13
+ | Prop | Type | Default | Description |
14
+ | ----------- | ----------------- | ----------- | -------------------------------------------------- |
15
+ | `className` | `string` | `""` | Additional classes for layout/size. |
16
+ | `children` | `React.ReactNode` | **required**| Compose with input, list, groups, items, etc. |
17
+
18
+ ### CommandDialog
19
+
20
+ Wraps a `Dialog` and renders a `Command` inside.
21
+
22
+ | Prop | Type | Default | Description |
23
+ | -------------- | ------------------------ | -------------------------------------- | -------------------------------- |
24
+ | `open` | `boolean` | `undefined` | Controlled open state. |
25
+ | `onOpenChange` | `(open: boolean) => any` | `undefined` | Called when dialog state changes.|
26
+ | `title` | `string` | `"Command Palette"` | Accessible dialog title. |
27
+ | `description` | `string` | `"Search for a command to run..."` | Accessible dialog description. |
28
+
29
+ ### Subcomponents
30
+
31
+ - `CommandInput`: Search input with a leading search icon.
32
+ - `CommandList`: Scrollable list container.
33
+ - `CommandEmpty`: Empty state when no results match.
34
+ - `CommandGroup`: Group with optional `heading` prop.
35
+ - `CommandItem`: Selectable item (supports disabled state).
36
+ - `CommandSeparator`: Visual separator between groups.
37
+ - `CommandShortcut`: Right-aligned shortcut hint (e.g., `⌘K`).
38
+
39
+ ---
40
+
41
+ ## Behavior
42
+
43
+ - **Filtering**: Typing in `CommandInput` filters visible items.
44
+ - **Keyboard**: Arrow keys navigate, Enter selects, Esc can close the dialog.
45
+ - **Accessibility**: Proper roles/aria set by `cmdk` and dialog wrapper.
46
+
47
+ ---
48
+
49
+ ## Examples
50
+
51
+ ### Basic List
52
+
53
+ ```tsx
54
+ import {
55
+ Command,
56
+ CommandEmpty,
57
+ CommandGroup,
58
+ CommandInput,
59
+ CommandItem,
60
+ CommandList,
61
+ CommandSeparator,
62
+ CommandShortcut,
63
+ } from "laif-ds";
64
+
65
+ export function BasicCommand() {
66
+ return (
67
+ <Command className="border-d-border w-[400px] rounded-lg border shadow-md">
68
+ <CommandInput placeholder="Type a command or search..." />
69
+ <CommandList>
70
+ <CommandEmpty>No results found.</CommandEmpty>
71
+ <CommandGroup heading="Suggestions">
72
+ <CommandItem>Calendar</CommandItem>
73
+ <CommandItem>Search</CommandItem>
74
+ <CommandItem>Settings</CommandItem>
75
+ </CommandGroup>
76
+ <CommandSeparator />
77
+ <CommandGroup heading="User">
78
+ <CommandItem>
79
+ Profile
80
+ <CommandShortcut>⌘P</CommandShortcut>
81
+ </CommandItem>
82
+ <CommandItem>Billing</CommandItem>
83
+ <CommandItem>Logout</CommandItem>
84
+ </CommandGroup>
85
+ </CommandList>
86
+ </Command>
87
+ );
88
+ }
89
+ ```
90
+
91
+ ### Command Dialog
92
+
93
+ ```tsx
94
+ import { useState } from "react";
95
+ import { Button } from "laif-ds";
96
+ import {
97
+ CommandDialog,
98
+ CommandInput,
99
+ CommandList,
100
+ CommandEmpty,
101
+ CommandGroup,
102
+ CommandItem,
103
+ CommandSeparator,
104
+ } from "laif-ds";
105
+
106
+ export function CommandDialogExample() {
107
+ const [open, setOpen] = useState(false);
108
+ return (
109
+ <>
110
+ <Button onClick={() => setOpen(true)} variant="outline">
111
+ Open Command Dialog
112
+ </Button>
113
+ <CommandDialog open={open} onOpenChange={setOpen}>
114
+ <CommandInput placeholder="Type a command or search..." />
115
+ <CommandList>
116
+ <CommandEmpty>No results found.</CommandEmpty>
117
+ <CommandGroup heading="Suggestions">
118
+ <CommandItem>Calendar</CommandItem>
119
+ <CommandItem>Search</CommandItem>
120
+ <CommandItem>Settings</CommandItem>
121
+ </CommandGroup>
122
+ <CommandSeparator />
123
+ <CommandGroup heading="User">
124
+ <CommandItem>Profile</CommandItem>
125
+ <CommandItem>Billing</CommandItem>
126
+ <CommandItem>Logout</CommandItem>
127
+ </CommandGroup>
128
+ </CommandList>
129
+ </CommandDialog>
130
+ </>
131
+ );
132
+ }
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Notes
138
+
139
+ - **Shortcuts**: Use `CommandShortcut` for right-aligned hints within `CommandItem`.
140
+ - **Layout**: Set explicit width on `Command` (e.g., `w-[400px]`) when used inline.
141
+ - **Dialog**: `CommandDialog` hides its title/description visually but preserves accessibility.
142
+
@@ -0,0 +1,175 @@
1
+ # Confirmer
2
+
3
+ ## Overview
4
+
5
+ Promise-based confirmation dialog utility built on top of `AlertDialog`. Mount the `Confirmer` component once, then call `confirm()` to open a dialog and await the user decision.
6
+
7
+ ---
8
+
9
+ ## API
10
+
11
+ ### `Confirmer` (Component)
12
+
13
+ Mount this once at app root (or Story scope) to enable dialogs.
14
+
15
+ ```tsx
16
+ import { Confirmer } from "laif-ds";
17
+
18
+ export function AppRoot() {
19
+ return (
20
+ <>
21
+ {/* ...your app... */}
22
+ <Confirmer />
23
+ </>
24
+ );
25
+ }
26
+ ```
27
+
28
+ ### `confirm(options)`
29
+
30
+ Returns a Promise that resolves when the user confirms and rejects when the user cancels.
31
+
32
+ ```ts
33
+ type ConfirmOptions = {
34
+ title?: React.ReactNode;
35
+ description?: React.ReactNode;
36
+ cancelText?: React.ReactNode;
37
+ actionText?: React.ReactNode;
38
+ CancelProps?: React.ComponentProps<typeof AlertDialogCancel>;
39
+ ActionProps?: React.ComponentProps<typeof Button>;
40
+ variant?: "default" | "destructive";
41
+ };
42
+
43
+ declare function confirm(options: ConfirmOptions): Promise<boolean>;
44
+ declare function safeConfirm(options: ConfirmOptions): Promise<boolean | undefined>;
45
+ ```
46
+
47
+ - `variant`: when set to `"destructive"`, shows a destructive style and warning icon.
48
+ - `safeConfirm`: resolves `undefined` instead of throwing on cancel.
49
+
50
+ ---
51
+
52
+ ## Behavior
53
+
54
+ - **Resolve/Reject**: `confirm()` resolves on action click, rejects on cancel or close.
55
+ - **Destructive mode**: Adds an alert icon and uses destructive button variant.
56
+ - **Custom buttons**: Pass `ActionProps` and `CancelProps` to customize.
57
+
58
+ ---
59
+
60
+ ## Examples
61
+
62
+ ### Destructive
63
+
64
+ ```tsx
65
+ import { Button } from "laif-ds";
66
+ import { Confirmer, confirm } from "laif-ds";
67
+
68
+ export function DeleteFile() {
69
+ const onClick = async () => {
70
+ try {
71
+ await confirm({
72
+ variant: "destructive",
73
+ title: "Permanently delete file?",
74
+ description: "This action cannot be undone. The file will be removed permanently.",
75
+ cancelText: "Cancel",
76
+ actionText: "Delete",
77
+ });
78
+ console.log("File deleted");
79
+ } catch {
80
+ console.log("Deletion cancelled");
81
+ }
82
+ };
83
+
84
+ return (
85
+ <>
86
+ <Button variant="destructive" onClick={onClick}>Delete File</Button>
87
+ <Confirmer />
88
+ </>
89
+ );
90
+ }
91
+ ```
92
+
93
+ ### Custom Text and Buttons
94
+
95
+ ```tsx
96
+ import { Button } from "laif-ds";
97
+ import { Confirmer, confirm } from "laif-ds";
98
+
99
+ export function PublishArticle() {
100
+ const onClick = async () => {
101
+ try {
102
+ await confirm({
103
+ title: "Publish article?",
104
+ description: "This will make your article visible to the public.",
105
+ cancelText: "Save as draft",
106
+ actionText: "Publish now",
107
+ ActionProps: {
108
+ variant: "default",
109
+ },
110
+ });
111
+ console.log("Article published");
112
+ } catch {
113
+ console.log("Article saved as draft");
114
+ }
115
+ };
116
+
117
+ return (
118
+ <>
119
+ <Button onClick={onClick}>Publish Article</Button>
120
+ <Confirmer />
121
+ </>
122
+ );
123
+ }
124
+ ```
125
+
126
+ ### Multiple Confirmers (independent flows)
127
+
128
+ ```tsx
129
+ import { Button } from "laif-ds";
130
+ import { Confirmer, confirm } from "laif-ds";
131
+
132
+ export function MultipleActions() {
133
+ const accept1 = async () => {
134
+ try {
135
+ await confirm({ title: "Confirm action 1", description: "This is the first confirmation dialog." });
136
+ console.log("Action 1 confirmed");
137
+ } catch {
138
+ console.log("Action 1 cancelled");
139
+ }
140
+ };
141
+
142
+ const accept2 = async () => {
143
+ try {
144
+ await confirm({
145
+ title: "Confirm action 2",
146
+ description: "This is the second confirmation dialog.",
147
+ cancelText: "Reject",
148
+ actionText: "Accept",
149
+ });
150
+ console.log("Action 2 confirmed");
151
+ } catch {
152
+ console.log("Action 2 cancelled");
153
+ }
154
+ };
155
+
156
+ return (
157
+ <>
158
+ <div className="flex gap-4">
159
+ <Button onClick={accept1}>Action 1</Button>
160
+ <Button onClick={accept2}>Action 2</Button>
161
+ </div>
162
+ <Confirmer />
163
+ </>
164
+ );
165
+ }
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Notes
171
+
172
+ - **Mount once**: Add a single `<Confirmer />` near app root.
173
+ - **Error handling**: Use `try/catch` with `confirm()`; or `safeConfirm()` to avoid throwing.
174
+ - **Theming**: `variant="destructive"` changes icon and button styling accordingly.
175
+