@vllnt/ui 0.2.1-canary.e1bc2b3 → 0.2.1-canary.ee942df

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 (137) hide show
  1. package/dist/components/agent-activity/agent-activity.js +311 -0
  2. package/dist/components/agent-activity/index.js +18 -0
  3. package/dist/components/ai-artifact/ai-artifact.js +422 -0
  4. package/dist/components/ai-artifact/index.js +24 -0
  5. package/dist/components/ai-sidebar/ai-sidebar.js +254 -0
  6. package/dist/components/ai-sidebar/index.js +22 -0
  7. package/dist/components/alert-pulse/alert-pulse.js +93 -0
  8. package/dist/components/alert-pulse/index.js +6 -0
  9. package/dist/components/auto-reload/auto-reload.js +367 -0
  10. package/dist/components/auto-reload/index.js +6 -0
  11. package/dist/components/banner/banner.js +155 -0
  12. package/dist/components/banner/index.js +10 -0
  13. package/dist/components/bottom-activity-strip/bottom-activity-strip.js +91 -0
  14. package/dist/components/bottom-activity-strip/index.js +6 -0
  15. package/dist/components/choropleth-map/choropleth-map.js +373 -0
  16. package/dist/components/choropleth-map/index.js +10 -0
  17. package/dist/components/chronological-timeline/chronological-timeline.js +337 -0
  18. package/dist/components/chronological-timeline/index.js +8 -0
  19. package/dist/components/civilization-card/civilization-card.js +258 -0
  20. package/dist/components/civilization-card/index.js +8 -0
  21. package/dist/components/comment-pin/comment-pin.js +104 -0
  22. package/dist/components/comment-pin/index.js +6 -0
  23. package/dist/components/context-lens/context-lens.js +98 -0
  24. package/dist/components/context-lens/index.js +6 -0
  25. package/dist/components/copy-button/copy-button.js +189 -0
  26. package/dist/components/copy-button/index.js +8 -0
  27. package/dist/components/document-sibling-nav/document-sibling-nav.js +111 -0
  28. package/dist/components/document-sibling-nav/index.js +8 -0
  29. package/dist/components/empty-state/empty-state.js +93 -0
  30. package/dist/components/empty-state/index.js +8 -0
  31. package/dist/components/era-comparison/era-comparison.js +198 -0
  32. package/dist/components/era-comparison/index.js +16 -0
  33. package/dist/components/floating-toolbar/floating-toolbar.js +66 -0
  34. package/dist/components/floating-toolbar/index.js +6 -0
  35. package/dist/components/follow-mode/follow-mode.js +89 -0
  36. package/dist/components/follow-mode/index.js +6 -0
  37. package/dist/components/gantt-chart/gantt-chart.js +331 -0
  38. package/dist/components/gantt-chart/index.js +6 -0
  39. package/dist/components/geography-quiz-map/geography-quiz-map.js +343 -0
  40. package/dist/components/geography-quiz-map/index.js +12 -0
  41. package/dist/components/globe-3d/globe-3d.js +417 -0
  42. package/dist/components/globe-3d/index.js +10 -0
  43. package/dist/components/handoff-beacon/handoff-beacon.js +78 -0
  44. package/dist/components/handoff-beacon/index.js +6 -0
  45. package/dist/components/heat-map-overlay/heat-map-overlay.js +215 -0
  46. package/dist/components/heat-map-overlay/index.js +6 -0
  47. package/dist/components/heat-overlay/heat-overlay.js +92 -0
  48. package/dist/components/heat-overlay/index.js +6 -0
  49. package/dist/components/historic-timeline/historic-timeline.js +342 -0
  50. package/dist/components/historic-timeline/index.js +6 -0
  51. package/dist/components/historical-figure-card/historical-figure-card.js +273 -0
  52. package/dist/components/historical-figure-card/index.js +6 -0
  53. package/dist/components/index.js +432 -1
  54. package/dist/components/infinite-plane/index.js +6 -0
  55. package/dist/components/infinite-plane/infinite-plane.js +75 -0
  56. package/dist/components/interactive-timeline/index.js +16 -0
  57. package/dist/components/interactive-timeline/interactive-timeline.js +708 -0
  58. package/dist/components/jarvis-dock/index.js +6 -0
  59. package/dist/components/jarvis-dock/jarvis-dock.js +98 -0
  60. package/dist/components/kbd/index.js +5 -0
  61. package/dist/components/kbd/kbd.js +117 -0
  62. package/dist/components/knowledge-check/index.js +6 -0
  63. package/dist/components/knowledge-check/knowledge-check.js +448 -0
  64. package/dist/components/live-cursor/index.js +6 -0
  65. package/dist/components/live-cursor/live-cursor.js +62 -0
  66. package/dist/components/map-2d/index.js +20 -0
  67. package/dist/components/map-2d/map-2d.js +455 -0
  68. package/dist/components/map-timeline/index.js +16 -0
  69. package/dist/components/map-timeline/map-timeline.js +506 -0
  70. package/dist/components/metric-cluster/index.js +6 -0
  71. package/dist/components/metric-cluster/metric-cluster.js +96 -0
  72. package/dist/components/model-comparison/index.js +12 -0
  73. package/dist/components/model-comparison/model-comparison.js +211 -0
  74. package/dist/components/multi-select-lasso/index.js +6 -0
  75. package/dist/components/multi-select-lasso/multi-select-lasso.js +76 -0
  76. package/dist/components/newsletter-signup/index.js +8 -0
  77. package/dist/components/newsletter-signup/newsletter-signup.js +269 -0
  78. package/dist/components/object-inspector/index.js +6 -0
  79. package/dist/components/object-inspector/object-inspector.js +136 -0
  80. package/dist/components/parallel-timeline/index.js +6 -0
  81. package/dist/components/parallel-timeline/parallel-timeline.js +251 -0
  82. package/dist/components/playback-ghost/index.js +6 -0
  83. package/dist/components/playback-ghost/playback-ghost.js +83 -0
  84. package/dist/components/policy-delivery-panel/index.js +6 -0
  85. package/dist/components/policy-delivery-panel/policy-delivery-panel.js +99 -0
  86. package/dist/components/presence-stack/index.js +6 -0
  87. package/dist/components/presence-stack/presence-stack.js +108 -0
  88. package/dist/components/presence-sync-indicator/index.js +6 -0
  89. package/dist/components/presence-sync-indicator/presence-sync-indicator.js +73 -0
  90. package/dist/components/pricing-table/index.js +8 -0
  91. package/dist/components/pricing-table/pricing-table.js +247 -0
  92. package/dist/components/primary-source-viewer/index.js +26 -0
  93. package/dist/components/primary-source-viewer/primary-source-viewer.js +439 -0
  94. package/dist/components/prompt-templates/index.js +6 -0
  95. package/dist/components/prompt-templates/prompt-templates.js +403 -0
  96. package/dist/components/property-section/index.js +6 -0
  97. package/dist/components/property-section/property-section.js +101 -0
  98. package/dist/components/relationship-inspector/index.js +6 -0
  99. package/dist/components/relationship-inspector/relationship-inspector.js +102 -0
  100. package/dist/components/route-map/index.js +6 -0
  101. package/dist/components/route-map/route-map.js +339 -0
  102. package/dist/components/routing-assignment-panel/index.js +6 -0
  103. package/dist/components/routing-assignment-panel/routing-assignment-panel.js +122 -0
  104. package/dist/components/run-timeline/index.js +6 -0
  105. package/dist/components/run-timeline/run-timeline.js +221 -0
  106. package/dist/components/runtime-overview-panel/index.js +6 -0
  107. package/dist/components/runtime-overview-panel/runtime-overview-panel.js +89 -0
  108. package/dist/components/selection-halo/index.js +6 -0
  109. package/dist/components/selection-halo/selection-halo.js +72 -0
  110. package/dist/components/selection-presence/index.js +6 -0
  111. package/dist/components/selection-presence/selection-presence.js +50 -0
  112. package/dist/components/snap-guides/index.js +6 -0
  113. package/dist/components/snap-guides/snap-guides.js +45 -0
  114. package/dist/components/state-badge-overlay/index.js +6 -0
  115. package/dist/components/state-badge-overlay/state-badge-overlay.js +90 -0
  116. package/dist/components/sticky-metric/index.js +6 -0
  117. package/dist/components/sticky-metric/sticky-metric.js +83 -0
  118. package/dist/components/story-map/index.js +8 -0
  119. package/dist/components/story-map/story-map.js +414 -0
  120. package/dist/components/thread-bubble/index.js +6 -0
  121. package/dist/components/thread-bubble/thread-bubble.js +85 -0
  122. package/dist/components/threshold-ring/index.js +6 -0
  123. package/dist/components/threshold-ring/threshold-ring.js +160 -0
  124. package/dist/components/timeline/index.js +12 -0
  125. package/dist/components/timeline/timeline.js +239 -0
  126. package/dist/components/timeline-scrubber/index.js +6 -0
  127. package/dist/components/timeline-scrubber/timeline-scrubber.js +179 -0
  128. package/dist/components/transaction-list/index.js +14 -0
  129. package/dist/components/transaction-list/transaction-list.js +226 -0
  130. package/dist/components/tree-view/index.js +6 -0
  131. package/dist/components/tree-view/tree-view.js +298 -0
  132. package/dist/components/viewport-bookmarks/index.js +6 -0
  133. package/dist/components/viewport-bookmarks/viewport-bookmarks.js +116 -0
  134. package/dist/components/world-breadcrumbs/index.js +6 -0
  135. package/dist/components/world-breadcrumbs/world-breadcrumbs.js +114 -0
  136. package/dist/index.d.ts +7135 -141
  137. package/package.json +1 -1
