@alpic-ai/ui 0.0.0

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 (134) hide show
  1. package/dist/components/accordion-card.d.mts +41 -0
  2. package/dist/components/accordion-card.mjs +61 -0
  3. package/dist/components/accordion.d.mts +29 -0
  4. package/dist/components/accordion.mjs +48 -0
  5. package/dist/components/alert.d.mts +40 -0
  6. package/dist/components/alert.mjs +63 -0
  7. package/dist/components/attachment-tile.d.mts +26 -0
  8. package/dist/components/attachment-tile.mjs +35 -0
  9. package/dist/components/avatar.d.mts +52 -0
  10. package/dist/components/avatar.mjs +81 -0
  11. package/dist/components/badge.d.mts +20 -0
  12. package/dist/components/badge.mjs +36 -0
  13. package/dist/components/breadcrumb.d.mts +42 -0
  14. package/dist/components/breadcrumb.mjs +79 -0
  15. package/dist/components/button.d.mts +29 -0
  16. package/dist/components/button.mjs +67 -0
  17. package/dist/components/card.d.mts +37 -0
  18. package/dist/components/card.mjs +54 -0
  19. package/dist/components/checkbox.d.mts +11 -0
  20. package/dist/components/checkbox.mjs +26 -0
  21. package/dist/components/collapsible.d.mts +16 -0
  22. package/dist/components/collapsible.mjs +24 -0
  23. package/dist/components/combobox.d.mts +86 -0
  24. package/dist/components/combobox.mjs +207 -0
  25. package/dist/components/command.d.mts +38 -0
  26. package/dist/components/command.mjs +68 -0
  27. package/dist/components/copyable.d.mts +22 -0
  28. package/dist/components/copyable.mjs +33 -0
  29. package/dist/components/description-list.d.mts +22 -0
  30. package/dist/components/description-list.mjs +34 -0
  31. package/dist/components/dialog.d.mts +61 -0
  32. package/dist/components/dialog.mjs +110 -0
  33. package/dist/components/dropdown-menu.d.mts +72 -0
  34. package/dist/components/dropdown-menu.mjs +122 -0
  35. package/dist/components/input-group.d.mts +25 -0
  36. package/dist/components/input-group.mjs +43 -0
  37. package/dist/components/input.d.mts +27 -0
  38. package/dist/components/input.mjs +90 -0
  39. package/dist/components/label.d.mts +11 -0
  40. package/dist/components/label.mjs +14 -0
  41. package/dist/components/pagination.d.mts +18 -0
  42. package/dist/components/pagination.mjs +42 -0
  43. package/dist/components/popover.d.mts +22 -0
  44. package/dist/components/popover.mjs +34 -0
  45. package/dist/components/radio-group.d.mts +15 -0
  46. package/dist/components/radio-group.mjs +26 -0
  47. package/dist/components/scroll-area.d.mts +17 -0
  48. package/dist/components/scroll-area.mjs +35 -0
  49. package/dist/components/select-trigger-variants.d.mts +13 -0
  50. package/dist/components/select-trigger-variants.mjs +23 -0
  51. package/dist/components/select.d.mts +51 -0
  52. package/dist/components/select.mjs +95 -0
  53. package/dist/components/separator.d.mts +13 -0
  54. package/dist/components/separator.mjs +16 -0
  55. package/dist/components/sheet.d.mts +43 -0
  56. package/dist/components/sheet.mjs +74 -0
  57. package/dist/components/sidebar.d.mts +163 -0
  58. package/dist/components/sidebar.mjs +378 -0
  59. package/dist/components/skeleton.d.mts +16 -0
  60. package/dist/components/skeleton.mjs +21 -0
  61. package/dist/components/sonner.d.mts +29 -0
  62. package/dist/components/sonner.mjs +76 -0
  63. package/dist/components/spinner.d.mts +30 -0
  64. package/dist/components/spinner.mjs +46 -0
  65. package/dist/components/status-dot.d.mts +19 -0
  66. package/dist/components/status-dot.mjs +34 -0
  67. package/dist/components/switch.d.mts +11 -0
  68. package/dist/components/switch.mjs +18 -0
  69. package/dist/components/table.d.mts +38 -0
  70. package/dist/components/table.mjs +65 -0
  71. package/dist/components/tabs.d.mts +58 -0
  72. package/dist/components/tabs.mjs +119 -0
  73. package/dist/components/tag.d.mts +35 -0
  74. package/dist/components/tag.mjs +65 -0
  75. package/dist/components/textarea.d.mts +21 -0
  76. package/dist/components/textarea.mjs +44 -0
  77. package/dist/components/toggle-group.d.mts +28 -0
  78. package/dist/components/toggle-group.mjs +72 -0
  79. package/dist/components/tooltip-icon-button.d.mts +12 -0
  80. package/dist/components/tooltip-icon-button.mjs +27 -0
  81. package/dist/components/tooltip.d.mts +23 -0
  82. package/dist/components/tooltip.mjs +35 -0
  83. package/dist/hooks/use-copy-to-clipboard.d.mts +11 -0
  84. package/dist/hooks/use-copy-to-clipboard.mjs +24 -0
  85. package/dist/hooks/use-mobile.d.mts +4 -0
  86. package/dist/hooks/use-mobile.mjs +16 -0
  87. package/dist/lib/cn.d.mts +6 -0
  88. package/dist/lib/cn.mjs +8 -0
  89. package/package.json +88 -0
  90. package/src/components/accordion-card.tsx +103 -0
  91. package/src/components/accordion.tsx +63 -0
  92. package/src/components/alert.tsx +74 -0
  93. package/src/components/attachment-tile.tsx +68 -0
  94. package/src/components/avatar.tsx +127 -0
  95. package/src/components/badge.tsx +41 -0
  96. package/src/components/breadcrumb.tsx +98 -0
  97. package/src/components/button.tsx +106 -0
  98. package/src/components/card.tsx +62 -0
  99. package/src/components/checkbox.tsx +35 -0
  100. package/src/components/collapsible.tsx +18 -0
  101. package/src/components/combobox.tsx +393 -0
  102. package/src/components/command.tsx +112 -0
  103. package/src/components/copyable.tsx +47 -0
  104. package/src/components/description-list.tsx +36 -0
  105. package/src/components/dialog.tsx +161 -0
  106. package/src/components/dropdown-menu.tsx +234 -0
  107. package/src/components/input-group.tsx +97 -0
  108. package/src/components/input.tsx +145 -0
  109. package/src/components/label.tsx +20 -0
  110. package/src/components/pagination.tsx +53 -0
  111. package/src/components/popover.tsx +49 -0
  112. package/src/components/radio-group.tsx +33 -0
  113. package/src/components/scroll-area.tsx +48 -0
  114. package/src/components/select-trigger-variants.ts +28 -0
  115. package/src/components/select.tsx +186 -0
  116. package/src/components/separator.tsx +30 -0
  117. package/src/components/sheet.tsx +112 -0
  118. package/src/components/sidebar.tsx +682 -0
  119. package/src/components/skeleton.tsx +24 -0
  120. package/src/components/sonner.tsx +91 -0
  121. package/src/components/spinner.tsx +62 -0
  122. package/src/components/status-dot.tsx +33 -0
  123. package/src/components/switch.tsx +33 -0
  124. package/src/components/table.tsx +89 -0
  125. package/src/components/tabs.tsx +226 -0
  126. package/src/components/tag.tsx +82 -0
  127. package/src/components/textarea.tsx +70 -0
  128. package/src/components/toggle-group.tsx +96 -0
  129. package/src/components/tooltip-icon-button.tsx +33 -0
  130. package/src/components/tooltip.tsx +54 -0
  131. package/src/hooks/use-copy-to-clipboard.ts +27 -0
  132. package/src/hooks/use-mobile.ts +17 -0
  133. package/src/lib/cn.ts +6 -0
  134. package/src/styles/tokens.css +352 -0
