@arbidocs/blocks 0.4.4 → 0.4.5

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 (64) hide show
  1. package/README.md +25 -0
  2. package/dist/agents/index.cjs +163 -163
  3. package/dist/agents/index.js +6 -6
  4. package/dist/artifacts/ArtifactCompareBar.d.ts +33 -0
  5. package/dist/artifacts/ArtifactEditor.d.ts +64 -0
  6. package/dist/artifacts/ArtifactEditorBody.d.ts +34 -0
  7. package/dist/artifacts/ArtifactRedlineView.d.ts +57 -0
  8. package/dist/artifacts/ArtifactToolbar.d.ts +53 -0
  9. package/dist/artifacts/ArtifactVersionBar.d.ts +42 -0
  10. package/dist/{files → artifacts}/RedlineParts.d.ts +4 -0
  11. package/dist/artifacts/editor/ArtifactMarkdownEditor.d.ts +39 -0
  12. package/dist/artifacts/editor/index.cjs +89 -0
  13. package/dist/artifacts/editor/index.cjs.map +1 -0
  14. package/dist/artifacts/editor/index.d.ts +1 -0
  15. package/dist/artifacts/editor/index.js +86 -0
  16. package/dist/artifacts/editor/index.js.map +1 -0
  17. package/dist/artifacts/index.cjs +807 -0
  18. package/dist/artifacts/index.cjs.map +1 -0
  19. package/dist/artifacts/index.d.ts +8 -0
  20. package/dist/artifacts/index.js +787 -0
  21. package/dist/artifacts/index.js.map +1 -0
  22. package/dist/chat/index.cjs +54 -54
  23. package/dist/chat/index.js +2 -2
  24. package/dist/{chunk-XKKGGUU2.cjs → chunk-3MIQASHO.cjs} +4 -4
  25. package/dist/{chunk-XKKGGUU2.cjs.map → chunk-3MIQASHO.cjs.map} +1 -1
  26. package/dist/{chunk-B673CCW5.js → chunk-3PJCET7H.js} +3 -3
  27. package/dist/{chunk-B673CCW5.js.map → chunk-3PJCET7H.js.map} +1 -1
  28. package/dist/{chunk-DGVKBOY5.cjs → chunk-3PZPRAAR.cjs} +14 -14
  29. package/dist/{chunk-DGVKBOY5.cjs.map → chunk-3PZPRAAR.cjs.map} +1 -1
  30. package/dist/{chunk-BBEMPS6C.js → chunk-5XTZFH65.js} +6 -6
  31. package/dist/{chunk-BBEMPS6C.js.map → chunk-5XTZFH65.js.map} +1 -1
  32. package/dist/{chunk-JPO3F4J7.js → chunk-6YHWXMPQ.js} +3 -3
  33. package/dist/{chunk-JPO3F4J7.js.map → chunk-6YHWXMPQ.js.map} +1 -1
  34. package/dist/{chunk-ZVPTFTGV.cjs → chunk-MVNCQDDE.cjs} +4 -4
  35. package/dist/{chunk-ZVPTFTGV.cjs.map → chunk-MVNCQDDE.cjs.map} +1 -1
  36. package/dist/{chunk-NJL4LIXX.js → chunk-NPKGUQU5.js} +4 -4
  37. package/dist/{chunk-NJL4LIXX.js.map → chunk-NPKGUQU5.js.map} +1 -1
  38. package/dist/{chunk-ATXPAD6S.cjs → chunk-YLOKCIQJ.cjs} +3 -3
  39. package/dist/{chunk-ATXPAD6S.cjs.map → chunk-YLOKCIQJ.cjs.map} +1 -1
  40. package/dist/connect/index.cjs +18 -18
  41. package/dist/connect/index.js +4 -4
  42. package/dist/facts/index.cjs +1 -1
  43. package/dist/facts/index.js +1 -1
  44. package/dist/files/ViewerChrome.d.ts +0 -45
  45. package/dist/files/ViewerParts.d.ts +0 -19
  46. package/dist/files/index.cjs +4 -436
  47. package/dist/files/index.cjs.map +1 -1
  48. package/dist/files/index.d.ts +2 -4
  49. package/dist/files/index.js +8 -428
  50. package/dist/files/index.js.map +1 -1
  51. package/dist/home/index.cjs +19 -19
  52. package/dist/home/index.js +4 -4
  53. package/dist/index.cjs +415 -415
  54. package/dist/index.js +14 -14
  55. package/dist/settings/index.cjs +3 -3
  56. package/dist/settings/index.js +4 -4
  57. package/dist/shell/index.cjs +10 -10
  58. package/dist/shell/index.js +2 -2
  59. package/dist/site/index.cjs +5 -5
  60. package/dist/site/index.js +1 -1
  61. package/dist/studio/index.cjs +8 -8
  62. package/dist/studio/index.js +6 -6
  63. package/package.json +25 -4
  64. /package/dist/{files → artifacts}/VersionTimeline.d.ts +0 -0
