@arbidocs/react 0.4.5 → 0.4.7
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.
- package/README.md +12 -0
- package/dist/artifacts/index.cjs +59 -23
- package/dist/artifacts/index.cjs.map +1 -1
- package/dist/artifacts/index.d.cts +18 -2
- package/dist/artifacts/index.d.ts +18 -2
- package/dist/artifacts/index.js +56 -21
- package/dist/artifacts/index.js.map +1 -1
- package/dist/{chunk-DVRJFLE7.js → chunk-2ACHNDO6.js} +5 -5
- package/dist/chunk-2ACHNDO6.js.map +1 -0
- package/dist/{chunk-2DXS7L7M.cjs → chunk-CBJ3WOGD.cjs} +18 -3
- package/dist/chunk-CBJ3WOGD.cjs.map +1 -0
- package/dist/{chunk-ZY53R6I4.js → chunk-KWCHIAQ5.js} +18 -4
- package/dist/chunk-KWCHIAQ5.js.map +1 -0
- package/dist/{chunk-7V7B7OEM.cjs → chunk-OI55JRKT.cjs} +44 -28
- package/dist/chunk-OI55JRKT.cjs.map +1 -0
- package/dist/{chunk-H7ZZQ4ZV.js → chunk-RIHMIEXM.js} +44 -29
- package/dist/chunk-RIHMIEXM.js.map +1 -0
- package/dist/{chunk-7BDGLRQX.cjs → chunk-Z5YCRJY3.cjs} +6 -6
- package/dist/chunk-Z5YCRJY3.cjs.map +1 -0
- package/dist/index-CC6CvXEs.d.cts +1366 -0
- package/dist/index-CC6CvXEs.d.ts +1366 -0
- package/dist/index.cjs +952 -322
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +588 -28
- package/dist/index.d.ts +588 -28
- package/dist/index.js +642 -42
- package/dist/index.js.map +1 -1
- package/dist/ui/index.cjs +131 -127
- package/dist/ui/index.d.cts +24 -1324
- package/dist/ui/index.d.ts +24 -1324
- package/dist/ui/index.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-2DXS7L7M.cjs.map +0 -1
- package/dist/chunk-7BDGLRQX.cjs.map +0 -1
- package/dist/chunk-7V7B7OEM.cjs.map +0 -1
- package/dist/chunk-DVRJFLE7.js.map +0 -1
- package/dist/chunk-H7ZZQ4ZV.js.map +0 -1
- package/dist/chunk-ZY53R6I4.js.map +0 -1
package/README.md
CHANGED
|
@@ -100,6 +100,18 @@ That's it — three hooks and you have a streaming RAG chat.
|
|
|
100
100
|
| `useTags(workspaceId)` | Workspace tags | Workspace selected |
|
|
101
101
|
| `useAssistantQuery()` | Streaming mutation | Call `.mutate()` |
|
|
102
102
|
| `useHealth()` | Backend status | Pass `{ enabled: true }` |
|
|
103
|
+
| `useProfile()` / `useUpdateProfile()` | The user's name, picture and email; save name or picture | Logged in |
|
|
104
|
+
| `useRequestEmailChange()` / `useConfirmEmailChange()` | Email change by verification code | Call `.mutate()` |
|
|
105
|
+
| `usePasswordChange()` | Change the master password (re-keys workspaces and direct messages) | Call `.mutate()` |
|
|
106
|
+
| `useNotificationPreferences(keys)` | Email notification switches, optimistic save | Logged in |
|
|
107
|
+
| `useSessions()` / `useTerminateSession()` / `useLogoutAllSessions()` | Active sessions, end one, sign out everywhere | Logged in |
|
|
108
|
+
| `useDeleteAccount()` | Close the account (soft delete) | Call `.mutate()` |
|
|
109
|
+
|
|
110
|
+
The account hooks have SDK-free controllers for hosts without an `ArbiProvider` (`useNameEditor`,
|
|
111
|
+
`useEmailChange`, `usePasswordChangeForm`, `useDeleteAccountFlow`, `useAvatarCrop`,
|
|
112
|
+
`toNotificationPreferences`): they own the form state and take the save as a function. The blocks
|
|
113
|
+
`/connect` entry composes the lot into a settings page (see the Settings page recipe in
|
|
114
|
+
`docs/design/blocks-package.md`).
|
|
103
115
|
|
|
104
116
|
## Artifact editing (`@arbidocs/react/artifacts`)
|
|
105
117
|
|
package/dist/artifacts/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkCBJ3WOGD_cjs = require('../chunk-CBJ3WOGD.cjs');
|
|
4
4
|
var chunkVJWAP2HJ_cjs = require('../chunk-VJWAP2HJ.cjs');
|
|
5
|
-
var
|
|
5
|
+
var chunkOI55JRKT_cjs = require('../chunk-OI55JRKT.cjs');
|
|
6
6
|
require('../chunk-S6A6FSG7.cjs');
|
|
7
7
|
var chunkZMTLGO3K_cjs = require('../chunk-ZMTLGO3K.cjs');
|
|
8
8
|
var react = require('react');
|
|
@@ -133,6 +133,10 @@ function versionLabel(versions, docId) {
|
|
|
133
133
|
function flattenChunks(chunks) {
|
|
134
134
|
return (chunks ?? []).map((c) => (c.content ?? "").trim()).join("\n\n");
|
|
135
135
|
}
|
|
136
|
+
var DOC_ID = /^doc/;
|
|
137
|
+
function isDocumentId(id) {
|
|
138
|
+
return !!id && DOC_ID.test(id);
|
|
139
|
+
}
|
|
136
140
|
function useArtifactEditSession(options) {
|
|
137
141
|
const {
|
|
138
142
|
docId,
|
|
@@ -309,19 +313,20 @@ function useArtifactEditSession(options) {
|
|
|
309
313
|
);
|
|
310
314
|
}
|
|
311
315
|
function useArtifactText(docId, options) {
|
|
312
|
-
const
|
|
313
|
-
|
|
316
|
+
const real = isDocumentId(docId);
|
|
317
|
+
const { data, isLoading, isError } = chunkCBJ3WOGD_cjs.useParsedDocument(real ? docId : void 0, "marker", {
|
|
318
|
+
enabled: (options?.enabled ?? true) && real
|
|
314
319
|
});
|
|
315
320
|
const text = react.useMemo(() => {
|
|
316
|
-
if (!
|
|
321
|
+
if (!real) return void 0;
|
|
317
322
|
if (isError) return null;
|
|
318
323
|
if (!data) return void 0;
|
|
319
324
|
return data.chunks?.length ? flattenChunks(data.chunks) : null;
|
|
320
|
-
}, [
|
|
321
|
-
return { text, isLoading:
|
|
325
|
+
}, [real, data, isError]);
|
|
326
|
+
return { text, isLoading: real && isLoading };
|
|
322
327
|
}
|
|
323
328
|
function useArtifactVersions(workspaceId, docId) {
|
|
324
|
-
const { data: documents } =
|
|
329
|
+
const { data: documents } = chunkCBJ3WOGD_cjs.useDocuments(workspaceId);
|
|
325
330
|
return react.useMemo(
|
|
326
331
|
() => toArtifactVersions(buildVersionChain(documents ?? [], docId)),
|
|
327
332
|
[documents, docId]
|
|
@@ -343,14 +348,28 @@ function useSaveArtifactVersion() {
|
|
|
343
348
|
}
|
|
344
349
|
);
|
|
345
350
|
if (workspaceId) {
|
|
346
|
-
await queryClient.invalidateQueries({ queryKey:
|
|
351
|
+
await queryClient.invalidateQueries({ queryKey: chunkCBJ3WOGD_cjs.arbiQueryKeys.documents(workspaceId) });
|
|
347
352
|
}
|
|
348
353
|
return { docId: result.doc_ext_ids?.[0] };
|
|
349
354
|
}
|
|
350
355
|
});
|
|
351
356
|
}
|
|
352
357
|
function useArtifactSession(options) {
|
|
353
|
-
const {
|
|
358
|
+
const {
|
|
359
|
+
workspaceId,
|
|
360
|
+
docId: hostDocId,
|
|
361
|
+
draftContent,
|
|
362
|
+
title,
|
|
363
|
+
configId,
|
|
364
|
+
compareId,
|
|
365
|
+
onCompareChange,
|
|
366
|
+
onSaved,
|
|
367
|
+
...passthrough
|
|
368
|
+
} = options;
|
|
369
|
+
const [saved, setSaved] = react.useState(null);
|
|
370
|
+
const adopted = saved && saved.forId === hostDocId ? saved : null;
|
|
371
|
+
const docId = adopted?.id ?? hostDocId;
|
|
372
|
+
const isLocal = !isDocumentId(docId);
|
|
354
373
|
const [ownCompareId, setOwnCompareId] = react.useState(null);
|
|
355
374
|
const activeCompareId = compareId === void 0 ? ownCompareId : compareId;
|
|
356
375
|
const changeCompare = react.useCallback(
|
|
@@ -361,37 +380,53 @@ function useArtifactSession(options) {
|
|
|
361
380
|
[onCompareChange]
|
|
362
381
|
);
|
|
363
382
|
const { text, isLoading } = useArtifactText(docId);
|
|
364
|
-
const versions = useArtifactVersions(workspaceId, docId);
|
|
383
|
+
const versions = useArtifactVersions(workspaceId, isLocal ? null : docId);
|
|
365
384
|
const { text: compareText, isLoading: compareLoading } = useArtifactText(activeCompareId, {
|
|
366
385
|
enabled: !!activeCompareId
|
|
367
386
|
});
|
|
368
387
|
const saveVersion = useSaveArtifactVersion();
|
|
369
388
|
const current = versions.find((v) => v.id === docId);
|
|
370
389
|
const save = react.useCallback(
|
|
371
|
-
(content) =>
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
390
|
+
async (content) => {
|
|
391
|
+
const result = await saveVersion.mutateAsync({
|
|
392
|
+
title: title ?? current?.name ?? "Untitled",
|
|
393
|
+
content,
|
|
394
|
+
parentId: isLocal ? null : docId,
|
|
395
|
+
configId,
|
|
396
|
+
workspaceId
|
|
397
|
+
});
|
|
398
|
+
return { ...result, version: isLocal ? 1 : versions.length + 1 };
|
|
399
|
+
},
|
|
400
|
+
[saveVersion, title, current?.name, isLocal, docId, configId, workspaceId, versions.length]
|
|
401
|
+
);
|
|
402
|
+
const handleSaved = react.useCallback(
|
|
403
|
+
(result, content) => {
|
|
404
|
+
if (!isDocumentId(hostDocId) && result.docId)
|
|
405
|
+
setSaved({ forId: hostDocId, id: result.docId, text: content });
|
|
406
|
+
onSaved?.(result, content);
|
|
407
|
+
},
|
|
408
|
+
[hostDocId, onSaved]
|
|
379
409
|
);
|
|
380
410
|
const session = useArtifactEditSession({
|
|
381
411
|
...passthrough,
|
|
382
412
|
docId,
|
|
383
|
-
|
|
413
|
+
// A local draft has only its own text; a just-saved one shows what was saved until the parsed
|
|
414
|
+
// text of the new document arrives.
|
|
415
|
+
baseline: text ?? (isLocal ? draftContent : adopted?.text),
|
|
384
416
|
parentId: current?.parentId,
|
|
385
417
|
compareId: activeCompareId,
|
|
386
418
|
onCompareChange: changeCompare,
|
|
387
419
|
compareText,
|
|
388
420
|
compareLoading,
|
|
389
|
-
save
|
|
421
|
+
save,
|
|
422
|
+
onSaved: handleSaved
|
|
390
423
|
});
|
|
391
424
|
const { redline } = session;
|
|
392
425
|
return react.useMemo(
|
|
393
426
|
() => ({
|
|
394
427
|
...session,
|
|
428
|
+
docId,
|
|
429
|
+
isLocal,
|
|
395
430
|
isLoading,
|
|
396
431
|
versions,
|
|
397
432
|
labelOf: (id) => versionLabel(versions, id),
|
|
@@ -423,11 +458,11 @@ function useArtifactSession(options) {
|
|
|
423
458
|
onRevert: (regionId) => void session.revertRegion(regionId)
|
|
424
459
|
}
|
|
425
460
|
}),
|
|
426
|
-
[session, redline, isLoading, versions, docId]
|
|
461
|
+
[session, redline, isLoading, isLocal, versions, docId]
|
|
427
462
|
);
|
|
428
463
|
}
|
|
429
464
|
function renderArtifactMarkdown(markdown, components) {
|
|
430
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
465
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunkOI55JRKT_cjs.MarkdownRenderer, { components, children: markdown });
|
|
431
466
|
}
|
|
432
467
|
|
|
433
468
|
Object.defineProperty(exports, "buildHybridRedlineMarkdown", {
|
|
@@ -444,6 +479,7 @@ Object.defineProperty(exports, "revertRedlineRegion", {
|
|
|
444
479
|
});
|
|
445
480
|
exports.buildVersionChain = buildVersionChain;
|
|
446
481
|
exports.flattenChunks = flattenChunks;
|
|
482
|
+
exports.isDocumentId = isDocumentId;
|
|
447
483
|
exports.mainThreadRedlineEngine = mainThreadRedlineEngine;
|
|
448
484
|
exports.renderArtifactMarkdown = renderArtifactMarkdown;
|
|
449
485
|
exports.toArtifactVersions = toArtifactVersions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/artifacts/redline-engine.ts","../../src/artifacts/useRedline.ts","../../src/artifacts/versions.ts","../../src/artifacts/useArtifactEditSession.ts","../../src/artifacts/useArtifactSession.ts","../../src/artifacts/renderArtifactMarkdown.tsx"],"names":["buildHybridRedlineMarkdown","buildHybridRedlineWithRegions","revertRedlineRegion","useState","useRef","useEffect","useCallback","useMemo","content","useParsedDocument","useDocuments","useArbi","useQueryClient","useMutation","arbiQueryKeys","jsx","MarkdownRenderer"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n buildHybridRedlineMarkdown,\n buildHybridRedlineWithRegions,\n revertRedlineRegion,\n type RedlineWithRegions,\n} from './redline-diff'\n\n/**\n * Where a redline is computed. The default runs on the calling thread; a host with large\n * documents passes an engine backed by a Web Worker (for example a Comlink proxy exposing the same\n * three functions) so typing never waits on a diff.\n */\nexport interface RedlineEngine {\n buildRedline(baseText: string, compareText: string): string | Promise<string>\n buildRedlineWithRegions(\n baseText: string,\n compareText: string\n ): RedlineWithRegions | Promise<RedlineWithRegions>\n revertRegion(baseText: string, compareText: string, regionId: string): string | Promise<string>\n}\n\n/** Main-thread engine: the pure functions of `redline-diff`. */\nexport const mainThreadRedlineEngine: RedlineEngine = {\n buildRedline: buildHybridRedlineMarkdown,\n buildRedlineWithRegions: buildHybridRedlineWithRegions,\n revertRegion: revertRedlineRegion,\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { RedlineRegion } from './redline-diff'\nimport { mainThreadRedlineEngine, type RedlineEngine } from './redline-engine'\n\n/** What a redline view can show. Mirrors the status parts of `@arbidocs/blocks/artifacts`. */\nexport type RedlineState =\n | { kind: 'idle' }\n | { kind: 'computing' }\n | { kind: 'ready'; markdown: string; regions: RedlineRegion[] }\n | { kind: 'identical' }\n | { kind: 'unavailable' }\n\nexport interface UseRedlineOptions {\n /** The older side. `null` means the text could not be loaded; `undefined` means not chosen. */\n baseText: string | null | undefined\n /** The newer side (a loaded version, or the live edit buffer). */\n compareText: string | null | undefined\n /** Either text is still being fetched. */\n isLoading?: boolean\n /** Tag every change with a stable id so a view can offer per-change undo. */\n withRegions?: boolean\n /** Defaults to the main thread; pass a worker-backed engine for big documents. */\n engine?: RedlineEngine\n}\n\nexport interface UseRedlineResult {\n state: RedlineState\n /** Undo one change: resolves with the compare text rebuilt without it (null if nothing changed). */\n revertRegion: (regionId: string) => Promise<string | null>\n}\n\n/**\n * Track-changes between two texts. Stale results are dropped when the inputs change mid-compute,\n * and a failed diff reports `unavailable` instead of throwing into the render.\n */\nexport function useRedline({\n baseText,\n compareText,\n isLoading = false,\n withRegions = false,\n engine = mainThreadRedlineEngine,\n}: UseRedlineOptions): UseRedlineResult {\n const [state, setState] = useState<RedlineState>({ kind: 'idle' })\n const requestIdRef = useRef(0)\n\n useEffect(() => {\n if (baseText === undefined || compareText === undefined) {\n setState({ kind: 'idle' })\n return\n }\n if (isLoading) {\n setState({ kind: 'computing' })\n return\n }\n if (baseText === null || compareText === null) {\n setState({ kind: 'unavailable' })\n return\n }\n if (baseText === compareText) {\n setState({ kind: 'identical' })\n return\n }\n\n const id = ++requestIdRef.current\n let cancelled = false\n setState({ kind: 'computing' })\n Promise.resolve(\n withRegions\n ? engine.buildRedlineWithRegions(baseText, compareText)\n : Promise.resolve(engine.buildRedline(baseText, compareText)).then((markdown) => ({\n markdown,\n regions: [] as RedlineRegion[],\n }))\n )\n .then((result) => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'ready', markdown: result.markdown, regions: result.regions })\n })\n .catch(() => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'unavailable' })\n })\n return () => {\n cancelled = true\n }\n }, [baseText, compareText, isLoading, withRegions, engine])\n\n // The latest texts, so `revertRegion` stays referentially stable while the user types.\n const latest = useRef({ baseText, compareText })\n useEffect(() => {\n latest.current = { baseText, compareText }\n }, [baseText, compareText])\n\n const revertRegion = useCallback(\n async (regionId: string): Promise<string | null> => {\n const { baseText: base, compareText: compare } = latest.current\n if (!base || !compare) return null\n try {\n const next = await engine.revertRegion(base, compare, regionId)\n return next !== compare ? next : null\n } catch {\n return null\n }\n },\n [engine]\n )\n\n return useMemo(() => ({ state, revertRegion }), [state, revertRegion])\n}\n","/**\n * Version lineage of an artifact. Every save creates a NEW document whose `parent_ext_id` is the\n * version it was saved from, so a lineage is a tree (a save from an old version is a deliberate\n * branch). Computed from a document list the host already has; no extra request.\n */\n\n/** The fields of a workspace document the lineage needs (structurally a subset of the API type). */\nexport interface VersionedDoc {\n external_id?: string | null\n parent_ext_id?: string | null\n file_name?: string | null\n created_at?: string | null\n}\n\n/** One row of a version list. Matches `VersionEntry` of `@arbidocs/blocks/artifacts`. */\nexport interface ArtifactVersion {\n id: string\n /** File name as stored. */\n name: string\n /** ISO timestamp. */\n createdAt: string\n /** The version this one was saved from. */\n parentId?: string | null\n}\n\n/**\n * The whole lineage of `docId` (root first, then oldest to newest), or `[]` when the document is\n * not in `docs`. Cycle-safe.\n */\nexport function buildVersionChain<T extends VersionedDoc>(\n docs: readonly T[],\n docId: string | null | undefined\n): T[] {\n if (!docId) return []\n const byId = new Map<string, T>()\n for (const d of docs) if (d.external_id) byId.set(d.external_id, d)\n\n const current = byId.get(docId)\n if (!current) return []\n\n let root = current\n const up = new Set<string>()\n while (\n root.parent_ext_id &&\n byId.has(root.parent_ext_id) &&\n root.external_id &&\n !up.has(root.external_id)\n ) {\n up.add(root.external_id)\n root = byId.get(root.parent_ext_id) as T\n }\n\n const byParent = new Map<string, T[]>()\n for (const d of docs) {\n if (d.parent_ext_id) {\n const siblings = byParent.get(d.parent_ext_id) ?? []\n siblings.push(d)\n byParent.set(d.parent_ext_id, siblings)\n }\n }\n const out: T[] = []\n const visited = new Set<string>()\n const walk = (d: T): void => {\n if (!d.external_id || visited.has(d.external_id)) return\n visited.add(d.external_id)\n out.push(d)\n for (const child of byParent.get(d.external_id) ?? []) walk(child)\n }\n walk(root)\n\n out.sort((a, b) => (a.created_at ?? '').localeCompare(b.created_at ?? ''))\n return out\n}\n\n/** The lineage of `docId` as plain version rows. */\nexport function toArtifactVersions(chain: readonly VersionedDoc[]): ArtifactVersion[] {\n return chain.flatMap((d) =>\n d.external_id\n ? [\n {\n id: d.external_id,\n name: d.file_name ?? '',\n createdAt: d.created_at ?? '',\n parentId: d.parent_ext_id,\n },\n ]\n : []\n )\n}\n\n/**\n * \"v2\": the 1-based position of `docId` in its lineage. `null` when there is nothing to tell apart\n * (the lineage is just this document, or it is unknown), so unversioned documents stay unlabelled.\n */\nexport function versionLabel(\n versions: readonly ArtifactVersion[],\n docId: string | null | undefined\n): string | null {\n if (!docId || versions.length <= 1) return null\n const index = versions.findIndex((v) => v.id === docId)\n return index === -1 ? null : `v${index + 1}`\n}\n\n/** Join parsed chunks into one markdown text (blank line between chunks). */\nexport function flattenChunks(\n chunks: readonly { content?: string | null }[] | null | undefined\n): string {\n return (chunks ?? []).map((c) => (c.content ?? '').trim()).join('\\n\\n')\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useRedline, type UseRedlineResult } from './useRedline'\nimport type { RedlineEngine } from './redline-engine'\n\n/** What a save reports back. `docId` is the new version when the backend already knows it. */\nexport interface ArtifactSaveResult {\n docId?: string\n}\n\nexport interface ArtifactEditSessionOptions {\n /** The artifact being edited. Changing it discards the buffer and any comparison. */\n docId: string | null | undefined\n /**\n * The saved text of the open version. `undefined` while it loads; whenever it changes the\n * baseline follows it (a version arriving from the realtime channel, a finished stream).\n */\n baseline: string | undefined\n /**\n * A new document the user types from scratch: open straight in the editor, seeded with\n * `initialContent`, instead of showing a read-only view. Read when `docId` changes.\n */\n startEditing?: boolean\n initialContent?: string\n /** The version this one was saved from. Offering \"compare with previous\" needs it. */\n parentId?: string | null\n /** Controlled comparison target. Omit for an uncontrolled one the session owns. */\n compareId?: string | null\n onCompareChange?: (id: string | null) => void\n /** The saved text of the compare target (the older side of the diff). */\n compareText?: string | null\n compareLoading?: boolean\n /** Starting a comparison opens the editor with track changes on (default true). */\n compareOpensEditor?: boolean\n /** Persist the buffer as a NEW version. Rejecting keeps the buffer so nothing is lost. */\n save: (content: string) => Promise<ArtifactSaveResult | void>\n onSaved?: (result: ArtifactSaveResult, content: string) => void\n onSaveError?: (error: unknown) => void\n /** Every buffer change (a host keeps a draft store in sync with it). */\n onContentChange?: (content: string) => void\n /** The unsaved-changes flag, for a host that warns before a panel is closed. */\n onDirtyChange?: (dirty: boolean) => void\n /** Where the diff runs. Defaults to the main thread. */\n redlineEngine?: RedlineEngine\n /** Typing is never debounced; the diff trails the buffer by this long. Default 300ms. */\n diffDelayMs?: number\n}\n\nexport interface ArtifactEditSession {\n isEditing: boolean\n /** The saved text of the open version. */\n baseline: string\n /** The text in the editor (the baseline until the first edit). */\n content: string\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n compareId: string | null\n showTrackChanges: boolean\n /** Track changes between the compare target and the (debounced) buffer. */\n redline: UseRedlineResult\n startEdit: () => void\n /** Discard the buffer and any comparison; back to the rendered view. */\n cancel: () => void\n /** Save the buffer as a new version. Resolves false when it failed (the buffer is kept). */\n save: () => Promise<boolean>\n /** The editor's `onChange`; also replaces the buffer (for example after an undo-this-change). */\n change: (markdown: string) => void\n /** The editor's `onNormalized`: adopt its canonical form as the baseline so Save does not fire. */\n normalized: (markdown: string) => void\n /** Compare with the previous version (when no id is given). */\n compare: (id?: string) => void\n stopCompare: () => void\n setShowTrackChanges: (show: boolean) => void\n /** Undo one tracked change in the buffer. */\n revertRegion: (regionId: string) => Promise<void>\n}\n\n/**\n * The state machine of an artifact edit session, with no SDK and no network: the edit buffer and\n * its baseline, the dirty flag, immutable-version saves and a track-changes comparison. A host\n * supplies the saved text and a `save` function (see `useArtifactSession` for the SDK binding).\n */\nexport function useArtifactEditSession(options: ArtifactEditSessionOptions): ArtifactEditSession {\n const {\n docId,\n baseline: loadedBaseline,\n startEditing = false,\n initialContent,\n parentId,\n compareId: controlledCompareId,\n onCompareChange,\n compareText,\n compareLoading = false,\n compareOpensEditor = true,\n save: persist,\n onSaved,\n onSaveError,\n onContentChange,\n onDirtyChange,\n redlineEngine,\n diffDelayMs = 300,\n } = options\n\n const [isEditing, setIsEditing] = useState(false)\n const [baseline, setBaseline] = useState('')\n const [buffer, setBuffer] = useState('')\n const [isSaving, setIsSaving] = useState(false)\n const [showTrackChanges, setShowTrackChanges] = useState(false)\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const controlled = controlledCompareId !== undefined\n const compareId = controlled ? controlledCompareId : ownCompareId\n\n const setCompareId = useCallback(\n (id: string | null) => {\n if (!controlled) setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [controlled, onCompareChange]\n )\n\n // The latest values for callbacks that must not change identity while the user types.\n const latest = useRef({ buffer, baseline, isEditing, initialContent })\n latest.current = { buffer, baseline, isEditing, initialContent }\n\n // The baseline follows the loaded text. A draft has none and seeds itself below.\n useEffect(() => {\n if (loadedBaseline !== undefined) setBaseline(loadedBaseline)\n }, [loadedBaseline])\n\n // Another artifact: drop stale edits and comparison. A new typed document starts in the editor.\n useEffect(() => {\n if (startEditing) {\n const seed = latest.current.initialContent ?? ''\n setIsEditing(true)\n setBaseline(seed)\n setBuffer(seed)\n } else {\n setIsEditing(false)\n setBuffer('')\n }\n setCompareId(null)\n setShowTrackChanges(false)\n // Only the identity of the artifact resets the session.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [docId])\n\n const startEdit = useCallback(() => {\n setBuffer(latest.current.baseline)\n setIsEditing(true)\n }, [])\n\n const stopCompare = useCallback(() => {\n setCompareId(null)\n setShowTrackChanges(false)\n }, [setCompareId])\n\n const cancel = useCallback(() => {\n setIsEditing(false)\n setBuffer('')\n stopCompare()\n }, [stopCompare])\n\n const compare = useCallback(\n (id?: string) => {\n const target = id ?? parentId\n if (target) setCompareId(target)\n },\n [parentId, setCompareId]\n )\n\n // Comparing and editing are one surface: a comparison opens the editor with the diff showing,\n // like Word's Compare yields tracked changes you can keep typing through.\n const hasBaseline = baseline !== ''\n useEffect(() => {\n if (!compareId || !compareOpensEditor || !hasBaseline) return\n if (!latest.current.isEditing) startEdit()\n setShowTrackChanges(true)\n }, [compareId, compareOpensEditor, hasBaseline, startEdit])\n\n const save = useCallback(async (): Promise<boolean> => {\n const content = latest.current.buffer\n setIsSaving(true)\n try {\n const result = (await persist(content)) ?? {}\n setBaseline(content)\n setIsEditing(false)\n stopCompare()\n onSaved?.(result, content)\n return true\n } catch (error) {\n onSaveError?.(error)\n return false\n } finally {\n setIsSaving(false)\n }\n }, [persist, stopCompare, onSaved, onSaveError])\n\n const content = buffer || baseline\n const hasChanges = isEditing && !!buffer && buffer !== baseline\n useEffect(() => {\n onDirtyChange?.(hasChanges)\n return () => onDirtyChange?.(false)\n }, [hasChanges, onDirtyChange])\n\n const setContent = useCallback(\n (markdown: string) => {\n setBuffer(markdown)\n onContentChange?.(markdown)\n },\n [onContentChange]\n )\n const normalized = useCallback((markdown: string) => {\n setBaseline(markdown)\n setBuffer(markdown)\n }, [])\n\n // The diff trails the buffer so it runs on a settled text.\n const [diffContent, setDiffContent] = useState(content)\n useEffect(() => {\n const id = setTimeout(() => setDiffContent(content), diffDelayMs)\n return () => clearTimeout(id)\n }, [content, diffDelayMs])\n\n const redline = useRedline({\n baseText: compareId ? compareText : undefined,\n compareText: compareId ? diffContent || baseline : undefined,\n isLoading: compareLoading,\n withRegions: true,\n engine: redlineEngine,\n })\n const { revertRegion: revertInRedline } = redline\n const revertRegion = useCallback(\n async (regionId: string): Promise<void> => {\n const next = await revertInRedline(regionId)\n if (next !== null) setContent(next)\n },\n [revertInRedline, setContent]\n )\n\n return useMemo(\n () => ({\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n canCompare: !!parentId && !compareId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n change: setContent,\n normalized,\n compare,\n stopCompare,\n setShowTrackChanges,\n revertRegion,\n }),\n [\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n parentId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n setContent,\n normalized,\n compare,\n stopCompare,\n revertRegion,\n ]\n )\n}\n","import { useCallback, useMemo, useState } from 'react'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys, useDocuments, useParsedDocument } from '../hooks'\nimport {\n buildVersionChain,\n flattenChunks,\n toArtifactVersions,\n versionLabel,\n type ArtifactVersion,\n} from './versions'\nimport {\n useArtifactEditSession,\n type ArtifactEditSession,\n type ArtifactEditSessionOptions,\n type ArtifactSaveResult,\n} from './useArtifactEditSession'\n\n/** The saved markdown of a document (its parsed chunks, joined). */\nexport function useArtifactText(\n docId: string | null | undefined,\n options?: { enabled?: boolean }\n): { text: string | null | undefined; isLoading: boolean } {\n const { data, isLoading, isError } = useParsedDocument(docId ?? undefined, 'marker', {\n enabled: (options?.enabled ?? true) && !!docId,\n })\n const text = useMemo(() => {\n if (!docId) return undefined\n if (isError) return null\n if (!data) return undefined\n return data.chunks?.length ? flattenChunks(data.chunks) : null\n }, [docId, data, isError])\n return { text, isLoading: !!docId && isLoading }\n}\n\n/** The version lineage of an artifact in a workspace, oldest first. */\nexport function useArtifactVersions(\n workspaceId: string | undefined,\n docId: string | null | undefined\n): ArtifactVersion[] {\n const { data: documents } = useDocuments(workspaceId)\n return useMemo(\n () => toArtifactVersions(buildVersionChain(documents ?? [], docId)),\n [documents, docId]\n )\n}\n\nexport interface SaveArtifactVersionInput {\n /** File name of the new version (`.md` is added when missing). */\n title: string\n content: string\n /** The version this one is saved from; omit for a first version. */\n parentId?: string | null\n /** The processing config (auto-title, parsing) to run the upload with. */\n configId?: string | null\n /** `artifact` (default) for AI-style drafts; `source` for a document the user typed. */\n wpType?: 'artifact' | 'source'\n}\n\n/**\n * Save markdown as a NEW immutable version (a child document of `parentId`) and refresh the\n * workspace document list so the version list picks it up. The id of the new version is often not\n * known yet (the document is parsed asynchronously); it then arrives through the list.\n */\nexport function useSaveArtifactVersion() {\n const arbi = useArbi()\n const queryClient = useQueryClient()\n return useMutation<\n ArtifactSaveResult,\n Error,\n SaveArtifactVersionInput & { workspaceId?: string }\n >({\n mutationFn: async ({ title, content, parentId, configId, wpType, workspaceId }) => {\n // The backend classifies uploads by extension: a title without one is silently dropped.\n const fileName = /\\.md$/i.test(title) ? title : `${title}.md`\n const result = await arbi.documents.uploadFile(\n new Blob([content], { type: 'text/markdown' }),\n fileName,\n {\n wpType: wpType ?? 'artifact',\n parentExtId: parentId ?? undefined,\n configExtId: configId ?? undefined,\n }\n )\n if (workspaceId) {\n await queryClient.invalidateQueries({ queryKey: arbiQueryKeys.documents(workspaceId) })\n }\n return { docId: result.doc_ext_ids?.[0] }\n },\n })\n}\n\nexport interface ArtifactSessionOptions extends Pick<\n ArtifactEditSessionOptions,\n | 'onSaved'\n | 'onSaveError'\n | 'onCompareChange'\n | 'compareId'\n | 'compareOpensEditor'\n | 'redlineEngine'\n | 'onDirtyChange'\n> {\n workspaceId: string | undefined\n /** The open version. */\n docId: string | null | undefined\n /** Name for saved versions. Defaults to the open version's file name, else \"Untitled\". */\n title?: string\n /** Processing config for saved versions. */\n configId?: string | null\n}\n\n/** Everything `ArtifactEditor` (`@arbidocs/blocks/artifacts`) takes from a session, flat. */\nexport interface ArtifactSessionView {\n content: string\n isEditing: boolean\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n comparing: boolean\n compareId: string | null\n showTrackChanges: boolean\n versions: ArtifactVersion[]\n currentVersionId: string\n onStartEdit: () => void\n onCancel: () => void\n onSave: () => void\n onCompare: () => void\n onStopCompare: () => void\n onToggleTrackChanges: () => void\n}\n\nexport interface ArtifactSession extends ArtifactEditSession {\n isLoading: boolean\n versions: ArtifactVersion[]\n /** \"v2\" for any version in the lineage. */\n labelOf: (id: string | null | undefined) => string | null\n /** Props for `<ArtifactEditor>`. */\n view: ArtifactSessionView\n /** Props for `<ArtifactMarkdownEditor>` (`@arbidocs/blocks/artifacts/editor`). */\n editorProps: {\n markdown: string\n onChange: (markdown: string) => void\n onNormalized: (markdown: string) => void\n }\n /** Props for `<ArtifactRedlineView>`. */\n redlineProps: {\n state: ArtifactEditSession['redline']['state']\n onRevert: (regionId: string) => void\n }\n}\n\n/**\n * Edit an artifact through the SDK: load it, edit it, save it as a new version, list its versions\n * and compare any two with track changes. Needs an `<ArbiProvider>` and a selected workspace.\n *\n * ```tsx\n * const session = useArtifactSession({ workspaceId, docId, onSaved: ({ docId }) => docId && open(docId) })\n * <ArtifactEditor {...session.view} onOpenVersion={open}\n * editor={<ArtifactMarkdownEditor {...session.editorProps} />}\n * redline={<ArtifactRedlineView {...session.redlineProps} />} />\n * ```\n */\nexport function useArtifactSession(options: ArtifactSessionOptions): ArtifactSession {\n const { workspaceId, docId, title, configId, compareId, onCompareChange, ...passthrough } =\n options\n // Owned here (not in the edit session) because the compare target's text must be loaded first.\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const activeCompareId = compareId === undefined ? ownCompareId : compareId\n const changeCompare = useCallback(\n (id: string | null) => {\n setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [onCompareChange]\n )\n\n const { text, isLoading } = useArtifactText(docId)\n const versions = useArtifactVersions(workspaceId, docId)\n const { text: compareText, isLoading: compareLoading } = useArtifactText(activeCompareId, {\n enabled: !!activeCompareId,\n })\n const saveVersion = useSaveArtifactVersion()\n const current = versions.find((v) => v.id === docId)\n\n const save = useCallback(\n (content: string) =>\n saveVersion.mutateAsync({\n title: title ?? current?.name ?? 'Untitled',\n content,\n parentId: docId,\n configId,\n workspaceId,\n }),\n [saveVersion, title, current?.name, docId, configId, workspaceId]\n )\n\n const session = useArtifactEditSession({\n ...passthrough,\n docId,\n baseline: text ?? undefined,\n parentId: current?.parentId,\n compareId: activeCompareId,\n onCompareChange: changeCompare,\n compareText,\n compareLoading,\n save,\n })\n\n const { redline } = session\n return useMemo<ArtifactSession>(\n () => ({\n ...session,\n isLoading,\n versions,\n labelOf: (id) => versionLabel(versions, id),\n view: {\n content: session.baseline,\n isEditing: session.isEditing,\n hasChanges: session.hasChanges,\n isSaving: session.isSaving,\n canCompare: session.canCompare,\n comparing: !!session.compareId,\n compareId: session.compareId,\n showTrackChanges: session.showTrackChanges,\n versions,\n currentVersionId: docId ?? '',\n onStartEdit: session.startEdit,\n onCancel: session.cancel,\n onSave: () => void session.save(),\n onCompare: () => session.compare(),\n onStopCompare: session.stopCompare,\n onToggleTrackChanges: () => session.setShowTrackChanges(!session.showTrackChanges),\n },\n editorProps: {\n markdown: session.content,\n onChange: session.change,\n onNormalized: session.normalized,\n },\n redlineProps: {\n state: redline.state,\n onRevert: (regionId) => void session.revertRegion(regionId),\n },\n }),\n [session, redline, isLoading, versions, docId]\n )\n}\n","import type { ComponentPropsWithoutRef, FC, ReactNode } from 'react'\nimport { MarkdownRenderer } from '../ai/MarkdownRenderer'\n\n/** The `<del>` / `<ins>` renderers `ArtifactRedlineView` hands to a markdown renderer. */\nexport interface ArtifactRedlineComponents {\n del: FC<ComponentPropsWithoutRef<'del'> & { 'data-cid'?: string }>\n ins: FC<ComponentPropsWithoutRef<'ins'> & { 'data-cid'?: string }>\n}\n\n/**\n * The kit's markdown renderer as the `renderMarkdown` slot of `ArtifactEditor` and\n * `ArtifactRedlineView`: full markdown (tables, lists, code) plus the raw `<del>` / `<ins>` tags\n * of a redline.\n */\nexport function renderArtifactMarkdown(\n markdown: string,\n components?: ArtifactRedlineComponents\n): ReactNode {\n return <MarkdownRenderer components={components}>{markdown}</MarkdownRenderer>\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/artifacts/redline-engine.ts","../../src/artifacts/useRedline.ts","../../src/artifacts/versions.ts","../../src/artifacts/useArtifactEditSession.ts","../../src/artifacts/useArtifactSession.ts","../../src/artifacts/renderArtifactMarkdown.tsx"],"names":["buildHybridRedlineMarkdown","buildHybridRedlineWithRegions","revertRedlineRegion","useState","useRef","useEffect","useCallback","useMemo","content","useParsedDocument","useDocuments","useArbi","useQueryClient","useMutation","arbiQueryKeys","jsx","MarkdownRenderer"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n buildHybridRedlineMarkdown,\n buildHybridRedlineWithRegions,\n revertRedlineRegion,\n type RedlineWithRegions,\n} from './redline-diff'\n\n/**\n * Where a redline is computed. The default runs on the calling thread; a host with large\n * documents passes an engine backed by a Web Worker (for example a Comlink proxy exposing the same\n * three functions) so typing never waits on a diff.\n */\nexport interface RedlineEngine {\n buildRedline(baseText: string, compareText: string): string | Promise<string>\n buildRedlineWithRegions(\n baseText: string,\n compareText: string\n ): RedlineWithRegions | Promise<RedlineWithRegions>\n revertRegion(baseText: string, compareText: string, regionId: string): string | Promise<string>\n}\n\n/** Main-thread engine: the pure functions of `redline-diff`. */\nexport const mainThreadRedlineEngine: RedlineEngine = {\n buildRedline: buildHybridRedlineMarkdown,\n buildRedlineWithRegions: buildHybridRedlineWithRegions,\n revertRegion: revertRedlineRegion,\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { RedlineRegion } from './redline-diff'\nimport { mainThreadRedlineEngine, type RedlineEngine } from './redline-engine'\n\n/** What a redline view can show. Mirrors the status parts of `@arbidocs/blocks/artifacts`. */\nexport type RedlineState =\n | { kind: 'idle' }\n | { kind: 'computing' }\n | { kind: 'ready'; markdown: string; regions: RedlineRegion[] }\n | { kind: 'identical' }\n | { kind: 'unavailable' }\n\nexport interface UseRedlineOptions {\n /** The older side. `null` means the text could not be loaded; `undefined` means not chosen. */\n baseText: string | null | undefined\n /** The newer side (a loaded version, or the live edit buffer). */\n compareText: string | null | undefined\n /** Either text is still being fetched. */\n isLoading?: boolean\n /** Tag every change with a stable id so a view can offer per-change undo. */\n withRegions?: boolean\n /** Defaults to the main thread; pass a worker-backed engine for big documents. */\n engine?: RedlineEngine\n}\n\nexport interface UseRedlineResult {\n state: RedlineState\n /** Undo one change: resolves with the compare text rebuilt without it (null if nothing changed). */\n revertRegion: (regionId: string) => Promise<string | null>\n}\n\n/**\n * Track-changes between two texts. Stale results are dropped when the inputs change mid-compute,\n * and a failed diff reports `unavailable` instead of throwing into the render.\n */\nexport function useRedline({\n baseText,\n compareText,\n isLoading = false,\n withRegions = false,\n engine = mainThreadRedlineEngine,\n}: UseRedlineOptions): UseRedlineResult {\n const [state, setState] = useState<RedlineState>({ kind: 'idle' })\n const requestIdRef = useRef(0)\n\n useEffect(() => {\n if (baseText === undefined || compareText === undefined) {\n setState({ kind: 'idle' })\n return\n }\n if (isLoading) {\n setState({ kind: 'computing' })\n return\n }\n if (baseText === null || compareText === null) {\n setState({ kind: 'unavailable' })\n return\n }\n if (baseText === compareText) {\n setState({ kind: 'identical' })\n return\n }\n\n const id = ++requestIdRef.current\n let cancelled = false\n setState({ kind: 'computing' })\n Promise.resolve(\n withRegions\n ? engine.buildRedlineWithRegions(baseText, compareText)\n : Promise.resolve(engine.buildRedline(baseText, compareText)).then((markdown) => ({\n markdown,\n regions: [] as RedlineRegion[],\n }))\n )\n .then((result) => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'ready', markdown: result.markdown, regions: result.regions })\n })\n .catch(() => {\n if (cancelled || id !== requestIdRef.current) return\n setState({ kind: 'unavailable' })\n })\n return () => {\n cancelled = true\n }\n }, [baseText, compareText, isLoading, withRegions, engine])\n\n // The latest texts, so `revertRegion` stays referentially stable while the user types.\n const latest = useRef({ baseText, compareText })\n useEffect(() => {\n latest.current = { baseText, compareText }\n }, [baseText, compareText])\n\n const revertRegion = useCallback(\n async (regionId: string): Promise<string | null> => {\n const { baseText: base, compareText: compare } = latest.current\n if (!base || !compare) return null\n try {\n const next = await engine.revertRegion(base, compare, regionId)\n return next !== compare ? next : null\n } catch {\n return null\n }\n },\n [engine]\n )\n\n return useMemo(() => ({ state, revertRegion }), [state, revertRegion])\n}\n","/**\n * Version lineage of an artifact. Every save creates a NEW document whose `parent_ext_id` is the\n * version it was saved from, so a lineage is a tree (a save from an old version is a deliberate\n * branch). Computed from a document list the host already has; no extra request.\n */\n\n/** The fields of a workspace document the lineage needs (structurally a subset of the API type). */\nexport interface VersionedDoc {\n external_id?: string | null\n parent_ext_id?: string | null\n file_name?: string | null\n created_at?: string | null\n}\n\n/** One row of a version list. Matches `VersionEntry` of `@arbidocs/blocks/artifacts`. */\nexport interface ArtifactVersion {\n id: string\n /** File name as stored. */\n name: string\n /** ISO timestamp. */\n createdAt: string\n /** The version this one was saved from. */\n parentId?: string | null\n}\n\n/**\n * The whole lineage of `docId` (root first, then oldest to newest), or `[]` when the document is\n * not in `docs`. Cycle-safe.\n */\nexport function buildVersionChain<T extends VersionedDoc>(\n docs: readonly T[],\n docId: string | null | undefined\n): T[] {\n if (!docId) return []\n const byId = new Map<string, T>()\n for (const d of docs) if (d.external_id) byId.set(d.external_id, d)\n\n const current = byId.get(docId)\n if (!current) return []\n\n let root = current\n const up = new Set<string>()\n while (\n root.parent_ext_id &&\n byId.has(root.parent_ext_id) &&\n root.external_id &&\n !up.has(root.external_id)\n ) {\n up.add(root.external_id)\n root = byId.get(root.parent_ext_id) as T\n }\n\n const byParent = new Map<string, T[]>()\n for (const d of docs) {\n if (d.parent_ext_id) {\n const siblings = byParent.get(d.parent_ext_id) ?? []\n siblings.push(d)\n byParent.set(d.parent_ext_id, siblings)\n }\n }\n const out: T[] = []\n const visited = new Set<string>()\n const walk = (d: T): void => {\n if (!d.external_id || visited.has(d.external_id)) return\n visited.add(d.external_id)\n out.push(d)\n for (const child of byParent.get(d.external_id) ?? []) walk(child)\n }\n walk(root)\n\n out.sort((a, b) => (a.created_at ?? '').localeCompare(b.created_at ?? ''))\n return out\n}\n\n/** The lineage of `docId` as plain version rows. */\nexport function toArtifactVersions(chain: readonly VersionedDoc[]): ArtifactVersion[] {\n return chain.flatMap((d) =>\n d.external_id\n ? [\n {\n id: d.external_id,\n name: d.file_name ?? '',\n createdAt: d.created_at ?? '',\n parentId: d.parent_ext_id,\n },\n ]\n : []\n )\n}\n\n/**\n * \"v2\": the 1-based position of `docId` in its lineage. `null` when there is nothing to tell apart\n * (the lineage is just this document, or it is unknown), so unversioned documents stay unlabelled.\n */\nexport function versionLabel(\n versions: readonly ArtifactVersion[],\n docId: string | null | undefined\n): string | null {\n if (!docId || versions.length <= 1) return null\n const index = versions.findIndex((v) => v.id === docId)\n return index === -1 ? null : `v${index + 1}`\n}\n\n/** Join parsed chunks into one markdown text (blank line between chunks). */\nexport function flattenChunks(\n chunks: readonly { content?: string | null }[] | null | undefined\n): string {\n return (chunks ?? []).map((c) => (c.content ?? '').trim()).join('\\n\\n')\n}\n\n/** The backend's pattern for a document id. Anything else (a streamed draft's placeholder) is local. */\nconst DOC_ID = /^doc/\n\n/** Is `id` a real, saved document id? Local drafts have placeholder ids and no backend document. */\nexport function isDocumentId(id: string | null | undefined): id is string {\n return !!id && DOC_ID.test(id)\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useRedline, type UseRedlineResult } from './useRedline'\nimport type { RedlineEngine } from './redline-engine'\n\n/** What a save reports back. `docId` is the new version when the backend already knows it. */\nexport interface ArtifactSaveResult {\n docId?: string\n /** 1-based number of the version that was just saved (1 for the first save of a draft). */\n version?: number\n}\n\nexport interface ArtifactEditSessionOptions {\n /** The artifact being edited. Changing it discards the buffer and any comparison. */\n docId: string | null | undefined\n /**\n * The saved text of the open version. `undefined` while it loads; whenever it changes the\n * baseline follows it (a version arriving from the realtime channel, a finished stream).\n */\n baseline: string | undefined\n /**\n * A new document the user types from scratch: open straight in the editor, seeded with\n * `initialContent`, instead of showing a read-only view. Read when `docId` changes.\n */\n startEditing?: boolean\n initialContent?: string\n /** The version this one was saved from. Offering \"compare with previous\" needs it. */\n parentId?: string | null\n /** Controlled comparison target. Omit for an uncontrolled one the session owns. */\n compareId?: string | null\n onCompareChange?: (id: string | null) => void\n /** The saved text of the compare target (the older side of the diff). */\n compareText?: string | null\n compareLoading?: boolean\n /** Starting a comparison opens the editor with track changes on (default true). */\n compareOpensEditor?: boolean\n /** Persist the buffer as a NEW version. Rejecting keeps the buffer so nothing is lost. */\n save: (content: string) => Promise<ArtifactSaveResult | void>\n onSaved?: (result: ArtifactSaveResult, content: string) => void\n onSaveError?: (error: unknown) => void\n /** Every buffer change (a host keeps a draft store in sync with it). */\n onContentChange?: (content: string) => void\n /** The unsaved-changes flag, for a host that warns before a panel is closed. */\n onDirtyChange?: (dirty: boolean) => void\n /** Where the diff runs. Defaults to the main thread. */\n redlineEngine?: RedlineEngine\n /** Typing is never debounced; the diff trails the buffer by this long. Default 300ms. */\n diffDelayMs?: number\n}\n\nexport interface ArtifactEditSession {\n isEditing: boolean\n /** The saved text of the open version. */\n baseline: string\n /** The text in the editor (the baseline until the first edit). */\n content: string\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n compareId: string | null\n showTrackChanges: boolean\n /** Track changes between the compare target and the (debounced) buffer. */\n redline: UseRedlineResult\n startEdit: () => void\n /** Discard the buffer and any comparison; back to the rendered view. */\n cancel: () => void\n /** Save the buffer as a new version. Resolves false when it failed (the buffer is kept). */\n save: () => Promise<boolean>\n /** The editor's `onChange`; also replaces the buffer (for example after an undo-this-change). */\n change: (markdown: string) => void\n /** The editor's `onNormalized`: adopt its canonical form as the baseline so Save does not fire. */\n normalized: (markdown: string) => void\n /** Compare with the previous version (when no id is given). */\n compare: (id?: string) => void\n stopCompare: () => void\n setShowTrackChanges: (show: boolean) => void\n /** Undo one tracked change in the buffer. */\n revertRegion: (regionId: string) => Promise<void>\n}\n\n/**\n * The state machine of an artifact edit session, with no SDK and no network: the edit buffer and\n * its baseline, the dirty flag, immutable-version saves and a track-changes comparison. A host\n * supplies the saved text and a `save` function (see `useArtifactSession` for the SDK binding).\n */\nexport function useArtifactEditSession(options: ArtifactEditSessionOptions): ArtifactEditSession {\n const {\n docId,\n baseline: loadedBaseline,\n startEditing = false,\n initialContent,\n parentId,\n compareId: controlledCompareId,\n onCompareChange,\n compareText,\n compareLoading = false,\n compareOpensEditor = true,\n save: persist,\n onSaved,\n onSaveError,\n onContentChange,\n onDirtyChange,\n redlineEngine,\n diffDelayMs = 300,\n } = options\n\n const [isEditing, setIsEditing] = useState(false)\n const [baseline, setBaseline] = useState('')\n const [buffer, setBuffer] = useState('')\n const [isSaving, setIsSaving] = useState(false)\n const [showTrackChanges, setShowTrackChanges] = useState(false)\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const controlled = controlledCompareId !== undefined\n const compareId = controlled ? controlledCompareId : ownCompareId\n\n const setCompareId = useCallback(\n (id: string | null) => {\n if (!controlled) setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [controlled, onCompareChange]\n )\n\n // The latest values for callbacks that must not change identity while the user types.\n const latest = useRef({ buffer, baseline, isEditing, initialContent })\n latest.current = { buffer, baseline, isEditing, initialContent }\n\n // The baseline follows the loaded text. A draft has none and seeds itself below.\n useEffect(() => {\n if (loadedBaseline !== undefined) setBaseline(loadedBaseline)\n }, [loadedBaseline])\n\n // Another artifact: drop stale edits and comparison. A new typed document starts in the editor.\n useEffect(() => {\n if (startEditing) {\n const seed = latest.current.initialContent ?? ''\n setIsEditing(true)\n setBaseline(seed)\n setBuffer(seed)\n } else {\n setIsEditing(false)\n setBuffer('')\n }\n setCompareId(null)\n setShowTrackChanges(false)\n // Only the identity of the artifact resets the session.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [docId])\n\n const startEdit = useCallback(() => {\n setBuffer(latest.current.baseline)\n setIsEditing(true)\n }, [])\n\n const stopCompare = useCallback(() => {\n setCompareId(null)\n setShowTrackChanges(false)\n }, [setCompareId])\n\n const cancel = useCallback(() => {\n setIsEditing(false)\n setBuffer('')\n stopCompare()\n }, [stopCompare])\n\n const compare = useCallback(\n (id?: string) => {\n const target = id ?? parentId\n if (target) setCompareId(target)\n },\n [parentId, setCompareId]\n )\n\n // Comparing and editing are one surface: a comparison opens the editor with the diff showing,\n // like Word's Compare yields tracked changes you can keep typing through.\n const hasBaseline = baseline !== ''\n useEffect(() => {\n if (!compareId || !compareOpensEditor || !hasBaseline) return\n if (!latest.current.isEditing) startEdit()\n setShowTrackChanges(true)\n }, [compareId, compareOpensEditor, hasBaseline, startEdit])\n\n const save = useCallback(async (): Promise<boolean> => {\n const content = latest.current.buffer\n setIsSaving(true)\n try {\n const result = (await persist(content)) ?? {}\n setBaseline(content)\n setIsEditing(false)\n stopCompare()\n onSaved?.(result, content)\n return true\n } catch (error) {\n onSaveError?.(error)\n return false\n } finally {\n setIsSaving(false)\n }\n }, [persist, stopCompare, onSaved, onSaveError])\n\n const content = buffer || baseline\n const hasChanges = isEditing && !!buffer && buffer !== baseline\n useEffect(() => {\n onDirtyChange?.(hasChanges)\n return () => onDirtyChange?.(false)\n }, [hasChanges, onDirtyChange])\n\n const setContent = useCallback(\n (markdown: string) => {\n setBuffer(markdown)\n onContentChange?.(markdown)\n },\n [onContentChange]\n )\n const normalized = useCallback((markdown: string) => {\n setBaseline(markdown)\n setBuffer(markdown)\n }, [])\n\n // The diff trails the buffer so it runs on a settled text.\n const [diffContent, setDiffContent] = useState(content)\n useEffect(() => {\n const id = setTimeout(() => setDiffContent(content), diffDelayMs)\n return () => clearTimeout(id)\n }, [content, diffDelayMs])\n\n const redline = useRedline({\n baseText: compareId ? compareText : undefined,\n compareText: compareId ? diffContent || baseline : undefined,\n isLoading: compareLoading,\n withRegions: true,\n engine: redlineEngine,\n })\n const { revertRegion: revertInRedline } = redline\n const revertRegion = useCallback(\n async (regionId: string): Promise<void> => {\n const next = await revertInRedline(regionId)\n if (next !== null) setContent(next)\n },\n [revertInRedline, setContent]\n )\n\n return useMemo(\n () => ({\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n canCompare: !!parentId && !compareId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n change: setContent,\n normalized,\n compare,\n stopCompare,\n setShowTrackChanges,\n revertRegion,\n }),\n [\n isEditing,\n baseline,\n content,\n hasChanges,\n isSaving,\n parentId,\n compareId,\n showTrackChanges,\n redline,\n startEdit,\n cancel,\n save,\n setContent,\n normalized,\n compare,\n stopCompare,\n revertRegion,\n ]\n )\n}\n","import { useCallback, useMemo, useState } from 'react'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys, useDocuments, useParsedDocument } from '../hooks'\nimport {\n buildVersionChain,\n isDocumentId,\n flattenChunks,\n toArtifactVersions,\n versionLabel,\n type ArtifactVersion,\n} from './versions'\nimport {\n useArtifactEditSession,\n type ArtifactEditSession,\n type ArtifactEditSessionOptions,\n type ArtifactSaveResult,\n} from './useArtifactEditSession'\n\n/** The saved markdown of a document (its parsed chunks, joined). */\nexport function useArtifactText(\n docId: string | null | undefined,\n options?: { enabled?: boolean }\n): { text: string | null | undefined; isLoading: boolean } {\n // A local draft has no backend document: asking for its text would be a 422.\n const real = isDocumentId(docId)\n const { data, isLoading, isError } = useParsedDocument(real ? docId : undefined, 'marker', {\n enabled: (options?.enabled ?? true) && real,\n })\n const text = useMemo(() => {\n if (!real) return undefined\n if (isError) return null\n if (!data) return undefined\n return data.chunks?.length ? flattenChunks(data.chunks) : null\n }, [real, data, isError])\n return { text, isLoading: real && isLoading }\n}\n\n/** The version lineage of an artifact in a workspace, oldest first. */\nexport function useArtifactVersions(\n workspaceId: string | undefined,\n docId: string | null | undefined\n): ArtifactVersion[] {\n const { data: documents } = useDocuments(workspaceId)\n return useMemo(\n () => toArtifactVersions(buildVersionChain(documents ?? [], docId)),\n [documents, docId]\n )\n}\n\nexport interface SaveArtifactVersionInput {\n /** File name of the new version (`.md` is added when missing). */\n title: string\n content: string\n /** The version this one is saved from; omit for a first version. */\n parentId?: string | null\n /** The processing config (auto-title, parsing) to run the upload with. */\n configId?: string | null\n /** `artifact` (default) for AI-style drafts; `source` for a document the user typed. */\n wpType?: 'artifact' | 'source'\n}\n\n/**\n * Save markdown as a NEW immutable version (a child document of `parentId`) and refresh the\n * workspace document list so the version list picks it up. The id of the new version is often not\n * known yet (the document is parsed asynchronously); it then arrives through the list.\n */\nexport function useSaveArtifactVersion() {\n const arbi = useArbi()\n const queryClient = useQueryClient()\n return useMutation<\n ArtifactSaveResult,\n Error,\n SaveArtifactVersionInput & { workspaceId?: string }\n >({\n mutationFn: async ({ title, content, parentId, configId, wpType, workspaceId }) => {\n // The backend classifies uploads by extension: a title without one is silently dropped.\n const fileName = /\\.md$/i.test(title) ? title : `${title}.md`\n const result = await arbi.documents.uploadFile(\n new Blob([content], { type: 'text/markdown' }),\n fileName,\n {\n wpType: wpType ?? 'artifact',\n parentExtId: parentId ?? undefined,\n configExtId: configId ?? undefined,\n }\n )\n if (workspaceId) {\n await queryClient.invalidateQueries({ queryKey: arbiQueryKeys.documents(workspaceId) })\n }\n return { docId: result.doc_ext_ids?.[0] }\n },\n })\n}\n\nexport interface ArtifactSessionOptions extends Pick<\n ArtifactEditSessionOptions,\n | 'onSaved'\n | 'onSaveError'\n | 'onCompareChange'\n | 'compareId'\n | 'compareOpensEditor'\n | 'redlineEngine'\n | 'onDirtyChange'\n> {\n workspaceId: string | undefined\n /**\n * The open version, or the placeholder id of an unsaved local draft (anything that is not a\n * backend document id, i.e. does not start with `doc`).\n */\n docId: string | null | undefined\n /**\n * The text of a local draft (nothing is fetched for it). The FIRST save uploads it as a real\n * document with no parent and the session switches to the new id; later saves chain from it.\n */\n draftContent?: string\n /** Name for saved versions. Defaults to the open version's file name, else \"Untitled\". */\n title?: string\n /** Processing config for saved versions. */\n configId?: string | null\n}\n\n/** Everything `ArtifactEditor` (`@arbidocs/blocks/artifacts`) takes from a session, flat. */\nexport interface ArtifactSessionView {\n content: string\n isEditing: boolean\n hasChanges: boolean\n isSaving: boolean\n canCompare: boolean\n comparing: boolean\n compareId: string | null\n showTrackChanges: boolean\n versions: ArtifactVersion[]\n currentVersionId: string\n onStartEdit: () => void\n onCancel: () => void\n onSave: () => void\n onCompare: () => void\n onStopCompare: () => void\n onToggleTrackChanges: () => void\n}\n\nexport interface ArtifactSession extends ArtifactEditSession {\n /** The open document: the new real id once a local draft has been saved. */\n docId: string | null | undefined\n /** The open version is an unsaved local draft (no backend document yet). */\n isLocal: boolean\n isLoading: boolean\n versions: ArtifactVersion[]\n /** \"v2\" for any version in the lineage. */\n labelOf: (id: string | null | undefined) => string | null\n /** Props for `<ArtifactEditor>`. */\n view: ArtifactSessionView\n /** Props for `<ArtifactMarkdownEditor>` (`@arbidocs/blocks/artifacts/editor`). */\n editorProps: {\n markdown: string\n onChange: (markdown: string) => void\n onNormalized: (markdown: string) => void\n }\n /** Props for `<ArtifactRedlineView>`. */\n redlineProps: {\n state: ArtifactEditSession['redline']['state']\n onRevert: (regionId: string) => void\n }\n}\n\n/**\n * Edit an artifact through the SDK: load it, edit it, save it as a new version, list its versions\n * and compare any two with track changes. Needs an `<ArbiProvider>` and a selected workspace.\n *\n * ```tsx\n * const session = useArtifactSession({ workspaceId, docId, onSaved: ({ docId }) => docId && open(docId) })\n * <ArtifactEditor {...session.view} onOpenVersion={open}\n * editor={<ArtifactMarkdownEditor {...session.editorProps} />}\n * redline={<ArtifactRedlineView {...session.redlineProps} />} />\n * ```\n */\nexport function useArtifactSession(options: ArtifactSessionOptions): ArtifactSession {\n const {\n workspaceId,\n docId: hostDocId,\n draftContent,\n title,\n configId,\n compareId,\n onCompareChange,\n onSaved,\n ...passthrough\n } = options\n // A saved local draft becomes this real document; another host docId resets it.\n const [saved, setSaved] = useState<{\n forId: string | null | undefined\n id: string\n text: string\n } | null>(null)\n const adopted = saved && saved.forId === hostDocId ? saved : null\n const docId = adopted?.id ?? hostDocId\n const isLocal = !isDocumentId(docId)\n\n // Owned here (not in the edit session) because the compare target's text must be loaded first.\n const [ownCompareId, setOwnCompareId] = useState<string | null>(null)\n const activeCompareId = compareId === undefined ? ownCompareId : compareId\n const changeCompare = useCallback(\n (id: string | null) => {\n setOwnCompareId(id)\n onCompareChange?.(id)\n },\n [onCompareChange]\n )\n\n const { text, isLoading } = useArtifactText(docId)\n const versions = useArtifactVersions(workspaceId, isLocal ? null : docId)\n const { text: compareText, isLoading: compareLoading } = useArtifactText(activeCompareId, {\n enabled: !!activeCompareId,\n })\n const saveVersion = useSaveArtifactVersion()\n const current = versions.find((v) => v.id === docId)\n\n const save = useCallback(\n async (content: string) => {\n const result = await saveVersion.mutateAsync({\n title: title ?? current?.name ?? 'Untitled',\n content,\n parentId: isLocal ? null : docId,\n configId,\n workspaceId,\n })\n return { ...result, version: isLocal ? 1 : versions.length + 1 }\n },\n [saveVersion, title, current?.name, isLocal, docId, configId, workspaceId, versions.length]\n )\n\n const handleSaved = useCallback(\n (result: ArtifactSaveResult, content: string) => {\n // A host that keeps passing the local draft's placeholder id: follow every save to the real\n // document it created (the first save creates version 1, later ones chain from it).\n if (!isDocumentId(hostDocId) && result.docId)\n setSaved({ forId: hostDocId, id: result.docId, text: content })\n onSaved?.(result, content)\n },\n [hostDocId, onSaved]\n )\n\n const session = useArtifactEditSession({\n ...passthrough,\n docId,\n // A local draft has only its own text; a just-saved one shows what was saved until the parsed\n // text of the new document arrives.\n baseline: text ?? (isLocal ? draftContent : adopted?.text),\n parentId: current?.parentId,\n compareId: activeCompareId,\n onCompareChange: changeCompare,\n compareText,\n compareLoading,\n save,\n onSaved: handleSaved,\n })\n\n const { redline } = session\n return useMemo<ArtifactSession>(\n () => ({\n ...session,\n docId,\n isLocal,\n isLoading,\n versions,\n labelOf: (id) => versionLabel(versions, id),\n view: {\n content: session.baseline,\n isEditing: session.isEditing,\n hasChanges: session.hasChanges,\n isSaving: session.isSaving,\n canCompare: session.canCompare,\n comparing: !!session.compareId,\n compareId: session.compareId,\n showTrackChanges: session.showTrackChanges,\n versions,\n currentVersionId: docId ?? '',\n onStartEdit: session.startEdit,\n onCancel: session.cancel,\n onSave: () => void session.save(),\n onCompare: () => session.compare(),\n onStopCompare: session.stopCompare,\n onToggleTrackChanges: () => session.setShowTrackChanges(!session.showTrackChanges),\n },\n editorProps: {\n markdown: session.content,\n onChange: session.change,\n onNormalized: session.normalized,\n },\n redlineProps: {\n state: redline.state,\n onRevert: (regionId) => void session.revertRegion(regionId),\n },\n }),\n [session, redline, isLoading, isLocal, versions, docId]\n )\n}\n","import type { ComponentPropsWithoutRef, FC, ReactNode } from 'react'\nimport { MarkdownRenderer } from '../ai/MarkdownRenderer'\n\n/** The `<del>` / `<ins>` renderers `ArtifactRedlineView` hands to a markdown renderer. */\nexport interface ArtifactRedlineComponents {\n del: FC<ComponentPropsWithoutRef<'del'> & { 'data-cid'?: string }>\n ins: FC<ComponentPropsWithoutRef<'ins'> & { 'data-cid'?: string }>\n}\n\n/**\n * The kit's markdown renderer as the `renderMarkdown` slot of `ArtifactEditor` and\n * `ArtifactRedlineView`: full markdown (tables, lists, code) plus the raw `<del>` / `<ins>` tags\n * of a redline.\n */\nexport function renderArtifactMarkdown(\n markdown: string,\n components?: ArtifactRedlineComponents\n): ReactNode {\n return <MarkdownRenderer components={components}>{markdown}</MarkdownRenderer>\n}\n"]}
|
|
@@ -91,10 +91,14 @@ declare function versionLabel(versions: readonly ArtifactVersion[], docId: strin
|
|
|
91
91
|
declare function flattenChunks(chunks: readonly {
|
|
92
92
|
content?: string | null;
|
|
93
93
|
}[] | null | undefined): string;
|
|
94
|
+
/** Is `id` a real, saved document id? Local drafts have placeholder ids and no backend document. */
|
|
95
|
+
declare function isDocumentId(id: string | null | undefined): id is string;
|
|
94
96
|
|
|
95
97
|
/** What a save reports back. `docId` is the new version when the backend already knows it. */
|
|
96
98
|
interface ArtifactSaveResult {
|
|
97
99
|
docId?: string;
|
|
100
|
+
/** 1-based number of the version that was just saved (1 for the first save of a draft). */
|
|
101
|
+
version?: number;
|
|
98
102
|
}
|
|
99
103
|
interface ArtifactEditSessionOptions {
|
|
100
104
|
/** The artifact being edited. Changing it discards the buffer and any comparison. */
|
|
@@ -199,8 +203,16 @@ declare function useSaveArtifactVersion(): _tanstack_react_query.UseMutationResu
|
|
|
199
203
|
}, unknown>;
|
|
200
204
|
interface ArtifactSessionOptions extends Pick<ArtifactEditSessionOptions, 'onSaved' | 'onSaveError' | 'onCompareChange' | 'compareId' | 'compareOpensEditor' | 'redlineEngine' | 'onDirtyChange'> {
|
|
201
205
|
workspaceId: string | undefined;
|
|
202
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* The open version, or the placeholder id of an unsaved local draft (anything that is not a
|
|
208
|
+
* backend document id, i.e. does not start with `doc`).
|
|
209
|
+
*/
|
|
203
210
|
docId: string | null | undefined;
|
|
211
|
+
/**
|
|
212
|
+
* The text of a local draft (nothing is fetched for it). The FIRST save uploads it as a real
|
|
213
|
+
* document with no parent and the session switches to the new id; later saves chain from it.
|
|
214
|
+
*/
|
|
215
|
+
draftContent?: string;
|
|
204
216
|
/** Name for saved versions. Defaults to the open version's file name, else "Untitled". */
|
|
205
217
|
title?: string;
|
|
206
218
|
/** Processing config for saved versions. */
|
|
@@ -226,6 +238,10 @@ interface ArtifactSessionView {
|
|
|
226
238
|
onToggleTrackChanges: () => void;
|
|
227
239
|
}
|
|
228
240
|
interface ArtifactSession extends ArtifactEditSession {
|
|
241
|
+
/** The open document: the new real id once a local draft has been saved. */
|
|
242
|
+
docId: string | null | undefined;
|
|
243
|
+
/** The open version is an unsaved local draft (no backend document yet). */
|
|
244
|
+
isLocal: boolean;
|
|
229
245
|
isLoading: boolean;
|
|
230
246
|
versions: ArtifactVersion[];
|
|
231
247
|
/** "v2" for any version in the lineage. */
|
|
@@ -273,4 +289,4 @@ interface ArtifactRedlineComponents {
|
|
|
273
289
|
*/
|
|
274
290
|
declare function renderArtifactMarkdown(markdown: string, components?: ArtifactRedlineComponents): ReactNode;
|
|
275
291
|
|
|
276
|
-
export { type ArtifactEditSession, type ArtifactEditSessionOptions, type ArtifactRedlineComponents, type ArtifactSaveResult, type ArtifactSession, type ArtifactSessionOptions, type ArtifactSessionView, type ArtifactVersion, type RedlineEngine, RedlineRegion, type RedlineState, RedlineWithRegions, type SaveArtifactVersionInput, type UseRedlineOptions, type UseRedlineResult, type VersionedDoc, buildVersionChain, flattenChunks, mainThreadRedlineEngine, renderArtifactMarkdown, toArtifactVersions, useArtifactEditSession, useArtifactSession, useArtifactText, useArtifactVersions, useRedline, useSaveArtifactVersion, versionLabel };
|
|
292
|
+
export { type ArtifactEditSession, type ArtifactEditSessionOptions, type ArtifactRedlineComponents, type ArtifactSaveResult, type ArtifactSession, type ArtifactSessionOptions, type ArtifactSessionView, type ArtifactVersion, type RedlineEngine, RedlineRegion, type RedlineState, RedlineWithRegions, type SaveArtifactVersionInput, type UseRedlineOptions, type UseRedlineResult, type VersionedDoc, buildVersionChain, flattenChunks, isDocumentId, mainThreadRedlineEngine, renderArtifactMarkdown, toArtifactVersions, useArtifactEditSession, useArtifactSession, useArtifactText, useArtifactVersions, useRedline, useSaveArtifactVersion, versionLabel };
|
|
@@ -91,10 +91,14 @@ declare function versionLabel(versions: readonly ArtifactVersion[], docId: strin
|
|
|
91
91
|
declare function flattenChunks(chunks: readonly {
|
|
92
92
|
content?: string | null;
|
|
93
93
|
}[] | null | undefined): string;
|
|
94
|
+
/** Is `id` a real, saved document id? Local drafts have placeholder ids and no backend document. */
|
|
95
|
+
declare function isDocumentId(id: string | null | undefined): id is string;
|
|
94
96
|
|
|
95
97
|
/** What a save reports back. `docId` is the new version when the backend already knows it. */
|
|
96
98
|
interface ArtifactSaveResult {
|
|
97
99
|
docId?: string;
|
|
100
|
+
/** 1-based number of the version that was just saved (1 for the first save of a draft). */
|
|
101
|
+
version?: number;
|
|
98
102
|
}
|
|
99
103
|
interface ArtifactEditSessionOptions {
|
|
100
104
|
/** The artifact being edited. Changing it discards the buffer and any comparison. */
|
|
@@ -199,8 +203,16 @@ declare function useSaveArtifactVersion(): _tanstack_react_query.UseMutationResu
|
|
|
199
203
|
}, unknown>;
|
|
200
204
|
interface ArtifactSessionOptions extends Pick<ArtifactEditSessionOptions, 'onSaved' | 'onSaveError' | 'onCompareChange' | 'compareId' | 'compareOpensEditor' | 'redlineEngine' | 'onDirtyChange'> {
|
|
201
205
|
workspaceId: string | undefined;
|
|
202
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* The open version, or the placeholder id of an unsaved local draft (anything that is not a
|
|
208
|
+
* backend document id, i.e. does not start with `doc`).
|
|
209
|
+
*/
|
|
203
210
|
docId: string | null | undefined;
|
|
211
|
+
/**
|
|
212
|
+
* The text of a local draft (nothing is fetched for it). The FIRST save uploads it as a real
|
|
213
|
+
* document with no parent and the session switches to the new id; later saves chain from it.
|
|
214
|
+
*/
|
|
215
|
+
draftContent?: string;
|
|
204
216
|
/** Name for saved versions. Defaults to the open version's file name, else "Untitled". */
|
|
205
217
|
title?: string;
|
|
206
218
|
/** Processing config for saved versions. */
|
|
@@ -226,6 +238,10 @@ interface ArtifactSessionView {
|
|
|
226
238
|
onToggleTrackChanges: () => void;
|
|
227
239
|
}
|
|
228
240
|
interface ArtifactSession extends ArtifactEditSession {
|
|
241
|
+
/** The open document: the new real id once a local draft has been saved. */
|
|
242
|
+
docId: string | null | undefined;
|
|
243
|
+
/** The open version is an unsaved local draft (no backend document yet). */
|
|
244
|
+
isLocal: boolean;
|
|
229
245
|
isLoading: boolean;
|
|
230
246
|
versions: ArtifactVersion[];
|
|
231
247
|
/** "v2" for any version in the lineage. */
|
|
@@ -273,4 +289,4 @@ interface ArtifactRedlineComponents {
|
|
|
273
289
|
*/
|
|
274
290
|
declare function renderArtifactMarkdown(markdown: string, components?: ArtifactRedlineComponents): ReactNode;
|
|
275
291
|
|
|
276
|
-
export { type ArtifactEditSession, type ArtifactEditSessionOptions, type ArtifactRedlineComponents, type ArtifactSaveResult, type ArtifactSession, type ArtifactSessionOptions, type ArtifactSessionView, type ArtifactVersion, type RedlineEngine, RedlineRegion, type RedlineState, RedlineWithRegions, type SaveArtifactVersionInput, type UseRedlineOptions, type UseRedlineResult, type VersionedDoc, buildVersionChain, flattenChunks, mainThreadRedlineEngine, renderArtifactMarkdown, toArtifactVersions, useArtifactEditSession, useArtifactSession, useArtifactText, useArtifactVersions, useRedline, useSaveArtifactVersion, versionLabel };
|
|
292
|
+
export { type ArtifactEditSession, type ArtifactEditSessionOptions, type ArtifactRedlineComponents, type ArtifactSaveResult, type ArtifactSession, type ArtifactSessionOptions, type ArtifactSessionView, type ArtifactVersion, type RedlineEngine, RedlineRegion, type RedlineState, RedlineWithRegions, type SaveArtifactVersionInput, type UseRedlineOptions, type UseRedlineResult, type VersionedDoc, buildVersionChain, flattenChunks, isDocumentId, mainThreadRedlineEngine, renderArtifactMarkdown, toArtifactVersions, useArtifactEditSession, useArtifactSession, useArtifactText, useArtifactVersions, useRedline, useSaveArtifactVersion, versionLabel };
|