@@ -0,0 +1,393 @@
1
+ "use client";
2
+
3
+ import type { VariantProps } from "class-variance-authority";
4
+ import { Command as CommandPrimitive } from "cmdk";
5
+ import { CheckIcon, ChevronDownIcon, SearchIcon } from "lucide-react";
6
+ import { createContext, type ReactNode, useCallback, useContext, useMemo, useState } from "react";
7
+
8
+ import { cn } from "../lib/cn";
9
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover";
10
+ import { selectTriggerVariants } from "./select-trigger-variants";
11
+ import { TagDismissible } from "./tag";
12
+
13
+ /* ── Context ──────────────────────────────────────────────────────────────── */
14
+
15
+ interface ComboboxContextValue {
16
+ multiple: boolean;
17
+ value: string | null;
18
+ values: string[];
19
+ onSelect: (itemValue: string) => void;
20
+ onDeselect: (itemValue: string) => void;
21
+ isSelected: (itemValue: string) => boolean;
22
+ open: boolean;
23
+ onOpenChange: (open: boolean) => void;
24
+ }
25
+
26
+ const ComboboxContext = createContext<ComboboxContextValue | null>(null);
27
+
28
+ function useComboboxContext() {
29
+ const context = useContext(ComboboxContext);
30
+ if (!context) {
31
+ throw new Error("Combobox compound components must be used within <Combobox>");
32
+ }
33
+ return context;
34
+ }
35
+
36
+ /* ── Root ─────────────────────────────────────────────────────────────────── */
37
+
38
+ interface ComboboxBaseProps {
39
+ children: ReactNode;
40
+ open?: boolean;
41
+ defaultOpen?: boolean;
42
+ onOpenChange?: (open: boolean) => void;
43
+ }
44
+
45
+ interface ComboboxSingleProps extends ComboboxBaseProps {
46
+ multiple?: false;
47
+ value?: string | null;
48
+ defaultValue?: string | null;
49
+ onValueChange?: (value: string | null) => void;
50
+ }
51
+
52
+ interface ComboboxMultipleProps extends ComboboxBaseProps {
53
+ multiple: true;
54
+ value?: string[];
55
+ defaultValue?: string[];
56
+ onValueChange?: (value: string[]) => void;
57
+ }
58
+
59
+ type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps;
60
+
61
+ function Combobox(props: ComboboxProps) {
62
+ const {
63
+ children,
64
+ multiple = false,
65
+ open: controlledOpen,
66
+ defaultOpen = false,
67
+ onOpenChange: controlledOnOpenChange,
68
+ } = props;
69
+
70
+ // Single mode state
71
+ const [uncontrolledSingleValue, setUncontrolledSingleValue] = useState<string | null>(
72
+ !multiple ? ((props as ComboboxSingleProps).defaultValue ?? null) : null,
73
+ );
74
+
75
+ // Multi mode state
76
+ const [uncontrolledMultiValue, setUncontrolledMultiValue] = useState<string[]>(
77
+ multiple ? ((props as ComboboxMultipleProps).defaultValue ?? []) : [],
78
+ );
79
+
80
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
81
+
82
+ const isOpenControlled = controlledOpen !== undefined;
83
+ const open = isOpenControlled ? controlledOpen : uncontrolledOpen;
84
+
85
+ const onOpenChange = useCallback(
86
+ (newOpen: boolean) => {
87
+ if (!isOpenControlled) setUncontrolledOpen(newOpen);
88
+ controlledOnOpenChange?.(newOpen);
89
+ },
90
+ [isOpenControlled, controlledOnOpenChange],
91
+ );
92
+
93
+ // Resolve current values
94
+ const singleValue = multiple
95
+ ? null
96
+ : (((props as ComboboxSingleProps).value !== undefined
97
+ ? (props as ComboboxSingleProps).value
98
+ : uncontrolledSingleValue) ?? null);
99
+
100
+ const multiValues = multiple
101
+ ? (props as ComboboxMultipleProps).value !== undefined
102
+ ? ((props as ComboboxMultipleProps).value as string[])
103
+ : uncontrolledMultiValue
104
+ : [];
105
+
106
+ const isSelected = useCallback(
107
+ (itemValue: string) => {
108
+ if (multiple) return multiValues.includes(itemValue);
109
+ return singleValue === itemValue;
110
+ },
111
+ [multiple, singleValue, multiValues],
112
+ );
113
+
114
+ // Extract specific callbacks to avoid depending on the entire props object
115
+ const onValueChangeSingle = !multiple ? (props as ComboboxSingleProps).onValueChange : undefined;
116
+ const onValueChangeMulti = multiple ? (props as ComboboxMultipleProps).onValueChange : undefined;
117
+ const isControlledSingle = !multiple && (props as ComboboxSingleProps).value !== undefined;
118
+ const isControlledMulti = multiple && (props as ComboboxMultipleProps).value !== undefined;
119
+
120
+ const onSelect = useCallback(
121
+ (itemValue: string) => {
122
+ if (multiple) {
123
+ const next = multiValues.includes(itemValue)
124
+ ? multiValues.filter((val) => val !== itemValue)
125
+ : [...multiValues, itemValue];
126
+ if (!isControlledMulti) setUncontrolledMultiValue(next);
127
+ onValueChangeMulti?.(next);
128
+ // Stay open in multi mode
129
+ } else {
130
+ if (!isControlledSingle) setUncontrolledSingleValue(itemValue);
131
+ onValueChangeSingle?.(itemValue);
132
+ onOpenChange(false);
133
+ }
134
+ },
135
+ [
136
+ multiple,
137
+ isControlledMulti,
138
+ isControlledSingle,
139
+ onValueChangeMulti,
140
+ onValueChangeSingle,
141
+ multiValues,
142
+ onOpenChange,
143
+ ],
144
+ );
145
+
146
+ const onDeselect = useCallback(
147
+ (itemValue: string) => {
148
+ if (!multiple) return;
149
+ const next = multiValues.filter((val) => val !== itemValue);
150
+ if (!isControlledMulti) setUncontrolledMultiValue(next);
151
+ onValueChangeMulti?.(next);
152
+ },
153
+ [multiple, isControlledMulti, onValueChangeMulti, multiValues],
154
+ );
155
+
156
+ const contextValue = useMemo(
157
+ () => ({
158
+ multiple,
159
+ value: singleValue,
160
+ values: multiValues,
161
+ onSelect,
162
+ onDeselect,
163
+ isSelected,
164
+ open,
165
+ onOpenChange,
166
+ }),
167
+ [multiple, singleValue, multiValues, onSelect, onDeselect, isSelected, open, onOpenChange],
168
+ );
169
+
170
+ return (
171
+ <ComboboxContext.Provider value={contextValue}>
172
+ <Popover open={open} onOpenChange={onOpenChange}>
173
+ {children}
174
+ </Popover>
175
+ </ComboboxContext.Provider>
176
+ );
177
+ }
178
+
179
+ /* ── Trigger ──────────────────────────────────────────────────────────────── */
180
+
181
+ interface ComboboxTriggerProps
182
+ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "size">,
183
+ VariantProps<typeof selectTriggerVariants> {
184
+ placeholder?: string;
185
+ }
186
+
187
+ function ComboboxTrigger({ className, size, placeholder, children, ...props }: ComboboxTriggerProps) {
188
+ const { multiple, value, values, open, onDeselect } = useComboboxContext();
189
+
190
+ const isEmpty = multiple ? values.length === 0 : value === null || value === undefined;
191
+
192
+ return (
193
+ <PopoverTrigger asChild>
194
+ <button
195
+ type="button"
196
+ data-slot="combobox-trigger"
197
+ role="combobox"
198
+ aria-expanded={open}
199
+ className={cn(selectTriggerVariants({ size }), className)}
200
+ {...props}
201
+ >
202
+ <span
203
+ className={cn(
204
+ "flex flex-1 items-center gap-1.5 text-left",
205
+ multiple && "flex-wrap",
206
+ isEmpty && "text-placeholder",
207
+ )}
208
+ >
209
+ {isEmpty ? placeholder : multiple ? <ComboboxTags values={values} onDeselect={onDeselect} /> : children}
210
+ </span>
211
+ <ChevronDownIcon className="size-5 shrink-0 text-muted-foreground" />
212
+ </button>
213
+ </PopoverTrigger>
214
+ );
215
+ }
216
+
217
+ /* ── Tags (internal, for multi-select trigger) ────────────────────────────── */
218
+
219
+ function ComboboxTags({ values, onDeselect }: { values: string[]; onDeselect: (value: string) => void }) {
220
+ return (
221
+ <>
222
+ {values.map((tagValue) => (
223
+ <TagDismissible
224
+ key={tagValue}
225
+ onClick={(event) => event.stopPropagation()}
226
+ onDismiss={() => onDeselect(tagValue)}
227
+ >
228
+ {tagValue}
229
+ </TagDismissible>
230
+ ))}
231
+ </>
232
+ );
233
+ }
234
+
235
+ /* ── Content ──────────────────────────────────────────────────────────────── */
236
+
237
+ interface ComboboxContentProps extends React.ComponentProps<typeof PopoverContent> {
238
+ className?: string;
239
+ children?: ReactNode;
240
+ filter?: React.ComponentProps<typeof CommandPrimitive>["filter"];
241
+ }
242
+
243
+ function ComboboxContent({ className, children, filter, ...props }: ComboboxContentProps) {
244
+ const { multiple } = useComboboxContext();
245
+
246
+ return (
247
+ <PopoverContent
248
+ className={cn("w-[var(--radix-popover-trigger-width)] p-0", className)}
249
+ align="start"
250
+ onOpenAutoFocus={multiple ? (event: Event) => event.preventDefault() : undefined}
251
+ {...props}
252
+ >
253
+ <CommandPrimitive
254
+ data-slot="combobox-command"
255
+ filter={filter}
256
+ className="flex h-full w-full flex-col overflow-hidden rounded-md bg-popover"
257
+ >
258
+ {children}
259
+ </CommandPrimitive>
260
+ </PopoverContent>
261
+ );
262
+ }
263
+
264
+ /* ── Search ───────────────────────────────────────────────────────────────── */
265
+
266
+ function ComboboxSearch({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Input>) {
267
+ return (
268
+ <div data-slot="combobox-search" className="flex items-center gap-2 border-b border-border-secondary px-3 py-2.5">
269
+ <SearchIcon className="size-5 shrink-0 text-muted-foreground" />
270
+ <CommandPrimitive.Input
271
+ data-slot="combobox-search-input"
272
+ className={cn(
273
+ "flex h-full w-full bg-transparent type-text-md font-medium text-foreground outline-hidden",
274
+ "placeholder:text-placeholder",
275
+ "disabled:cursor-not-allowed disabled:opacity-50",
276
+ className,
277
+ )}
278
+ {...props}
279
+ />
280
+ </div>
281
+ );
282
+ }
283
+
284
+ /* ── List ─────────────────────────────────────────────────────────────────── */
285
+
286
+ function ComboboxList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {
287
+ return (
288
+ <CommandPrimitive.List
289
+ data-slot="combobox-list"
290
+ className={cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto py-1", className)}
291
+ {...props}
292
+ />
293
+ );
294
+ }
295
+
296
+ /* ── Empty ────────────────────────────────────────────────────────────────── */
297
+
298
+ function ComboboxEmpty({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
299
+ return (
300
+ <CommandPrimitive.Empty
301
+ data-slot="combobox-empty"
302
+ className={cn("py-6 text-center type-text-sm text-muted-foreground", className)}
303
+ {...props}
304
+ />
305
+ );
306
+ }
307
+
308
+ /* ── Group ────────────────────────────────────────────────────────────────── */
309
+
310
+ function ComboboxGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>) {
311
+ return (
312
+ <CommandPrimitive.Group
313
+ data-slot="combobox-group"
314
+ className={cn(
315
+ "overflow-hidden [&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:type-text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-subtle-foreground",
316
+ className,
317
+ )}
318
+ {...props}
319
+ />
320
+ );
321
+ }
322
+
323
+ /* ── Separator ────────────────────────────────────────────────────────────── */
324
+
325
+ function ComboboxSeparator({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
326
+ return (
327
+ <CommandPrimitive.Separator
328
+ data-slot="combobox-separator"
329
+ className={cn("bg-border-secondary -mx-1 my-1 h-px", className)}
330
+ {...props}
331
+ />
332
+ );
333
+ }
334
+
335
+ /* ── Item ─────────────────────────────────────────────────────────────────── */
336
+
337
+ interface ComboboxItemProps extends Omit<React.ComponentProps<typeof CommandPrimitive.Item>, "onSelect"> {
338
+ /** The value stored when this item is selected */
339
+ itemValue: string;
340
+ }
341
+
342
+ function ComboboxItem({ className, children, itemValue, ...props }: ComboboxItemProps) {
343
+ const { onSelect, isSelected } = useComboboxContext();
344
+ const selected = isSelected(itemValue);
345
+
346
+ return (
347
+ <CommandPrimitive.Item
348
+ data-slot="combobox-item"
349
+ data-selected-item={selected || undefined}
350
+ onSelect={() => onSelect(itemValue)}
351
+ className={cn(
352
+ "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-2.5 outline-hidden select-none",
353
+ "type-text-md font-medium text-foreground mx-1.5 my-px",
354
+ "data-[selected=true]:bg-background-hover",
355
+ "data-[selected-item]:bg-accent",
356
+ "data-[disabled=true]:pointer-events-none data-[disabled=true]:text-disabled-foreground",
357
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5",
358
+ className,
359
+ )}
360
+ {...props}
361
+ >
362
+ <span className="flex flex-1 items-center gap-2 truncate">{children}</span>
363
+ {selected && <CheckIcon className="size-5 shrink-0 text-primary" />}
364
+ </CommandPrimitive.Item>
365
+ );
366
+ }
367
+
368
+ /* ── Item supporting text ─────────────────────────────────────────────────── */
369
+
370
+ function ComboboxItemText({ className, children, ...props }: React.HTMLAttributes<HTMLSpanElement>) {
371
+ return (
372
+ <span
373
+ data-slot="combobox-item-text"
374
+ className={cn("type-text-md font-normal text-subtle-foreground", className)}
375
+ {...props}
376
+ >
377
+ {children}
378
+ </span>
379
+ );
380
+ }
381
+
382
+ export {
383
+ Combobox,
384
+ ComboboxContent,
385
+ ComboboxEmpty,
386
+ ComboboxGroup,
387
+ ComboboxItem,
388
+ ComboboxItemText,
389
+ ComboboxList,
390
+ ComboboxSearch,
391
+ ComboboxSeparator,
392
+ ComboboxTrigger,
393
+ };
@@ -0,0 +1,112 @@
1
+ "use client";
2
+
3
+ import { cn } from "@alpic-ai/ui/lib/cn";
4
+ import { Command as CommandPrimitive } from "cmdk";
5
+ import { SearchIcon } from "lucide-react";
6
+ import type * as React from "react";
7
+
8
+ function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
9
+ return (
10
+ <CommandPrimitive
11
+ data-slot="command"
12
+ className={cn("bg-popover text-foreground flex h-full w-full flex-col overflow-hidden rounded-md", className)}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ function CommandInput({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Input>) {
19
+ return (
20
+ <div data-slot="command-input-wrapper" className="flex h-14 items-center gap-2 border-b p-3">
21
+ <SearchIcon className="size-5 shrink-0 text-muted-foreground" />
22
+ <CommandPrimitive.Input
23
+ data-slot="command-input"
24
+ className={cn(
25
+ "placeholder:text-placeholder flex h-full w-full bg-transparent type-text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
26
+ className,
27
+ )}
28
+ {...props}
29
+ />
30
+ </div>
31
+ );
32
+ }
33
+
34
+ function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {
35
+ return (
36
+ <CommandPrimitive.List
37
+ data-slot="command-list"
38
+ className={cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", className)}
39
+ {...props}
40
+ />
41
+ );
42
+ }
43
+
44
+ function CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
45
+ return (
46
+ <CommandPrimitive.Empty
47
+ data-slot="command-empty"
48
+ className="py-6 text-center type-text-sm text-muted-foreground"
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+
54
+ function CommandGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>) {
55
+ return (
56
+ <CommandPrimitive.Group
57
+ data-slot="command-group"
58
+ className={cn(
59
+ "text-foreground [&_[cmdk-group-heading]]:text-subtle-foreground overflow-hidden px-2 py-1 [&_[cmdk-group-heading]]:p-2 [&_[cmdk-group-heading]]:type-text-xs [&_[cmdk-group-heading]]:font-medium",
60
+ className,
61
+ )}
62
+ {...props}
63
+ />
64
+ );
65
+ }
66
+
67
+ function CommandSeparator({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
68
+ return (
69
+ <CommandPrimitive.Separator
70
+ data-slot="command-separator"
71
+ className={cn("bg-border -mx-1 h-px", className)}
72
+ {...props}
73
+ />
74
+ );
75
+ }
76
+
77
+ function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {
78
+ return (
79
+ <CommandPrimitive.Item
80
+ data-slot="command-item"
81
+ className={cn(
82
+ "data-[selected=true]:bg-background-hover [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-xs px-2 py-3 type-text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:text-disabled-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5",
83
+ className,
84
+ )}
85
+ {...props}
86
+ />
87
+ );
88
+ }
89
+
90
+ function CommandShortcut({ className, ...props }: React.ComponentProps<"span">) {
91
+ return (
92
+ <span
93
+ data-slot="command-shortcut"
94
+ className={cn(
95
+ "ml-auto shrink-0 rounded-xs border border-border-secondary px-1 py-px type-text-xs font-medium text-placeholder",
96
+ className,
97
+ )}
98
+ {...props}
99
+ />
100
+ );
101
+ }
102
+
103
+ export {
104
+ Command,
105
+ CommandEmpty,
106
+ CommandGroup,
107
+ CommandInput,
108
+ CommandItem,
109
+ CommandList,
110
+ CommandSeparator,
111
+ CommandShortcut,
112
+ };
@@ -0,0 +1,47 @@
1
+ "use client";
2
+
3
+ import { Check, Copy } from "lucide-react";
4
+ import type { ReactNode } from "react";
5
+ import { useCopyToClipboard } from "../hooks/use-copy-to-clipboard";
6
+ import { cn } from "../lib/cn";
7
+ import { Button } from "./button";
8
+
9
+ interface CopyableProps {
10
+ content: string;
11
+ children: ReactNode;
12
+ className?: string;
13
+ }
14
+
15
+ function Copyable({ content, children, className }: CopyableProps) {
16
+ const { copy, isCopied } = useCopyToClipboard();
17
+
18
+ return (
19
+ <div className={cn("flex items-center gap-1", className)}>
20
+ {children}
21
+ <Button
22
+ variant="tertiary"
23
+ size="icon"
24
+ onClick={(event) => {
25
+ event.preventDefault();
26
+ copy(content);
27
+ }}
28
+ >
29
+ {isCopied ? <Check className="size-4 text-success" /> : <Copy className="size-4 text-muted-foreground" />}
30
+ </Button>
31
+ </div>
32
+ );
33
+ }
34
+
35
+ interface CopyableUrlProps {
36
+ url: URL;
37
+ }
38
+
39
+ function CopyableUrl({ url }: CopyableUrlProps) {
40
+ return (
41
+ <Copyable content={url.href}>
42
+ <span className="font-semibold">{url.hostname}</span>
43
+ </Copyable>
44
+ );
45
+ }
46
+
47
+ export { Copyable, type CopyableProps, CopyableUrl, type CopyableUrlProps };
@@ -0,0 +1,36 @@
1
+ "use client";
2
+
3
+ import { cn } from "@alpic-ai/ui/lib/cn";
4
+ import type * as React from "react";
5
+
6
+ function DescriptionList({ className, ...props }: React.ComponentProps<"dl">) {
7
+ return (
8
+ <dl
9
+ data-slot="description-list"
10
+ className={cn("grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4", className)}
11
+ {...props}
12
+ />
13
+ );
14
+ }
15
+
16
+ function DescriptionItem({ className, ...props }: React.ComponentProps<"div">) {
17
+ return <div data-slot="description-item" className={cn("flex flex-col gap-1 xl:gap-1.5", className)} {...props} />;
18
+ }
19
+
20
+ function DescriptionTitle({ className, ...props }: React.ComponentProps<"dt">) {
21
+ return (
22
+ <dt
23
+ data-slot="description-title"
24
+ className={cn("type-text-xs font-medium text-subtle-foreground", className)}
25
+ {...props}
26
+ />
27
+ );
28
+ }
29
+
30
+ function DescriptionValue({ className, ...props }: React.ComponentProps<"dd">) {
31
+ return (
32
+ <dd data-slot="description-value" className={cn("type-text-sm text-foreground truncate", className)} {...props} />
33
+ );
34
+ }
35
+
36
+ export { DescriptionItem, DescriptionList, DescriptionTitle, DescriptionValue };