@@ -0,0 +1,807 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkMHVNT4J3_cjs = require('../chunk-MHVNT4J3.cjs');
5
+ var ui = require('@arbidocs/react/ui');
6
+ var lucideReact = require('lucide-react');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+ var react = require('react');
9
+
10
+ var DEFAULT_ARTIFACT_COMPARE_BAR_LABELS = {
11
+ compareVs: "Compare vs.",
12
+ trackChanges: "Track changes",
13
+ trackChangesBack: "Back to editing (your comparison stays active)",
14
+ trackChangesView: "View tracked changes against Compare vs.",
15
+ flipComparison: "Flip comparison direction",
16
+ stopComparing: "Stop comparing"
17
+ };
18
+ var barButton = "inline-flex shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11 pointer-coarse:min-w-11 pointer-coarse:px-2.5";
19
+ function ArtifactCompareBar({
20
+ compareTarget,
21
+ versionLabel,
22
+ mode,
23
+ showTrackChanges,
24
+ onToggleTrackChanges,
25
+ onFlip,
26
+ onStop,
27
+ labels,
28
+ testIds
29
+ }) {
30
+ const l = { ...DEFAULT_ARTIFACT_COMPARE_BAR_LABELS, ...labels };
31
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
32
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-sm text-muted-foreground", children: l.compareVs }),
33
+ compareTarget,
34
+ versionLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: versionLabel }),
35
+ mode === "track-changes" ? /* @__PURE__ */ jsxRuntime.jsxs(
36
+ "button",
37
+ {
38
+ type: "button",
39
+ onClick: onToggleTrackChanges,
40
+ "aria-pressed": showTrackChanges,
41
+ className: ui.cn(
42
+ barButton,
43
+ showTrackChanges ? "bg-accent text-accent-foreground hover:bg-accent/70" : "text-muted-foreground hover:bg-muted hover:text-foreground"
44
+ ),
45
+ title: showTrackChanges ? l.trackChangesBack : l.trackChangesView,
46
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.trackChanges, { testId: "track-changes-toggle" }),
47
+ children: [
48
+ showTrackChanges ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "size-3.5", "aria-hidden": true }),
49
+ l.trackChanges
50
+ ]
51
+ }
52
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
53
+ "button",
54
+ {
55
+ type: "button",
56
+ onClick: onFlip,
57
+ className: ui.cn(
58
+ barButton,
59
+ "p-1 text-muted-foreground hover:bg-muted hover:text-foreground"
60
+ ),
61
+ title: l.flipComparison,
62
+ "aria-label": l.flipComparison,
63
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeftRight, { className: "size-3.5", "aria-hidden": true })
64
+ }
65
+ ),
66
+ /* @__PURE__ */ jsxRuntime.jsxs(
67
+ "button",
68
+ {
69
+ type: "button",
70
+ onClick: onStop,
71
+ className: ui.cn(
72
+ barButton,
73
+ "ml-auto text-muted-foreground hover:bg-muted hover:text-foreground"
74
+ ),
75
+ title: l.stopComparing,
76
+ children: [
77
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3", "aria-hidden": true }),
78
+ l.stopComparing
79
+ ]
80
+ }
81
+ )
82
+ ] });
83
+ }
84
+ function ArtifactEditorBody({
85
+ content,
86
+ isEditing,
87
+ comparing,
88
+ showTrackChanges,
89
+ editor,
90
+ redline,
91
+ renderMarkdown,
92
+ onSave,
93
+ canSave = true,
94
+ className,
95
+ testIds
96
+ }) {
97
+ const onKeyDown = react.useCallback(
98
+ (e) => {
99
+ if (!isEditing || !onSave) return;
100
+ if ((e.metaKey || e.ctrlKey) && !e.altKey && e.key.toLowerCase() === "s") {
101
+ e.preventDefault();
102
+ if (canSave) onSave();
103
+ }
104
+ },
105
+ [isEditing, onSave, canSave]
106
+ );
107
+ const tracking = isEditing && comparing && showTrackChanges;
108
+ return (
109
+ // The key handler only listens to bubbling keystrokes of the editor inside; the editor itself
110
+ // is the focusable element.
111
+ /* @__PURE__ */ jsxRuntime.jsx(
112
+ "div",
113
+ {
114
+ "data-slot": "artifact-body",
115
+ className: ui.cn("h-full min-h-0 overflow-auto", className),
116
+ onKeyDown,
117
+ children: !isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
118
+ "div",
119
+ {
120
+ className: "p-6",
121
+ "data-slot": "artifact-rendered",
122
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.rendered, { testId: "document-rendered-markdown" }),
123
+ children: renderMarkdown(content)
124
+ }
125
+ ) : tracking ? /* @__PURE__ */ jsxRuntime.jsx(
126
+ "div",
127
+ {
128
+ className: "h-full",
129
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.trackChanges, { testId: "track-changes-panel" }),
130
+ children: redline
131
+ }
132
+ ) : editor
133
+ }
134
+ )
135
+ );
136
+ }
137
+ var DEFAULT_ARTIFACT_TOOLBAR_LABELS = {
138
+ group: "Document actions",
139
+ edit: "Edit",
140
+ cancel: "Cancel",
141
+ cancelTitle: "Cancel editing",
142
+ compare: "Compare",
143
+ compareTitle: "Compare against the previous version",
144
+ saveDocument: "Save document",
145
+ saveAsVersion: "Save as a new version",
146
+ noChanges: "No changes to save",
147
+ saving: "Saving\u2026",
148
+ save: "Save",
149
+ saveVersion: "Save version",
150
+ unsaved: "Unsaved changes"
151
+ };
152
+ function ArtifactToolbar({
153
+ isEditing,
154
+ isDraft = false,
155
+ compact = false,
156
+ hasChanges,
157
+ isSaving,
158
+ canCompare,
159
+ onStartEdit,
160
+ onCancel,
161
+ onCompare,
162
+ onSave,
163
+ className,
164
+ labels,
165
+ testIds
166
+ }) {
167
+ const l = { ...DEFAULT_ARTIFACT_TOOLBAR_LABELS, ...labels };
168
+ const group = (children) => /* @__PURE__ */ jsxRuntime.jsx(
169
+ "div",
170
+ {
171
+ role: "group",
172
+ "aria-label": l.group,
173
+ "data-slot": "artifact-toolbar",
174
+ className: ui.cn("flex items-center gap-2", compact && "gap-1", className),
175
+ children
176
+ }
177
+ );
178
+ if (!isEditing) {
179
+ return group(
180
+ /* @__PURE__ */ jsxRuntime.jsxs(
181
+ ui.Button,
182
+ {
183
+ onClick: onStartEdit,
184
+ variant: "outline",
185
+ size: compact ? "icon" : "sm",
186
+ title: l.edit,
187
+ "aria-label": l.edit,
188
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.edit, { testId: "edit-document-button" }),
189
+ className: "pointer-coarse:min-h-11 pointer-coarse:min-w-11",
190
+ children: [
191
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "size-4", "aria-hidden": true }),
192
+ !compact && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: l.edit })
193
+ ]
194
+ }
195
+ )
196
+ );
197
+ }
198
+ return group(
199
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
200
+ !isDraft && /* @__PURE__ */ jsxRuntime.jsxs(
201
+ ui.Button,
202
+ {
203
+ onClick: onCancel,
204
+ variant: "outline",
205
+ size: "sm",
206
+ title: l.cancelTitle,
207
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.cancel, { testId: "cancel-edit-button" }),
208
+ className: "pointer-coarse:min-h-11",
209
+ children: [
210
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4", "aria-hidden": true }),
211
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: l.cancel })
212
+ ]
213
+ }
214
+ ),
215
+ canCompare && /* @__PURE__ */ jsxRuntime.jsxs(
216
+ ui.Button,
217
+ {
218
+ onClick: onCompare,
219
+ variant: "outline",
220
+ size: compact ? "icon" : "sm",
221
+ title: l.compareTitle,
222
+ "aria-label": l.compare,
223
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.compare, { testId: "compare-button" }),
224
+ className: "pointer-coarse:min-h-11 pointer-coarse:min-w-11",
225
+ children: [
226
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitCompare, { className: "size-4", "aria-hidden": true }),
227
+ !compact && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: l.compare })
228
+ ]
229
+ }
230
+ ),
231
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
232
+ /* @__PURE__ */ jsxRuntime.jsxs(
233
+ ui.Button,
234
+ {
235
+ onClick: onSave,
236
+ variant: hasChanges ? "default" : "outline",
237
+ size: "sm",
238
+ title: hasChanges ? isDraft ? l.saveDocument : l.saveAsVersion : l.noChanges,
239
+ disabled: !hasChanges || isSaving,
240
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.save, { testId: "save-document-button" }),
241
+ className: "pointer-coarse:min-h-11",
242
+ children: [
243
+ isSaving ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-4", "aria-hidden": true }),
244
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: isSaving ? l.saving : isDraft ? l.save : l.saveVersion })
245
+ ]
246
+ }
247
+ ),
248
+ hasChanges && !isSaving && /* @__PURE__ */ jsxRuntime.jsx(
249
+ "span",
250
+ {
251
+ className: "absolute -right-1 -top-1 size-2.5 rounded-full bg-primary ring-2 ring-background",
252
+ "aria-hidden": true,
253
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.unsavedDot, { testId: "unsaved-changes-dot" })
254
+ }
255
+ )
256
+ ] }),
257
+ /* @__PURE__ */ jsxRuntime.jsx("span", { role: "status", className: "sr-only", children: hasChanges && !isSaving ? l.unsaved : "" })
258
+ ] })
259
+ );
260
+ }
261
+ var DEFAULT_ARTIFACT_VERSION_BAR_LABELS = {
262
+ group: "Versions",
263
+ position: (index, total) => `Version ${index} of ${total}`,
264
+ only: "Version 1",
265
+ latest: "Latest",
266
+ select: "Open a version",
267
+ option: (index, date, isCurrent) => `Version ${index} \xB7 ${date}${isCurrent ? " (open)" : ""}`,
268
+ compare: "Compare with previous",
269
+ compareTitle: "Compare this version against the one it was saved from"
270
+ };
271
+ function ArtifactVersionBar({
272
+ versions,
273
+ currentId,
274
+ formatDate,
275
+ onOpen,
276
+ onCompare,
277
+ className,
278
+ labels,
279
+ testIds
280
+ }) {
281
+ const l = { ...DEFAULT_ARTIFACT_VERSION_BAR_LABELS, ...labels };
282
+ const index = versions.findIndex((v) => v.id === currentId);
283
+ const isLatest = index === versions.length - 1;
284
+ return /* @__PURE__ */ jsxRuntime.jsxs(
285
+ "div",
286
+ {
287
+ role: "group",
288
+ "aria-label": l.group,
289
+ "data-slot": "artifact-version-bar",
290
+ className: ui.cn("flex min-w-0 flex-wrap items-center gap-2 text-sm", className),
291
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "artifact-version-bar" }),
292
+ children: [
293
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
294
+ /* @__PURE__ */ jsxRuntime.jsx(
295
+ "span",
296
+ {
297
+ className: "shrink-0 font-medium text-foreground",
298
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.position, { testId: "artifact-version-position" }),
299
+ children: versions.length > 1 && index >= 0 ? l.position(index + 1, versions.length) : l.only
300
+ }
301
+ ),
302
+ versions.length > 1 && index >= 0 && isLatest && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded-full bg-accent px-2 py-0.5 text-xs font-medium text-accent-foreground", children: l.latest }),
303
+ versions.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
304
+ "select",
305
+ {
306
+ "aria-label": l.select,
307
+ value: currentId,
308
+ onChange: (e) => onOpen(e.target.value),
309
+ className: "min-w-0 max-w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11 pointer-coarse:text-base",
310
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.select, { testId: "artifact-version-select" }),
311
+ children: versions.map((v, i) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: v.id, children: l.option(i + 1, formatDate(v.createdAt), v.id === currentId) }, v.id))
312
+ }
313
+ ),
314
+ onCompare && /* @__PURE__ */ jsxRuntime.jsxs(
315
+ ui.Button,
316
+ {
317
+ variant: "ghost",
318
+ size: "sm",
319
+ onClick: onCompare,
320
+ title: l.compareTitle,
321
+ className: "pointer-coarse:min-h-11",
322
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.compare, { testId: "artifact-version-compare" }),
323
+ children: [
324
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitCompare, { className: "size-4", "aria-hidden": true }),
325
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: l.compare })
326
+ ]
327
+ }
328
+ )
329
+ ]
330
+ }
331
+ );
332
+ }
333
+ var defaultFormatDate = (iso) => {
334
+ const date = new Date(iso);
335
+ return Number.isNaN(date.getTime()) ? iso : date.toLocaleString();
336
+ };
337
+ function ArtifactEditor({
338
+ content,
339
+ isEditing,
340
+ hasChanges,
341
+ isSaving,
342
+ isDraft = false,
343
+ compact = false,
344
+ canCompare,
345
+ comparing,
346
+ compareId,
347
+ showTrackChanges,
348
+ versions = [],
349
+ currentVersionId = "",
350
+ onStartEdit,
351
+ onCancel,
352
+ onSave,
353
+ onCompare,
354
+ onStopCompare,
355
+ onToggleTrackChanges,
356
+ onOpenVersion,
357
+ formatDate = defaultFormatDate,
358
+ editor,
359
+ redline,
360
+ renderMarkdown,
361
+ actions,
362
+ className,
363
+ labels,
364
+ testIds
365
+ }) {
366
+ const compared = versions.findIndex((v) => v.id === compareId);
367
+ return /* @__PURE__ */ jsxRuntime.jsxs(
368
+ "div",
369
+ {
370
+ "data-slot": "artifact-editor",
371
+ className: ui.cn("flex h-full max-h-dvh min-h-0 flex-col bg-background", className),
372
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "artifact-editor" }),
373
+ children: [
374
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 border-b border-border px-3 py-2", children: [
375
+ versions.length > 0 && onOpenVersion ? /* @__PURE__ */ jsxRuntime.jsx(
376
+ ArtifactVersionBar,
377
+ {
378
+ versions,
379
+ currentId: currentVersionId,
380
+ formatDate,
381
+ onOpen: onOpenVersion,
382
+ onCompare: canCompare ? onCompare : void 0,
383
+ labels: labels?.versions,
384
+ testIds: testIds?.versions
385
+ }
386
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
387
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
388
+ /* @__PURE__ */ jsxRuntime.jsx(
389
+ ArtifactToolbar,
390
+ {
391
+ isEditing,
392
+ isDraft,
393
+ compact,
394
+ hasChanges,
395
+ isSaving,
396
+ canCompare: canCompare && !(versions.length > 0 && onOpenVersion),
397
+ onStartEdit,
398
+ onCancel,
399
+ onCompare,
400
+ onSave,
401
+ labels: labels?.toolbar
402
+ }
403
+ ),
404
+ actions
405
+ ] })
406
+ ] }),
407
+ comparing && /* @__PURE__ */ jsxRuntime.jsx(
408
+ "div",
409
+ {
410
+ className: "flex flex-wrap items-center gap-1.5 border-b border-border px-3 py-1.5",
411
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.compareRow, { testId: "artifact-compare-row" }),
412
+ children: /* @__PURE__ */ jsxRuntime.jsx(
413
+ ArtifactCompareBar,
414
+ {
415
+ compareTarget: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate text-sm font-medium text-foreground", children: compared >= 0 ? versions[compared].name : "" }),
416
+ versionLabel: compared >= 0 && versions.length > 1 ? `v${compared + 1}` : null,
417
+ mode: "track-changes",
418
+ showTrackChanges,
419
+ onToggleTrackChanges,
420
+ onFlip: onStopCompare,
421
+ onStop: onStopCompare,
422
+ labels: labels?.compare
423
+ }
424
+ )
425
+ }
426
+ ),
427
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
428
+ ArtifactEditorBody,
429
+ {
430
+ content,
431
+ isEditing,
432
+ comparing,
433
+ showTrackChanges,
434
+ editor,
435
+ redline,
436
+ renderMarkdown,
437
+ onSave,
438
+ canSave: hasChanges && !isSaving,
439
+ testIds: testIds?.body
440
+ }
441
+ ) })
442
+ ]
443
+ }
444
+ );
445
+ }
446
+ var DEFAULT_REDLINE_LABELS = {
447
+ flipComparison: "Flip comparison",
448
+ noDocument: "No document selected for comparison.",
449
+ noChangesYet: "No changes yet \u2014 start editing to see redlined differences here.",
450
+ identical: "Documents are identical.",
451
+ unavailable: "Document text not available for comparison.",
452
+ revertMove: "Undo this move (revert both ends)",
453
+ revertReplace: "Undo this edit",
454
+ revertAdd: "Undo this insertion",
455
+ revertRemove: "Undo this deletion",
456
+ tracked: "Tracked changes",
457
+ computing: "Comparing\u2026"
458
+ };
459
+ function RedlineFrame({ header, children }) {
460
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col", "data-slot": "redline-frame", children: [
461
+ header,
462
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto text-sm leading-relaxed", children })
463
+ ] });
464
+ }
465
+ function RedlineHeader({ base, compare, onFlip, labels }) {
466
+ const l = { ...DEFAULT_REDLINE_LABELS, ...labels };
467
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-border bg-muted px-3 py-2", children: [
468
+ base,
469
+ /* @__PURE__ */ jsxRuntime.jsx(
470
+ ui.Button,
471
+ {
472
+ variant: "ghost",
473
+ size: "icon",
474
+ className: "size-6 shrink-0 pointer-coarse:size-11",
475
+ onClick: onFlip,
476
+ title: l.flipComparison,
477
+ "aria-label": l.flipComparison,
478
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeftRight, { className: "size-3.5" })
479
+ }
480
+ ),
481
+ compare
482
+ ] });
483
+ }
484
+ function RedlineStatus({
485
+ kind,
486
+ reviewMode,
487
+ labels
488
+ }) {
489
+ const l = { ...DEFAULT_REDLINE_LABELS, ...labels };
490
+ const text = kind === "idle" ? l.noDocument : kind === "identical" ? reviewMode ? l.noChangesYet : l.identical : l.unavailable;
491
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-sm text-muted-foreground", children: text });
492
+ }
493
+ function RedlineComputing({ children }) {
494
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children });
495
+ }
496
+ function RedlineDocument({ children, bodyRef, gutter }) {
497
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
498
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: bodyRef, className: "mx-auto max-w-3xl px-6 py-4 pr-14", children }),
499
+ gutter
500
+ ] });
501
+ }
502
+ var MARK_TONE = {
503
+ del: {
504
+ base: "font-semibold text-red-600 line-through decoration-2 dark:text-red-400",
505
+ move: "font-semibold text-emerald-600 line-through decoration-2 dark:text-emerald-400"
506
+ },
507
+ ins: {
508
+ base: "font-semibold text-blue-600 underline decoration-2 dark:text-blue-400",
509
+ move: "font-semibold text-emerald-600 underline decoration-2 dark:text-emerald-400"
510
+ }
511
+ };
512
+ function RedlineMark({
513
+ as: Tag,
514
+ isMove,
515
+ children,
516
+ ...props
517
+ }) {
518
+ const cls = MARK_TONE[Tag][isMove ? "move" : "base"];
519
+ return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className: cls, ...props, children });
520
+ }
521
+ var REVERT_TONE = {
522
+ move: "border-emerald-600 text-emerald-700 hover:bg-emerald-50 dark:border-emerald-400 dark:text-emerald-300 dark:hover:bg-emerald-950/40",
523
+ add: "border-blue-600 text-blue-700 hover:bg-blue-50 dark:border-blue-400 dark:text-blue-300 dark:hover:bg-blue-950/40",
524
+ replace: "border-blue-600 text-blue-700 hover:bg-blue-50 dark:border-blue-400 dark:text-blue-300 dark:hover:bg-blue-950/40",
525
+ remove: "border-red-600 text-red-700 hover:bg-red-50 dark:border-red-400 dark:text-red-300 dark:hover:bg-red-950/40"
526
+ };
527
+ function RedlineRevertGutter({
528
+ markers,
529
+ onRevert,
530
+ labels,
531
+ testId
532
+ }) {
533
+ if (markers.length === 0) return null;
534
+ const l = { ...DEFAULT_REDLINE_LABELS, ...labels };
535
+ const revertTitle = {
536
+ move: l.revertMove,
537
+ replace: l.revertReplace,
538
+ add: l.revertAdd,
539
+ remove: l.revertRemove
540
+ };
541
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute right-2 top-0 w-9", "data-slot": "redline-gutter", children: markers.map((m) => /* @__PURE__ */ jsxRuntime.jsx(
542
+ "button",
543
+ {
544
+ type: "button",
545
+ onClick: () => onRevert(m.cid),
546
+ title: revertTitle[m.kind],
547
+ "aria-label": revertTitle[m.kind],
548
+ style: { top: m.top - 2 },
549
+ className: ui.cn(
550
+ "pointer-events-auto absolute right-0 inline-flex h-6 w-7 items-center justify-center rounded-md border bg-background transition-colors pointer-coarse:h-11 pointer-coarse:w-11",
551
+ REVERT_TONE[m.kind]
552
+ ),
553
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId?.(m.cid), { testId: `redline-revert-${m.cid}` }),
554
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo2, { className: "size-3.5" })
555
+ },
556
+ m.cid
557
+ )) });
558
+ }
559
+ function kindFromCid(cid) {
560
+ switch (cid?.[0]) {
561
+ case "p":
562
+ return "replace";
563
+ case "r":
564
+ return "remove";
565
+ case "a":
566
+ return "add";
567
+ case "m":
568
+ return "move";
569
+ default:
570
+ return null;
571
+ }
572
+ }
573
+ var MARKER_MIN_GAP = 26;
574
+ function ArtifactRedlineView({
575
+ state,
576
+ renderMarkdown,
577
+ onRevert,
578
+ header,
579
+ labels,
580
+ testIds
581
+ }) {
582
+ const l = { ...DEFAULT_REDLINE_LABELS, ...labels };
583
+ const reviewMode = typeof onRevert === "function";
584
+ const bodyRef = react.useRef(null);
585
+ const [markers, setMarkers] = react.useState([]);
586
+ const regionKinds = react.useMemo(
587
+ () => state.kind === "ready" ? new Map(state.regions.map((r) => [r.id, r.kind])) : null,
588
+ [state]
589
+ );
590
+ const components = react.useMemo(() => {
591
+ const isMove = (cid) => (regionKinds?.get(cid ?? "") ?? kindFromCid(cid)) === "move";
592
+ return {
593
+ del: ({ children, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(RedlineMark, { as: "del", isMove: isMove(props["data-cid"]), ...props, children }),
594
+ ins: ({ children, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(RedlineMark, { as: "ins", isMove: isMove(props["data-cid"]), ...props, children })
595
+ };
596
+ }, [regionKinds]);
597
+ react.useLayoutEffect(() => {
598
+ const host = bodyRef.current;
599
+ if (!reviewMode || state.kind !== "ready" || !host) {
600
+ setMarkers([]);
601
+ return;
602
+ }
603
+ const hostTop = host.getBoundingClientRect().top;
604
+ const seen = /* @__PURE__ */ new Map();
605
+ host.querySelectorAll("[data-cid]").forEach((el) => {
606
+ const cid = el.dataset.cid;
607
+ if (!cid || seen.has(cid)) return;
608
+ seen.set(cid, {
609
+ top: el.getBoundingClientRect().top - hostTop,
610
+ kind: regionKinds?.get(cid) ?? kindFromCid(cid) ?? "replace"
611
+ });
612
+ });
613
+ const sorted = Array.from(seen, ([cid, v]) => ({ cid, ...v })).sort((a, b) => a.top - b.top);
614
+ const spaced = [];
615
+ for (const m of sorted) {
616
+ const prev = spaced[spaced.length - 1];
617
+ spaced.push({
618
+ ...m,
619
+ top: prev && m.top - prev.top < MARKER_MIN_GAP ? prev.top + MARKER_MIN_GAP : m.top
620
+ });
621
+ }
622
+ setMarkers(spaced);
623
+ }, [reviewMode, state, regionKinds]);
624
+ return /* @__PURE__ */ jsxRuntime.jsx(
625
+ "section",
626
+ {
627
+ "aria-label": l.tracked,
628
+ className: "h-full",
629
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "artifact-redline" }),
630
+ children: /* @__PURE__ */ jsxRuntime.jsx(RedlineFrame, { header, children: state.kind === "idle" || state.kind === "identical" || state.kind === "unavailable" ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsx(RedlineStatus, { kind: state.kind, reviewMode, labels }) }) : state.kind === "computing" ? /* @__PURE__ */ jsxRuntime.jsxs(RedlineComputing, { children: [
631
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-5 animate-spin text-muted-foreground", "aria-hidden": true }),
632
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", role: "status", children: l.computing })
633
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
634
+ RedlineDocument,
635
+ {
636
+ bodyRef,
637
+ gutter: reviewMode ? /* @__PURE__ */ jsxRuntime.jsx(
638
+ RedlineRevertGutter,
639
+ {
640
+ markers,
641
+ onRevert,
642
+ labels,
643
+ testId: testIds?.revert
644
+ }
645
+ ) : null,
646
+ children: renderMarkdown(state.markdown, components)
647
+ }
648
+ ) })
649
+ }
650
+ );
651
+ }
652
+ var DEFAULT_VERSION_TIMELINE_LABELS = {
653
+ emptyLive: "No earlier versions yet. When you ask the assistant for a change, the previous version is kept here.",
654
+ emptyDocument: "No earlier versions yet. Editing this draft and saving creates a new version here.",
655
+ untitled: "Untitled",
656
+ latest: "Latest",
657
+ viewing: "Viewing",
658
+ current: "Current",
659
+ version: (n) => `Version ${n}`,
660
+ branchedFrom: (n) => `branched from Version ${n}`,
661
+ open: "Open",
662
+ compare: "Compare"
663
+ };
664
+ function VersionTimeline({
665
+ versions,
666
+ currentId,
667
+ live = false,
668
+ formatDate,
669
+ onOpen,
670
+ onCompare,
671
+ className,
672
+ labels,
673
+ testIds
674
+ }) {
675
+ const l = { ...DEFAULT_VERSION_TIMELINE_LABELS, ...labels };
676
+ if (versions.length <= 1) {
677
+ return /* @__PURE__ */ jsxRuntime.jsx(
678
+ "div",
679
+ {
680
+ className: ui.cn("p-6 text-sm text-muted-foreground", className),
681
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.empty, { testId: "version-timeline-empty" }),
682
+ children: live ? l.emptyLive : l.emptyDocument
683
+ }
684
+ );
685
+ }
686
+ const numberById = /* @__PURE__ */ new Map();
687
+ versions.forEach((v, i) => numberById.set(v.id, i + 1));
688
+ const canCompare = !live && !!onCompare;
689
+ return /* @__PURE__ */ jsxRuntime.jsx(
690
+ "div",
691
+ {
692
+ className: ui.cn("h-full overflow-auto p-4", className),
693
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "version-timeline" }),
694
+ children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "mx-auto max-w-2xl space-y-1", children: versions.map((v, i) => {
695
+ const isCurrent = v.id === currentId;
696
+ const isLatest = i === versions.length - 1;
697
+ const parentNumber = v.parentId ? numberById.get(v.parentId) : void 0;
698
+ const branchedFrom = parentNumber !== void 0 && parentNumber !== i ? parentNumber : null;
699
+ const badge = !isCurrent ? null : live ? isLatest ? l.latest : l.viewing : l.current;
700
+ const name = live ? (v.name || l.untitled).replace(/\.[A-Za-z0-9]+$/, "") : v.name || l.untitled;
701
+ return /* @__PURE__ */ jsxRuntime.jsxs(
702
+ "li",
703
+ {
704
+ className: ui.cn(
705
+ "flex items-center gap-3 rounded-md px-3 py-2.5",
706
+ isCurrent && "bg-accent"
707
+ ),
708
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.row?.(v.id), { testId: `version-row-${v.id}` }),
709
+ children: [
710
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
711
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
712
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
713
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-foreground", children: l.version(i + 1) }),
714
+ badge && /* @__PURE__ */ jsxRuntime.jsx(
715
+ "span",
716
+ {
717
+ className: "rounded-full bg-background px-2 py-0.5 text-xs font-medium text-accent-foreground",
718
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.currentBadge, {
719
+ testId: "version-current-badge"
720
+ }),
721
+ children: badge
722
+ }
723
+ )
724
+ ] }),
725
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "truncate text-sm text-muted-foreground", children: [
726
+ name,
727
+ " \xB7 ",
728
+ formatDate(v.createdAt),
729
+ branchedFrom !== null && /* @__PURE__ */ jsxRuntime.jsxs(
730
+ "span",
731
+ {
732
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.branch?.(v.id), {
733
+ testId: `version-branch-${v.id}`
734
+ }),
735
+ children: [
736
+ " ",
737
+ "\xB7 ",
738
+ l.branchedFrom(branchedFrom)
739
+ ]
740
+ }
741
+ )
742
+ ] })
743
+ ] }),
744
+ !isCurrent && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
745
+ /* @__PURE__ */ jsxRuntime.jsxs(
746
+ "button",
747
+ {
748
+ type: "button",
749
+ onClick: () => onOpen(v.id),
750
+ className: "inline-flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
751
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.open?.(v.id), {
752
+ testId: `open-version-${v.id}`
753
+ }),
754
+ children: [
755
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "size-3.5" }),
756
+ " ",
757
+ l.open
758
+ ]
759
+ }
760
+ ),
761
+ canCompare && /* @__PURE__ */ jsxRuntime.jsxs(
762
+ "button",
763
+ {
764
+ type: "button",
765
+ onClick: () => onCompare(v.id),
766
+ className: "inline-flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-sm font-medium text-primary transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
767
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.compare?.(v.id), {
768
+ testId: `compare-version-${v.id}`
769
+ }),
770
+ children: [
771
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitCompare, { className: "size-3.5" }),
772
+ " ",
773
+ l.compare
774
+ ]
775
+ }
776
+ )
777
+ ] })
778
+ ]
779
+ },
780
+ v.id
781
+ );
782
+ }) })
783
+ }
784
+ );
785
+ }
786
+
787
+ exports.ArtifactCompareBar = ArtifactCompareBar;
788
+ exports.ArtifactEditor = ArtifactEditor;
789
+ exports.ArtifactEditorBody = ArtifactEditorBody;
790
+ exports.ArtifactRedlineView = ArtifactRedlineView;
791
+ exports.ArtifactToolbar = ArtifactToolbar;
792
+ exports.ArtifactVersionBar = ArtifactVersionBar;
793
+ exports.DEFAULT_ARTIFACT_COMPARE_BAR_LABELS = DEFAULT_ARTIFACT_COMPARE_BAR_LABELS;
794
+ exports.DEFAULT_ARTIFACT_TOOLBAR_LABELS = DEFAULT_ARTIFACT_TOOLBAR_LABELS;
795
+ exports.DEFAULT_ARTIFACT_VERSION_BAR_LABELS = DEFAULT_ARTIFACT_VERSION_BAR_LABELS;
796
+ exports.DEFAULT_REDLINE_LABELS = DEFAULT_REDLINE_LABELS;
797
+ exports.DEFAULT_VERSION_TIMELINE_LABELS = DEFAULT_VERSION_TIMELINE_LABELS;
798
+ exports.RedlineComputing = RedlineComputing;
799
+ exports.RedlineDocument = RedlineDocument;
800
+ exports.RedlineFrame = RedlineFrame;
801
+ exports.RedlineHeader = RedlineHeader;
802
+ exports.RedlineMark = RedlineMark;
803
+ exports.RedlineRevertGutter = RedlineRevertGutter;
804
+ exports.RedlineStatus = RedlineStatus;
805
+ exports.VersionTimeline = VersionTimeline;
806
+ //# sourceMappingURL=index.cjs.map
807
+ //# sourceMappingURL=index.cjs.map