@arbidocs/blocks 0.4.9 → 0.4.11

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