@@ -0,0 +1,422 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ createContext,
5
+ forwardRef,
6
+ useCallback,
7
+ useContext,
8
+ useMemo,
9
+ useState
10
+ } from "react";
11
+ import {
12
+ Check,
13
+ Copy,
14
+ Download,
15
+ Maximize2,
16
+ Minimize2,
17
+ Pencil
18
+ } from "lucide-react";
19
+ import { cn } from "../../lib/utils";
20
+ import { Badge } from "../badge/badge";
21
+ import { Button } from "../button/button";
22
+ const COPIED_TIMEOUT_MS = 2e3;
23
+ const DEFAULT_LABELS = {
24
+ copied: "Copied",
25
+ copy: "Copy",
26
+ download: "Download",
27
+ edit: "Edit",
28
+ enterFullscreen: "Enter fullscreen",
29
+ exitFullscreen: "Exit fullscreen",
30
+ versions: "Versions"
31
+ };
32
+ const NO_OP = () => {
33
+ return;
34
+ };
35
+ const DEFAULT_CONTEXT = {
36
+ copied: false,
37
+ copy: async () => false,
38
+ download: NO_OP,
39
+ filename: "artifact.txt",
40
+ fullscreen: false,
41
+ hasOnEdit: false,
42
+ labels: DEFAULT_LABELS,
43
+ onEdit: NO_OP,
44
+ toggleFullscreen: NO_OP,
45
+ type: "code",
46
+ value: ""
47
+ };
48
+ const AIArtifactContext = createContext(DEFAULT_CONTEXT);
49
+ function useAIArtifact() {
50
+ return useContext(AIArtifactContext);
51
+ }
52
+ function pickExtension(type, language) {
53
+ if (language) return language;
54
+ switch (type) {
55
+ case "code":
56
+ return "txt";
57
+ case "custom":
58
+ return "txt";
59
+ case "diagram":
60
+ return "mmd";
61
+ case "document":
62
+ return "md";
63
+ case "html":
64
+ return "html";
65
+ case "image":
66
+ return "png";
67
+ case "table":
68
+ return "csv";
69
+ }
70
+ }
71
+ const SLUG_INVALID_CHARS = /[^\da-z]+/g;
72
+ const SLUG_TRIM = /^-+|-+$/g;
73
+ function buildFilename({
74
+ filename,
75
+ language,
76
+ title,
77
+ type
78
+ }) {
79
+ if (filename) return filename;
80
+ const base = typeof title === "string" && title.length > 0 ? title : "artifact";
81
+ const slug = base.toLowerCase().replaceAll(SLUG_INVALID_CHARS, "-").replaceAll(SLUG_TRIM, "");
82
+ const safeBase = slug.length > 0 ? slug : "artifact";
83
+ return `${safeBase}.${pickExtension(type, language)}`;
84
+ }
85
+ async function writeToClipboard(value) {
86
+ if (typeof navigator === "undefined" || typeof navigator.clipboard?.writeText !== "function") {
87
+ return false;
88
+ }
89
+ try {
90
+ await navigator.clipboard.writeText(value);
91
+ return true;
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
96
+ function downloadValueAsFile(value, filename) {
97
+ if (typeof document === "undefined") return;
98
+ const blob = new Blob([value], { type: "text/plain;charset=utf-8" });
99
+ const url = URL.createObjectURL(blob);
100
+ const anchor = document.createElement("a");
101
+ anchor.href = url;
102
+ anchor.download = filename;
103
+ anchor.style.display = "none";
104
+ document.body.append(anchor);
105
+ anchor.click();
106
+ anchor.remove();
107
+ URL.revokeObjectURL(url);
108
+ }
109
+ function ArtifactHeader({
110
+ language,
111
+ subtitle,
112
+ title,
113
+ type
114
+ }) {
115
+ if (!title && !subtitle && !language) return null;
116
+ return /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-1", children: [
117
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
118
+ title ? /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold tracking-tight text-foreground", children: title }) : null,
119
+ /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: language || type })
120
+ ] }),
121
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: subtitle }) : null
122
+ ] });
123
+ }
124
+ function useArtifactController(options) {
125
+ const {
126
+ defaultFullscreen,
127
+ filename,
128
+ labels,
129
+ language,
130
+ onEdit,
131
+ title,
132
+ type,
133
+ value
134
+ } = options;
135
+ const [fullscreen, setFullscreen] = useState(defaultFullscreen);
136
+ const [copied, setCopied] = useState(false);
137
+ const resolvedFilename = useMemo(
138
+ () => buildFilename({ filename, language, title, type }),
139
+ [filename, language, title, type]
140
+ );
141
+ const copy = useCallback(async () => {
142
+ const ok = await writeToClipboard(value);
143
+ if (!ok) return false;
144
+ setCopied(true);
145
+ setTimeout(() => {
146
+ setCopied(false);
147
+ }, COPIED_TIMEOUT_MS);
148
+ return true;
149
+ }, [value]);
150
+ const download = useCallback(() => {
151
+ downloadValueAsFile(value, resolvedFilename);
152
+ }, [resolvedFilename, value]);
153
+ const toggleFullscreen = useCallback(() => {
154
+ setFullscreen((current) => !current);
155
+ }, []);
156
+ const triggerEdit = useCallback(() => {
157
+ onEdit?.();
158
+ }, [onEdit]);
159
+ return useMemo(
160
+ () => ({
161
+ copied,
162
+ copy,
163
+ download,
164
+ filename: resolvedFilename,
165
+ fullscreen,
166
+ hasOnEdit: onEdit !== void 0,
167
+ labels,
168
+ onEdit: triggerEdit,
169
+ toggleFullscreen,
170
+ type,
171
+ value
172
+ }),
173
+ [
174
+ copied,
175
+ copy,
176
+ download,
177
+ fullscreen,
178
+ labels,
179
+ onEdit,
180
+ resolvedFilename,
181
+ toggleFullscreen,
182
+ triggerEdit,
183
+ type,
184
+ value
185
+ ]
186
+ );
187
+ }
188
+ const AIArtifact = forwardRef(
189
+ (props, ref) => {
190
+ const {
191
+ children,
192
+ className,
193
+ defaultFullscreen = false,
194
+ filename,
195
+ labels,
196
+ language = "",
197
+ onEdit,
198
+ subtitle,
199
+ title,
200
+ type = "code",
201
+ value = "",
202
+ ...rest
203
+ } = props;
204
+ const resolvedLabels = useMemo(
205
+ () => ({ ...DEFAULT_LABELS, ...labels }),
206
+ [labels]
207
+ );
208
+ const contextValue = useArtifactController({
209
+ defaultFullscreen,
210
+ filename,
211
+ labels: resolvedLabels,
212
+ language,
213
+ onEdit,
214
+ title,
215
+ type,
216
+ value
217
+ });
218
+ return /* @__PURE__ */ jsx(AIArtifactContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
219
+ "section",
220
+ {
221
+ "aria-label": typeof title === "string" ? title : void 0,
222
+ className: cn(
223
+ "flex flex-col gap-3 rounded-2xl border bg-background p-4",
224
+ className
225
+ ),
226
+ "data-fullscreen": contextValue.fullscreen ? "true" : "false",
227
+ "data-type": type,
228
+ ref,
229
+ ...rest,
230
+ children: [
231
+ /* @__PURE__ */ jsx(
232
+ ArtifactHeader,
233
+ {
234
+ language,
235
+ subtitle,
236
+ title,
237
+ type
238
+ }
239
+ ),
240
+ children
241
+ ]
242
+ }
243
+ ) });
244
+ }
245
+ );
246
+ AIArtifact.displayName = "AIArtifact";
247
+ const AIArtifactToolbar = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(
248
+ "div",
249
+ {
250
+ className: cn(
251
+ "flex flex-wrap items-center gap-1.5 border-b border-border pb-2",
252
+ className
253
+ ),
254
+ ref,
255
+ role: "toolbar",
256
+ ...rest
257
+ }
258
+ ));
259
+ AIArtifactToolbar.displayName = "AIArtifactToolbar";
260
+ const AIArtifactCopyButton = forwardRef(({ className, onClick, ...rest }, ref) => {
261
+ const { copied, copy, labels } = useAIArtifact();
262
+ const handleClick = useCallback(
263
+ (event) => {
264
+ onClick?.(event);
265
+ if (event.defaultPrevented) return;
266
+ void copy();
267
+ },
268
+ [copy, onClick]
269
+ );
270
+ return /* @__PURE__ */ jsx(
271
+ Button,
272
+ {
273
+ "aria-label": copied ? labels.copied : labels.copy,
274
+ className: cn("h-8 w-8", className),
275
+ onClick: handleClick,
276
+ ref,
277
+ size: "icon",
278
+ type: "button",
279
+ variant: "ghost",
280
+ ...rest,
281
+ children: copied ? /* @__PURE__ */ jsx(Check, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": "true", className: "h-4 w-4" })
282
+ }
283
+ );
284
+ });
285
+ AIArtifactCopyButton.displayName = "AIArtifactCopyButton";
286
+ const AIArtifactEditButton = forwardRef(({ className, onClick, ...rest }, ref) => {
287
+ const { hasOnEdit, labels, onEdit } = useAIArtifact();
288
+ const handleClick = useCallback(
289
+ (event) => {
290
+ onClick?.(event);
291
+ if (event.defaultPrevented) return;
292
+ onEdit();
293
+ },
294
+ [onClick, onEdit]
295
+ );
296
+ if (!hasOnEdit) return null;
297
+ return /* @__PURE__ */ jsx(
298
+ Button,
299
+ {
300
+ "aria-label": labels.edit,
301
+ className: cn("h-8 w-8", className),
302
+ onClick: handleClick,
303
+ ref,
304
+ size: "icon",
305
+ type: "button",
306
+ variant: "ghost",
307
+ ...rest,
308
+ children: /* @__PURE__ */ jsx(Pencil, { "aria-hidden": "true", className: "h-4 w-4" })
309
+ }
310
+ );
311
+ });
312
+ AIArtifactEditButton.displayName = "AIArtifactEditButton";
313
+ const AIArtifactDownloadButton = forwardRef(({ className, onClick, ...rest }, ref) => {
314
+ const { download, labels } = useAIArtifact();
315
+ const handleClick = useCallback(
316
+ (event) => {
317
+ onClick?.(event);
318
+ if (event.defaultPrevented) return;
319
+ download();
320
+ },
321
+ [download, onClick]
322
+ );
323
+ return /* @__PURE__ */ jsx(
324
+ Button,
325
+ {
326
+ "aria-label": labels.download,
327
+ className: cn("h-8 w-8", className),
328
+ onClick: handleClick,
329
+ ref,
330
+ size: "icon",
331
+ type: "button",
332
+ variant: "ghost",
333
+ ...rest,
334
+ children: /* @__PURE__ */ jsx(Download, { "aria-hidden": "true", className: "h-4 w-4" })
335
+ }
336
+ );
337
+ });
338
+ AIArtifactDownloadButton.displayName = "AIArtifactDownloadButton";
339
+ const AIArtifactFullscreenButton = forwardRef(({ className, onClick, ...rest }, ref) => {
340
+ const { fullscreen, labels, toggleFullscreen } = useAIArtifact();
341
+ const handleClick = useCallback(
342
+ (event) => {
343
+ onClick?.(event);
344
+ if (event.defaultPrevented) return;
345
+ toggleFullscreen();
346
+ },
347
+ [onClick, toggleFullscreen]
348
+ );
349
+ return /* @__PURE__ */ jsx(
350
+ Button,
351
+ {
352
+ "aria-label": fullscreen ? labels.exitFullscreen : labels.enterFullscreen,
353
+ "aria-pressed": fullscreen,
354
+ className: cn("h-8 w-8", className),
355
+ onClick: handleClick,
356
+ ref,
357
+ size: "icon",
358
+ type: "button",
359
+ variant: "ghost",
360
+ ...rest,
361
+ children: fullscreen ? /* @__PURE__ */ jsx(Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
362
+ }
363
+ );
364
+ });
365
+ AIArtifactFullscreenButton.displayName = "AIArtifactFullscreenButton";
366
+ const AIArtifactContent = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(
367
+ "div",
368
+ {
369
+ className: cn(
370
+ "min-h-[6rem] overflow-auto rounded-lg border border-border bg-muted/20 p-3 text-sm text-foreground",
371
+ className
372
+ ),
373
+ ref,
374
+ ...rest
375
+ }
376
+ ));
377
+ AIArtifactContent.displayName = "AIArtifactContent";
378
+ const AIArtifactVersions = forwardRef(({ children, className, ...rest }, ref) => {
379
+ const { labels } = useAIArtifact();
380
+ return /* @__PURE__ */ jsx(
381
+ "nav",
382
+ {
383
+ "aria-label": labels.versions,
384
+ className: cn(
385
+ "flex flex-wrap items-center gap-1.5 border-t border-border pt-2",
386
+ className
387
+ ),
388
+ ref,
389
+ ...rest,
390
+ children
391
+ }
392
+ );
393
+ });
394
+ AIArtifactVersions.displayName = "AIArtifactVersions";
395
+ const AIArtifactVersion = forwardRef(({ active = false, className, label, ...rest }, ref) => /* @__PURE__ */ jsx(
396
+ "button",
397
+ {
398
+ "aria-current": active ? "true" : void 0,
399
+ className: cn(
400
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
401
+ active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-background text-muted-foreground hover:bg-accent",
402
+ className
403
+ ),
404
+ ref,
405
+ type: "button",
406
+ ...rest,
407
+ children: label
408
+ }
409
+ ));
410
+ AIArtifactVersion.displayName = "AIArtifactVersion";
411
+ export {
412
+ AIArtifact,
413
+ AIArtifactContent,
414
+ AIArtifactCopyButton,
415
+ AIArtifactDownloadButton,
416
+ AIArtifactEditButton,
417
+ AIArtifactFullscreenButton,
418
+ AIArtifactToolbar,
419
+ AIArtifactVersion,
420
+ AIArtifactVersions,
421
+ useAIArtifact
422
+ };
@@ -0,0 +1,24 @@
1
+ import {
2
+ AIArtifact,
3
+ AIArtifactContent,
4
+ AIArtifactCopyButton,
5
+ AIArtifactDownloadButton,
6
+ AIArtifactEditButton,
7
+ AIArtifactFullscreenButton,
8
+ AIArtifactToolbar,
9
+ AIArtifactVersion,
10
+ AIArtifactVersions,
11
+ useAIArtifact
12
+ } from "./ai-artifact";
13
+ export {
14
+ AIArtifact,
15
+ AIArtifactContent,
16
+ AIArtifactCopyButton,
17
+ AIArtifactDownloadButton,
18
+ AIArtifactEditButton,
19
+ AIArtifactFullscreenButton,
20
+ AIArtifactToolbar,
21
+ AIArtifactVersion,
22
+ AIArtifactVersions,
23
+ useAIArtifact
24
+ };
@@ -0,0 +1,254 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ createContext,
5
+ forwardRef,
6
+ useCallback,
7
+ useContext,
8
+ useEffect,
9
+ useMemo,
10
+ useState
11
+ } from "react";
12
+ import { Bot, MessageSquarePlus, X } from "lucide-react";
13
+ import { cn } from "../../lib/utils";
14
+ import { Button } from "../button/button";
15
+ const DEFAULT_WIDTH = 400;
16
+ const MIN_WIDTH = 280;
17
+ const MAX_WIDTH = 720;
18
+ const DEFAULT_LABELS = {
19
+ close: "Close assistant",
20
+ defaultTitle: "AI Assistant",
21
+ open: "Open AI assistant"
22
+ };
23
+ const NO_OP = () => {
24
+ return;
25
+ };
26
+ const DEFAULT_CONTEXT = {
27
+ close: NO_OP,
28
+ labels: DEFAULT_LABELS,
29
+ open: NO_OP,
30
+ openState: false,
31
+ position: "right",
32
+ setOpen: NO_OP,
33
+ toggle: NO_OP,
34
+ width: DEFAULT_WIDTH
35
+ };
36
+ const AISidebarContext = createContext(DEFAULT_CONTEXT);
37
+ function useAISidebar() {
38
+ return useContext(AISidebarContext);
39
+ }
40
+ function clampWidth(value) {
41
+ return Math.min(Math.max(value, MIN_WIDTH), MAX_WIDTH);
42
+ }
43
+ function AISidebarProvider({
44
+ children,
45
+ defaultOpen = false,
46
+ defaultPosition = "right",
47
+ defaultWidth = DEFAULT_WIDTH,
48
+ labels,
49
+ onOpenChange,
50
+ open: controlledOpen
51
+ }) {
52
+ const resolvedLabels = useMemo(
53
+ () => ({ ...DEFAULT_LABELS, ...labels }),
54
+ [labels]
55
+ );
56
+ const [uncontrolled, setUncontrolled] = useState(defaultOpen);
57
+ const isControlled = controlledOpen !== void 0;
58
+ const openState = isControlled ? controlledOpen : uncontrolled;
59
+ const setOpen = useCallback(
60
+ (next) => {
61
+ if (!isControlled) setUncontrolled(next);
62
+ onOpenChange?.(next);
63
+ },
64
+ [isControlled, onOpenChange]
65
+ );
66
+ const open = useCallback(() => {
67
+ setOpen(true);
68
+ }, [setOpen]);
69
+ const close = useCallback(() => {
70
+ setOpen(false);
71
+ }, [setOpen]);
72
+ const toggle = useCallback(() => {
73
+ setOpen(!openState);
74
+ }, [openState, setOpen]);
75
+ const value = useMemo(
76
+ () => ({
77
+ close,
78
+ labels: resolvedLabels,
79
+ open,
80
+ openState,
81
+ position: defaultPosition,
82
+ setOpen,
83
+ toggle,
84
+ width: clampWidth(defaultWidth)
85
+ }),
86
+ [
87
+ close,
88
+ defaultPosition,
89
+ defaultWidth,
90
+ open,
91
+ openState,
92
+ resolvedLabels,
93
+ setOpen,
94
+ toggle
95
+ ]
96
+ );
97
+ return /* @__PURE__ */ jsx(AISidebarContext.Provider, { value, children });
98
+ }
99
+ function useEscapeToClose(enabled, isOpen, onClose) {
100
+ useEffect(() => {
101
+ if (!enabled || !isOpen) return;
102
+ const handler = (event) => {
103
+ if (event.key === "Escape") onClose();
104
+ };
105
+ document.addEventListener("keydown", handler);
106
+ return () => {
107
+ document.removeEventListener("keydown", handler);
108
+ };
109
+ }, [enabled, isOpen, onClose]);
110
+ }
111
+ const AISidebar = forwardRef(
112
+ (props, ref) => {
113
+ const { children, className, closeOnEscape = true, ...rest } = props;
114
+ const { close, labels, openState, position, width } = useAISidebar();
115
+ useEscapeToClose(closeOnEscape, openState, close);
116
+ return /* @__PURE__ */ jsx(
117
+ "aside",
118
+ {
119
+ "aria-hidden": !openState,
120
+ "aria-label": labels.defaultTitle,
121
+ className: cn(
122
+ "fixed top-0 z-40 flex h-full flex-col border-border bg-background shadow-lg transition-transform duration-200 ease-out",
123
+ position === "right" ? "right-0 border-l" : "left-0 border-r",
124
+ openState ? "translate-x-0" : position === "right" ? "translate-x-full" : "-translate-x-full",
125
+ "max-w-full",
126
+ className
127
+ ),
128
+ "data-state": openState ? "open" : "closed",
129
+ ref,
130
+ style: { width: `${width.toString()}px` },
131
+ ...rest,
132
+ children
133
+ }
134
+ );
135
+ }
136
+ );
137
+ AISidebar.displayName = "AISidebar";
138
+ const AISidebarHeader = forwardRef(({ children, className, ...rest }, ref) => /* @__PURE__ */ jsx(
139
+ "header",
140
+ {
141
+ className: cn(
142
+ "flex items-center gap-2 border-b border-border px-4 py-3",
143
+ className
144
+ ),
145
+ ref,
146
+ ...rest,
147
+ children
148
+ }
149
+ ));
150
+ AISidebarHeader.displayName = "AISidebarHeader";
151
+ const AISidebarTitle = forwardRef(({ children, className, ...rest }, ref) => {
152
+ const { labels } = useAISidebar();
153
+ return /* @__PURE__ */ jsxs(
154
+ "h2",
155
+ {
156
+ className: cn(
157
+ "flex flex-1 items-center gap-2 text-sm font-semibold tracking-tight text-foreground",
158
+ className
159
+ ),
160
+ ref,
161
+ ...rest,
162
+ children: [
163
+ /* @__PURE__ */ jsx(Bot, { "aria-hidden": "true", className: "h-4 w-4 text-muted-foreground" }),
164
+ children ?? labels.defaultTitle
165
+ ]
166
+ }
167
+ );
168
+ });
169
+ AISidebarTitle.displayName = "AISidebarTitle";
170
+ const AISidebarClose = forwardRef(({ className, onClick, ...rest }, ref) => {
171
+ const { close, labels } = useAISidebar();
172
+ const handleClick = useCallback(
173
+ (event) => {
174
+ onClick?.(event);
175
+ if (event.defaultPrevented) return;
176
+ close();
177
+ },
178
+ [close, onClick]
179
+ );
180
+ return /* @__PURE__ */ jsx(
181
+ Button,
182
+ {
183
+ "aria-label": labels.close,
184
+ className: cn("h-8 w-8", className),
185
+ onClick: handleClick,
186
+ ref,
187
+ size: "icon",
188
+ type: "button",
189
+ variant: "ghost",
190
+ ...rest,
191
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "h-4 w-4" })
192
+ }
193
+ );
194
+ });
195
+ AISidebarClose.displayName = "AISidebarClose";
196
+ const AISidebarContent = forwardRef(({ children, className, ...rest }, ref) => /* @__PURE__ */ jsx(
197
+ "div",
198
+ {
199
+ className: cn("flex flex-1 flex-col gap-2 overflow-y-auto p-4", className),
200
+ ref,
201
+ ...rest,
202
+ children
203
+ }
204
+ ));
205
+ AISidebarContent.displayName = "AISidebarContent";
206
+ const AISidebarFooter = forwardRef(({ children, className, ...rest }, ref) => /* @__PURE__ */ jsx(
207
+ "footer",
208
+ {
209
+ className: cn("border-t border-border bg-background px-4 py-3", className),
210
+ ref,
211
+ ...rest,
212
+ children
213
+ }
214
+ ));
215
+ AISidebarFooter.displayName = "AISidebarFooter";
216
+ const AISidebarTrigger = forwardRef(({ children, className, onClick, ...rest }, ref) => {
217
+ const { labels, openState, toggle } = useAISidebar();
218
+ const handleClick = useCallback(
219
+ (event) => {
220
+ onClick?.(event);
221
+ if (event.defaultPrevented) return;
222
+ toggle();
223
+ },
224
+ [onClick, toggle]
225
+ );
226
+ return /* @__PURE__ */ jsx(
227
+ Button,
228
+ {
229
+ "aria-expanded": openState,
230
+ "aria-label": children ? void 0 : labels.open,
231
+ className: cn(className),
232
+ "data-state": openState ? "open" : "closed",
233
+ onClick: handleClick,
234
+ ref,
235
+ size: children ? "sm" : "icon",
236
+ type: "button",
237
+ variant: "outline",
238
+ ...rest,
239
+ children: children ?? /* @__PURE__ */ jsx(MessageSquarePlus, { "aria-hidden": "true", className: "h-4 w-4" })
240
+ }
241
+ );
242
+ });
243
+ AISidebarTrigger.displayName = "AISidebarTrigger";
244
+ export {
245
+ AISidebar,
246
+ AISidebarClose,
247
+ AISidebarContent,
248
+ AISidebarFooter,
249
+ AISidebarHeader,
250
+ AISidebarProvider,
251
+ AISidebarTitle,
252
+ AISidebarTrigger,
253
+ useAISidebar
254
+ };
@@ -0,0 +1,22 @@
1
+ import {
2
+ AISidebar,
3
+ AISidebarClose,
4
+ AISidebarContent,
5
+ AISidebarFooter,
6
+ AISidebarHeader,
7
+ AISidebarProvider,
8
+ AISidebarTitle,
9
+ AISidebarTrigger,
10
+ useAISidebar
11
+ } from "./ai-sidebar";
12
+ export {
13
+ AISidebar,
14
+ AISidebarClose,
15
+ AISidebarContent,
16
+ AISidebarFooter,
17
+ AISidebarHeader,
18
+ AISidebarProvider,
19
+ AISidebarTitle,
20
+ AISidebarTrigger,
21
+ useAISidebar
22
+ };