@arbidocs/react 0.4.6 → 0.4.8
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/dist/artifacts/index.cjs +56 -20
- 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 +55 -20
- package/dist/artifacts/index.js.map +1 -1
- package/dist/{chunk-RIHMIEXM.js → chunk-77G7DSUW.js} +27 -4
- package/dist/chunk-77G7DSUW.js.map +1 -0
- package/dist/{chunk-OI55JRKT.cjs → chunk-FUPWPQGK.cjs} +27 -3
- package/dist/chunk-FUPWPQGK.cjs.map +1 -0
- package/dist/{chunk-2ACHNDO6.js → chunk-U7RBOJK3.js} +3 -3
- package/dist/{chunk-2ACHNDO6.js.map → chunk-U7RBOJK3.js.map} +1 -1
- package/dist/{chunk-Z5YCRJY3.cjs → chunk-YURJV3RS.cjs} +4 -4
- package/dist/{chunk-Z5YCRJY3.cjs.map → chunk-YURJV3RS.cjs.map} +1 -1
- package/dist/{index-CC6CvXEs.d.cts → index-4WLy-KDK.d.cts} +10 -1
- package/dist/{index-CC6CvXEs.d.ts → index-4WLy-KDK.d.ts} +10 -1
- package/dist/index.cjs +266 -262
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/ui/index.cjs +132 -128
- package/dist/ui/index.d.cts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-OI55JRKT.cjs.map +0 -1
- package/dist/chunk-RIHMIEXM.js.map +0 -1
|
@@ -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":["useState","useCallback","useRef","useEffect","content","useMemo"],"mappings":"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","file":"index.js","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":["useState","useCallback","useRef","useEffect","content","useMemo"],"mappings":"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","file":"index.js","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"]}
|
|
@@ -167,6 +167,22 @@ var OPEN_CITATION_TAIL = /\[[^\]\n]*(?:\](?:\((?:#(?:c(?:i(?:t(?:e(?:-[\w-]*)?)?
|
|
|
167
167
|
function trimOpenCitation(markdown) {
|
|
168
168
|
return markdown.replace(OPEN_CITATION_TAIL, "");
|
|
169
169
|
}
|
|
170
|
+
function boldMarks(line) {
|
|
171
|
+
return (line.replace(/`[^`]*`/g, "").match(/\*\*/g) ?? []).length;
|
|
172
|
+
}
|
|
173
|
+
function closeOpenEmphasis(markdown) {
|
|
174
|
+
const cut = markdown.lastIndexOf("\n") + 1;
|
|
175
|
+
const head = markdown.slice(0, cut);
|
|
176
|
+
const fences = head.split("\n").filter((l) => /^\s*(```|~~~)/.test(l)).length;
|
|
177
|
+
let line = markdown.slice(cut);
|
|
178
|
+
if (fences % 2 === 1 || /^\s*(```|~~~)/.test(line)) return markdown;
|
|
179
|
+
line = line.replace(/(^|[\s|])\*$/, "$1");
|
|
180
|
+
if (boldMarks(line) % 2 === 0) return head + line;
|
|
181
|
+
line = line.replace(/([^*\s])\*$/, "$1");
|
|
182
|
+
if (boldMarks(line) % 2 === 0) return head + line;
|
|
183
|
+
if (/\*\*\s*$/.test(line)) return head + line.replace(/\s*\*\*\s*$/, " ");
|
|
184
|
+
return head + line + "**";
|
|
185
|
+
}
|
|
170
186
|
function CodeBlock({ language, code }) {
|
|
171
187
|
const [copied, setCopied] = useState(false);
|
|
172
188
|
const handleCopy = async () => {
|
|
@@ -297,7 +313,14 @@ function MarkdownRendererComponent({
|
|
|
297
313
|
a: (props) => props.href?.startsWith("#cite-") ? renderCitation({ num: props.href.slice(6), children: props.children }) : React.createElement(Link, props)
|
|
298
314
|
};
|
|
299
315
|
}, [customComponents, renderCitation]);
|
|
300
|
-
const blocks = useMemo(
|
|
316
|
+
const blocks = useMemo(
|
|
317
|
+
() => splitMarkdownBlocks(
|
|
318
|
+
normalizeCitationMarkup(
|
|
319
|
+
isStreaming ? closeOpenEmphasis(trimOpenCitation(children)) : children
|
|
320
|
+
)
|
|
321
|
+
),
|
|
322
|
+
[children, isStreaming]
|
|
323
|
+
);
|
|
301
324
|
return /* @__PURE__ */ jsx(
|
|
302
325
|
MarkdownErrorBoundary,
|
|
303
326
|
{
|
|
@@ -315,6 +338,6 @@ function MarkdownRendererComponent({
|
|
|
315
338
|
}
|
|
316
339
|
var MarkdownRenderer = React.memo(MarkdownRendererComponent);
|
|
317
340
|
|
|
318
|
-
export { MarkdownRenderer, MarkdownStreamingContext, markdownBaseComponents, normalizeCitationMarkup, splitMarkdownBlocks, trimOpenCitation };
|
|
319
|
-
//# sourceMappingURL=chunk-
|
|
320
|
-
//# sourceMappingURL=chunk-
|
|
341
|
+
export { MarkdownRenderer, MarkdownStreamingContext, closeOpenEmphasis, markdownBaseComponents, normalizeCitationMarkup, splitMarkdownBlocks, trimOpenCitation };
|
|
342
|
+
//# sourceMappingURL=chunk-77G7DSUW.js.map
|
|
343
|
+
//# sourceMappingURL=chunk-77G7DSUW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ai/markdown-base-components.tsx","../src/ai/markdown-streaming-context.ts","../src/ai/split-markdown-blocks.ts","../src/ai/normalize-citations.ts","../src/ai/MarkdownRenderer.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-77G7DSUW.js","sourcesContent":["import React from 'react'\nimport type { Components } from 'react-markdown'\n\n/**\n * Brand-neutral presentational component overrides for react-markdown, shared by\n * every markdown surface in the workspace (the monolith's `MarkdownRenderer` and\n * the AI kit's `AiMarkdown`). One house style for headings, lists, tables and the\n * inline text elements — token-based, so it themes per app.\n *\n * Deliberately excluded (kept per-consumer): `a` (external-link confirm vs\n * plain), `code`/`pre` (rich CodeBlock + Mermaid vs inline), `span` (doc-entity\n * pills), and `del`/`ins`/`mark` (general emphasis vs redline tracked-changes) —\n * these differ by intent or carry heavy/coupled behaviour, so each renderer owns\n * them and spreads this base underneath.\n */\nexport const markdownBaseComponents: Partial<Components> = {\n h1: ({ children, ...props }: React.ComponentPropsWithoutRef<'h1'>) => (\n <h1 className=\"text-lg font-semibold\" data-testid=\"markdown-heading-1\" {...props}>\n {children}\n </h1>\n ),\n h2: ({ children, ...props }: React.ComponentPropsWithoutRef<'h2'>) => (\n <h2 className=\"font-semibold text-base\" data-testid=\"markdown-heading-2\" {...props}>\n {children}\n </h2>\n ),\n h3: ({ children, ...props }: React.ComponentPropsWithoutRef<'h3'>) => (\n <h3 className=\"font-semibold text-base\" data-testid=\"markdown-heading-3\" {...props}>\n {children}\n </h3>\n ),\n h4: ({ children, ...props }: React.ComponentPropsWithoutRef<'h4'>) => (\n <h4 className=\"font-semibold text-base\" {...props}>\n {children}\n </h4>\n ),\n h5: ({ children, ...props }: React.ComponentPropsWithoutRef<'h5'>) => (\n <h5 className=\"font-medium\" {...props}>\n {children}\n </h5>\n ),\n strong: ({ children, ...props }: React.ComponentPropsWithoutRef<'strong'>) => (\n <strong className=\"font-semibold\" {...props}>\n {children}\n </strong>\n ),\n blockquote: ({ children, ...props }: React.ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote className=\"border-l-2 border-primary pl-4\" {...props}>\n {children}\n </blockquote>\n ),\n ol: ({ children, ...props }: React.ComponentPropsWithoutRef<'ol'>) => (\n <ol className=\"list-decimal space-y-2 pl-6\" data-testid=\"markdown-ordered-list\" {...props}>\n {children}\n </ol>\n ),\n ul: ({ children, ...props }: React.ComponentPropsWithoutRef<'ul'>) => (\n <ul className=\"list-none space-y-2 pl-6\" data-testid=\"markdown-unordered-list\" {...props}>\n {children}\n </ul>\n ),\n li: ({ children, ...props }: React.ComponentPropsWithoutRef<'li'>) => (\n <li className=\"my-1.5\" {...props}>\n {children}\n </li>\n ),\n table: ({ children, ...props }: React.ComponentPropsWithoutRef<'table'>) => (\n <table data-testid=\"markdown-table\" {...props}>\n {children}\n </table>\n ),\n th: ({ children, ...props }: React.ComponentPropsWithoutRef<'th'>) => (\n <th {...props}>{children}</th>\n ),\n td: ({ children, ...props }: React.ComponentPropsWithoutRef<'td'>) => (\n <td {...props}>{children}</td>\n ),\n tr: ({ children, ...props }: React.ComponentPropsWithoutRef<'tr'>) => (\n <tr {...props}>{children}</tr>\n ),\n p: ({ children, ...props }: React.ComponentPropsWithoutRef<'p'>) => (\n <p className=\"whitespace-pre-wrap\" {...props}>\n {children}\n </p>\n ),\n hr: (props: React.ComponentPropsWithoutRef<'hr'>) => (\n <hr className=\"border-foreground/20\" {...props} />\n ),\n sup: ({ children, ...props }: React.ComponentPropsWithoutRef<'sup'>) => (\n <sup className=\"text-xs\" {...props}>\n {children}\n </sup>\n ),\n sub: ({ children, ...props }: React.ComponentPropsWithoutRef<'sub'>) => (\n <sub className=\"text-xs\" {...props}>\n {children}\n </sub>\n ),\n div: ({ children, className, ...props }: React.ComponentPropsWithoutRef<'div'>) => (\n <div className={className} {...props}>\n {children}\n </div>\n ),\n br: (props: React.ComponentPropsWithoutRef<'br'>) => <br {...props} />,\n kbd: ({ children, ...props }: React.ComponentPropsWithoutRef<'kbd'>) => (\n <kbd\n className=\"px-1.5 py-0.5 text-xs font-mono bg-muted border border-border rounded\"\n {...props}\n >\n {children}\n </kbd>\n ),\n abbr: ({ children, title, ...props }: React.ComponentPropsWithoutRef<'abbr'>) => (\n <abbr title={title} className=\"underline decoration-dotted cursor-help\" {...props}>\n {children}\n </abbr>\n ),\n cite: ({ children, ...props }: React.ComponentPropsWithoutRef<'cite'>) => (\n <cite className=\"italic\" {...props}>\n {children}\n </cite>\n ),\n}\n","import { createContext } from 'react'\n\n/**\n * Signals to `MarkdownRenderer`'s component overrides that the surrounding\n * message is still streaming tokens. Heavy renderers can defer their work while\n * this is true to avoid burning CPU on partially complete fences and to keep the\n * UI responsive during long generations.\n *\n * Default `false` means non-streaming usages (parsed documents, static answers,\n * DM bubbles) get the full rendering with no behaviour change.\n */\nexport const MarkdownStreamingContext = createContext(false)\n","/**\n * Splits a markdown string into top-level blocks at `\\n\\n` boundaries.\n *\n * Streaming AI responses arrive token-by-token; passing the full string to\n * react-markdown re-parses the entire AST on every flush. By splitting into\n * blocks and memoizing each, only the trailing (still-growing) block re-parses\n * — completed blocks stay frozen in the DOM.\n *\n * The split avoids three correctness pitfalls:\n * - never splits inside an open ``` code fence (would corrupt the language)\n * - never splits between two adjacent list items (would render as two lists)\n * - never splits between two blockquote lines (would render as two quotes)\n */\nconst LIST_ITEM_RE = /^\\s*([-*+]|\\d+[.)])\\s/\nconst BLOCKQUOTE_RE = /^\\s*>/\n\nexport function splitMarkdownBlocks(content: string): string[] {\n if (!content) return []\n const blocks: string[] = []\n let start = 0\n let inFence = false\n let i = 0\n while (i < content.length) {\n if (content.startsWith('```', i)) {\n inFence = !inFence\n i += 3\n continue\n }\n if (!inFence && content[i] === '\\n' && content[i + 1] === '\\n') {\n const before = content.slice(start, i)\n const lastLine = before.slice(before.lastIndexOf('\\n') + 1)\n const afterStart = i + 2\n const nextNewline = content.indexOf('\\n', afterStart)\n const nextLine = content.slice(afterStart, nextNewline === -1 ? undefined : nextNewline)\n const bothListItems = LIST_ITEM_RE.test(lastLine) && LIST_ITEM_RE.test(nextLine)\n const bothBlockquotes = BLOCKQUOTE_RE.test(lastLine) && BLOCKQUOTE_RE.test(nextLine)\n if (bothListItems || bothBlockquotes) {\n i += 2\n continue\n }\n blocks.push(content.slice(start, afterStart))\n start = afterStart\n i = afterStart\n continue\n }\n i++\n }\n if (start < content.length) blocks.push(content.slice(start))\n return blocks\n}\n","/**\n * Citation markup normaliser.\n *\n * The backend marks a cited statement as a markdown link, `[statement](#cite-N)`, and the\n * statement can include the markdown that surrounds it: a list marker, a heading marker or the\n * opener of a bold/italic span whose closer sits after the link. Inside link text those tokens\n * are not parsed as block or inline syntax, so they show literally and break lists and bold:\n *\n * [- **Claimed quantum (by Claimant)](#cite-1):** **USD 47 million**\n *\n * `normalizeCitationMarkup` hoists the leading tokens out of the link text (and a trailing\n * emphasis closer after it), so the link only wraps the words:\n *\n * - **[Claimed quantum (by Claimant)](#cite-1):** **USD 47 million**\n *\n * It is conservative: emphasis that opens and closes inside the link text is valid markdown and\n * is left alone, an opener is only hoisted when its closer follows on the same line, and fenced\n * code blocks are never touched. The result is idempotent.\n *\n * It also tidies the residue the model leaves when it cites in prose as well: a literal\n * `(*Source: Award.pdf, p. 12*)` shows its asterisks, because `(*` does not open emphasis. It\n * becomes the italic note `*(Source: Award.pdf, p. 12)*`.\n */\n\nconst SOURCE_RESIDUE = /\\(\\*+\\s*(Sources?\\s*:[^\\n]*?)\\s*\\*+\\)/g\n\nconst CITE_LINK = /\\[([^\\]\\n]+)\\]\\((#cite-[\\w-]+)\\)/g\nconst BLOCK_MARKER = /^(?:[-*+]|\\d{1,9}[.)]|#{1,6})[ \\t]+/\nconst LEADING_EMPHASIS = /^(?:\\*\\*|__|\\*|_)+/\nconst TRAILING_EMPHASIS = /(\\*\\*|__|\\*|_)(:?)$/\n\n/** Occurrences of `token` in `text`; a single `*` is counted outside any `**` pair. */\nfunction countToken(text: string, token: string): number {\n const double = token + token\n if (token.length === 2) return text.split(token).length - 1\n const withoutDouble = text.split(double).join('')\n return withoutDouble.split(token).length - 1\n}\n\n/** Split a run of emphasis characters (`***`, `**`, `*`...) into its parser-level tokens. */\nfunction emphasisTokens(run: string): string[] {\n const char = run[0]\n const tokens: string[] = []\n let rest = run\n while (rest.length > 0) {\n const size = rest.length >= 2 ? 2 : 1\n tokens.push(char.repeat(size))\n rest = rest.slice(size)\n }\n return tokens\n}\n\nfunction hoistFromLink(text: string, before: string, after: string): [string, string, string] {\n let body = text\n let prefix = ''\n let suffix = ''\n\n if (before.trim() === '') {\n const marker = BLOCK_MARKER.exec(body)\n if (marker) {\n prefix += marker[0]\n body = body.slice(marker[0].length)\n }\n }\n\n const leading = LEADING_EMPHASIS.exec(body)\n if (leading) {\n let kept = ''\n let rest = body.slice(leading[0].length)\n for (const token of emphasisTokens(leading[0]).reverse()) {\n // Balanced inside the link text: valid as written.\n if (countToken(rest, token) % 2 === 1) {\n kept = token + kept\n continue\n }\n // Unmatched here: hoist only if the line closes it after the link.\n if (countToken(after, token) % 2 === 1) prefix += token\n else kept = token + kept\n }\n body = kept + rest\n rest = ''\n }\n\n const trailing = TRAILING_EMPHASIS.exec(body)\n if (trailing) {\n const token = trailing[1]\n const inner = body.slice(0, body.length - trailing[0].length)\n const openedBefore = countToken(before + prefix, token) % 2 === 1\n if (countToken(inner, token) % 2 === 0 && openedBefore) {\n body = inner\n suffix = trailing[0]\n }\n }\n\n return [prefix, body, suffix]\n}\n\nfunction normalizeLine(line: string): string {\n if (!line.includes('](#cite-')) return line\n return line.replace(CITE_LINK, (match, text: string, href: string, offset: number) => {\n const before = line.slice(0, offset)\n const after = line.slice(offset + match.length)\n const [prefix, body, suffix] = hoistFromLink(text, before, after)\n if (!prefix && !suffix && body === text) return match\n return `${prefix}[${body}](${href})${suffix}`\n })\n}\n\nfunction normalizeSourceResidue(line: string): string {\n return line.includes('(*') ? line.replace(SOURCE_RESIDUE, '*($1)*') : line\n}\n\nexport function normalizeCitationMarkup(markdown: string): string {\n if (!markdown.includes('](#cite-') && !markdown.includes('(*')) return markdown\n let inFence = false\n return markdown\n .split('\\n')\n .map((line) => {\n if (/^\\s*(```|~~~)/.test(line)) {\n inFence = !inFence\n return line\n }\n return inFence ? line : normalizeSourceResidue(normalizeLine(line))\n })\n .join('\\n')\n}\n\n/** A trailing, still-open `[words](#cite-N` marker (or an unclosed `[words`) on the last line. */\nconst OPEN_CITATION_TAIL = /\\[[^\\]\\n]*(?:\\](?:\\((?:#(?:c(?:i(?:t(?:e(?:-[\\w-]*)?)?)?)?)?)?)?)?$/\n\n/**\n * Drops an unfinished citation marker from the end of text that is still streaming (or was\n * stopped mid-marker), so `[Change of control](#cite-` never shows as raw markup: the words appear\n * once the marker is complete. Complete markers and everything else are left alone.\n */\nexport function trimOpenCitation(markdown: string): string {\n return markdown.replace(OPEN_CITATION_TAIL, '')\n}\n\n/** `**` pairs outside inline code in a line. */\nfunction boldMarks(line: string): number {\n return (line.replace(/`[^`]*`/g, '').match(/\\*\\*/g) ?? []).length\n}\n\n/**\n * Makes the tail of text that is still streaming (or was stopped) render cleanly: a `**` opened\n * in the last line and not yet closed (`| Valuation | **[USD 6.2 million](#cite-2)`) would show as\n * literal asterisks until its closer arrives, because an unclosed emphasis is not emphasis. The\n * open bold is closed at the end of the line, or removed when it has no text yet (`| **`, or a\n * half-typed closer `**USD 6*`). Text with balanced emphasis, and every line but the last, is\n * left alone. Apply after `trimOpenCitation`.\n */\nexport function closeOpenEmphasis(markdown: string): string {\n const cut = markdown.lastIndexOf('\\n') + 1\n const head = markdown.slice(0, cut)\n const fences = head.split('\\n').filter((l) => /^\\s*(```|~~~)/.test(l)).length\n let line = markdown.slice(cut)\n if (fences % 2 === 1 || /^\\s*(```|~~~)/.test(line)) return markdown\n // A half-typed opener: the first `*` of `**` after a space or a cell border.\n line = line.replace(/(^|[\\s|])\\*$/, '$1')\n if (boldMarks(line) % 2 === 0) return head + line\n // A half-typed closer: `**USD 6*` -> the second asterisk has not arrived.\n line = line.replace(/([^*\\s])\\*$/, '$1')\n if (boldMarks(line) % 2 === 0) return head + line\n if (/\\*\\*\\s*$/.test(line)) return head + line.replace(/\\s*\\*\\*\\s*$/, ' ')\n return head + line + '**'\n}\n","import React, { useMemo, useState } from 'react'\nimport Markdown, { type Components } from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport rehypeRaw from 'rehype-raw'\nimport { Copy, Check } from 'lucide-react'\nimport { cn } from '../lib/utils'\nimport { markdownBaseComponents } from './markdown-base-components'\nimport { MarkdownStreamingContext } from './markdown-streaming-context'\nimport { splitMarkdownBlocks } from './split-markdown-blocks'\nimport { closeOpenEmphasis, normalizeCitationMarkup, trimOpenCitation } from './normalize-citations'\n\n/**\n * MarkdownRenderer — the single, full-featured markdown surface for the kit.\n *\n * Renders AI answers, chat/DM messages and parsed-document panes with one house\n * style: headings, paragraphs, bold/italic, ordered/unordered lists, GFM tables,\n * fenced code blocks (monospace + copy button), inline code, blockquotes, safe\n * links (`rel=\"noopener\"`, new tab) and horizontal rules.\n *\n * Styling is 100% semantic Tailwind tokens (`text-foreground`,\n * `text-muted-foreground`, `border-border`, `bg-muted`, `text-primary`) so it\n * themes per firm — no hardcoded brand colours. It sizes to its container, so it\n * looks right in a compact chat bubble and in a full-width document pane alike.\n *\n * Streaming: the content is split into block-level chunks (see\n * `splitMarkdownBlocks`) and each chunk is memoised, so streaming token updates\n * only re-parse the trailing block instead of the whole message. Pass\n * `isStreaming` to let heavy custom components defer via `MarkdownStreamingContext`.\n *\n * Extending: pass `components` to override any element (the kit's `AiMarkdown`\n * and `CitationRenderer` layer their accent links / citation popovers on top).\n */\n\n/** Fenced code block with a language label and copy-to-clipboard button. */\nfunction CodeBlock({ language, code }: { language: string; code: string }) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(code)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Clipboard unavailable (insecure context / permissions) — no-op.\n }\n }\n\n return (\n <div\n className=\"code-block relative my-3 overflow-hidden rounded-md border border-current/20 bg-current/5\"\n data-testid=\"markdown-code-block\"\n >\n <div className=\"flex items-center justify-between border-b border-current/20 px-3 py-1.5\">\n <span className=\"font-mono text-xs text-muted-foreground\">{language || 'code'}</span>\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground\"\n title={copied ? 'Copied!' : 'Copy code'}\n >\n {copied ? <Check size={12} /> : <Copy size={12} />}\n <span>{copied ? 'Copied' : 'Copy'}</span>\n </button>\n </div>\n <pre className=\"overflow-x-auto p-3 text-sm leading-relaxed\">\n <code className={cn('font-mono', language && `language-${language}`)}>{code}</code>\n </pre>\n </div>\n )\n}\n\n/**\n * Links. Internal hash/anchor links stay in-page; everything else opens safely in a new tab\n * (`rel=\"noopener noreferrer\"` prevents reverse-tabnabbing). A backend citation marker\n * (`#cite-N`) has no popover here: the cited words stay in the surface's own colour with a quiet\n * superscript number after them (no underline, so a cited sentence does not read as a link).\n * Pass `renderCitation` to `MarkdownRenderer` to swap in a real source popover.\n */\nfunction MarkdownLink({ href, children, ...props }: React.ComponentPropsWithoutRef<'a'>) {\n if (href?.startsWith('#cite-')) {\n return (\n <span\n className=\"cited-text after:ml-px after:align-super after:text-[0.7em] after:font-medium after:text-muted-foreground after:content-[attr(data-cite)]\"\n data-cite={href.slice(6)}\n >\n {children}\n </span>\n )\n }\n const isInternal = !href || href.startsWith('#') || href.startsWith('cite:')\n return (\n <a\n className=\"text-primary underline underline-offset-2\"\n href={href}\n {...(isInternal ? {} : { target: '_blank', rel: 'noopener noreferrer' })}\n {...props}\n >\n {children}\n </a>\n )\n}\n\n/**\n * Default component overrides. Spreads the shared brand-neutral base\n * (`markdownBaseComponents`: headings, lists, paragraphs, emphasis, hr…) and adds\n * the elements that carry behaviour or need self-contained styling: safe links,\n * code (inline + fenced), bordered tables and blockquotes. Module-scoped so the\n * reference is stable across renders and react-markdown can skip re-parsing.\n */\nconst defaultComponents: Partial<Components> = {\n ...markdownBaseComponents,\n a: MarkdownLink,\n em: ({ children, ...props }: React.ComponentPropsWithoutRef<'em'>) => (\n <em className=\"italic\" {...props}>\n {children}\n </em>\n ),\n code: function MarkdownCode({\n className,\n children,\n ...props\n }: React.ComponentPropsWithoutRef<'code'>) {\n const match = /language-(\\w+)/.exec(className || '')\n if (!match) {\n return (\n <code\n className=\"rounded bg-current/10 px-1 py-0.5 font-mono text-[0.9em]\"\n data-testid=\"markdown-inline-code\"\n {...props}\n >\n {children}\n </code>\n )\n }\n return <CodeBlock language={match[1]} code={String(children).replace(/\\n$/, '')} />\n },\n // The CodeBlock renders its own <pre>; unwrap react-markdown's wrapper so we\n // don't nest <pre><pre>.\n pre: ({ children }: React.ComponentPropsWithoutRef<'pre'>) => <>{children}</>,\n blockquote: ({ children, ...props }: React.ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote className=\"border-l-2 border-border pl-4 italic text-muted-foreground\" {...props}>\n {children}\n </blockquote>\n ),\n table: ({ children, ...props }: React.ComponentPropsWithoutRef<'table'>) => (\n <div className=\"my-3 overflow-x-auto rounded-lg border border-border\">\n <table data-testid=\"markdown-table\" className=\"w-full border-collapse text-sm\" {...props}>\n {children}\n </table>\n </div>\n ),\n thead: ({ children, ...props }: React.ComponentPropsWithoutRef<'thead'>) => (\n <thead className=\"bg-current/10\" {...props}>\n {children}\n </thead>\n ),\n th: ({ children, ...props }: React.ComponentPropsWithoutRef<'th'>) => (\n <th className=\"border-b border-border px-3 py-2 text-left font-semibold\" {...props}>\n {children}\n </th>\n ),\n td: ({ children, ...props }: React.ComponentPropsWithoutRef<'td'>) => (\n <td className=\"border-b border-border px-3 py-2 align-top\" {...props}>\n {children}\n </td>\n ),\n // General emphasis marks (GFM `~~strikethrough~~` → <del>, raw <ins>/<mark>).\n del: ({ children, ...props }: React.ComponentPropsWithoutRef<'del'>) => (\n <del className=\"text-muted-foreground line-through\" {...props}>\n {children}\n </del>\n ),\n ins: ({ children, ...props }: React.ComponentPropsWithoutRef<'ins'>) => (\n <ins className=\"underline decoration-primary/60\" {...props}>\n {children}\n </ins>\n ),\n mark: ({ children, ...props }: React.ComponentPropsWithoutRef<'mark'>) => (\n <mark className=\"rounded bg-primary/15 px-0.5 text-inherit\" {...props}>\n {children}\n </mark>\n ),\n}\n\n// Stable module-scope plugin arrays so react-markdown compares them by reference\n// and skips re-running the remark/rehype pipeline when nothing else changed.\n// `rehype-raw` enables inline HTML (e.g. redline <del>/<ins>); no math/mermaid\n// plugins are bundled to keep the kit light.\nconst remarkPlugins = [remarkGfm]\nconst rehypePlugins = [rehypeRaw]\n\n/**\n * One parsed markdown block, memoised on (content, components) so already-rendered\n * blocks don't re-parse when a later block streams new tokens. This is the core\n * of the streaming-rendering optimisation.\n */\nconst MemoizedBlock = React.memo(function MarkdownBlock({\n content,\n components,\n}: {\n content: string\n components: Partial<Components>\n}) {\n return (\n <Markdown remarkPlugins={remarkPlugins} rehypePlugins={rehypePlugins} components={components}>\n {content}\n </Markdown>\n )\n})\n\n/** Prevents a malformed-markdown render error from crashing the whole surface. */\nclass MarkdownErrorBoundary extends React.Component<\n { fallback: React.ReactNode; children: React.ReactNode },\n { hasError: boolean }\n> {\n state = { hasError: false }\n static getDerivedStateFromError() {\n return { hasError: true }\n }\n render() {\n return this.state.hasError ? this.props.fallback : this.props.children\n }\n}\n\nexport interface MarkdownRendererProps {\n /** Markdown content to render. */\n children: string\n /** Custom component overrides merged on top of the defaults. */\n components?: Partial<Components>\n /**\n * When true, signals heavy custom components (via `MarkdownStreamingContext`)\n * to defer their work while tokens are still arriving. Defaults to false.\n */\n isStreaming?: boolean\n /**\n * Renders a citation marker `[words](#cite-N)`: `children` are the cited words, `num` the N.\n * Keep it referentially stable (`useCallback`/`useMemo`), or every block re-parses.\n */\n renderCitation?: (citation: { num: string; children: React.ReactNode }) => React.ReactNode\n /** Extra classes on the wrapper (font-size, prose width, etc.). */\n className?: string\n /** Overrides the `data-testid` on the wrapper (default `markdown-renderer`). */\n testId?: string\n}\n\nfunction MarkdownRendererComponent({\n children,\n components: customComponents,\n renderCitation,\n isStreaming = false,\n className,\n testId = 'markdown-renderer',\n}: MarkdownRendererProps) {\n const components = useMemo(() => {\n const base = customComponents\n ? { ...defaultComponents, ...customComponents }\n : defaultComponents\n if (!renderCitation) return base\n const Link = base.a ?? MarkdownLink\n return {\n ...base,\n a: (props: React.ComponentPropsWithoutRef<'a'>) =>\n props.href?.startsWith('#cite-')\n ? renderCitation({ num: props.href.slice(6), children: props.children })\n : React.createElement(Link as React.ElementType, props),\n }\n }, [customComponents, renderCitation])\n\n const blocks = useMemo(\n () =>\n splitMarkdownBlocks(\n normalizeCitationMarkup(\n isStreaming ? closeOpenEmphasis(trimOpenCitation(children)) : children\n )\n ),\n [children, isStreaming]\n )\n\n return (\n <MarkdownErrorBoundary\n fallback={<div className={cn('whitespace-pre-wrap break-words', className)}>{children}</div>}\n >\n <MarkdownStreamingContext.Provider value={isStreaming}>\n <div\n className={cn('markdown-content space-y-3 break-words leading-relaxed', className)}\n data-testid={testId}\n >\n {blocks.map((block, index) => (\n <MemoizedBlock key={index} content={block} components={components} />\n ))}\n </div>\n </MarkdownStreamingContext.Provider>\n </MarkdownErrorBoundary>\n )\n}\n\n/**\n * Memoised so a stable message in a long thread doesn't re-parse when unrelated\n * tokens arrive elsewhere; a streaming message gets a fresh `children` each flush\n * and re-renders (only its trailing block re-parses, thanks to `MemoizedBlock`).\n */\nexport const MarkdownRenderer = React.memo(MarkdownRendererComponent)\n"]}
|
|
@@ -176,6 +176,22 @@ var OPEN_CITATION_TAIL = /\[[^\]\n]*(?:\](?:\((?:#(?:c(?:i(?:t(?:e(?:-[\w-]*)?)?
|
|
|
176
176
|
function trimOpenCitation(markdown) {
|
|
177
177
|
return markdown.replace(OPEN_CITATION_TAIL, "");
|
|
178
178
|
}
|
|
179
|
+
function boldMarks(line) {
|
|
180
|
+
return (line.replace(/`[^`]*`/g, "").match(/\*\*/g) ?? []).length;
|
|
181
|
+
}
|
|
182
|
+
function closeOpenEmphasis(markdown) {
|
|
183
|
+
const cut = markdown.lastIndexOf("\n") + 1;
|
|
184
|
+
const head = markdown.slice(0, cut);
|
|
185
|
+
const fences = head.split("\n").filter((l) => /^\s*(```|~~~)/.test(l)).length;
|
|
186
|
+
let line = markdown.slice(cut);
|
|
187
|
+
if (fences % 2 === 1 || /^\s*(```|~~~)/.test(line)) return markdown;
|
|
188
|
+
line = line.replace(/(^|[\s|])\*$/, "$1");
|
|
189
|
+
if (boldMarks(line) % 2 === 0) return head + line;
|
|
190
|
+
line = line.replace(/([^*\s])\*$/, "$1");
|
|
191
|
+
if (boldMarks(line) % 2 === 0) return head + line;
|
|
192
|
+
if (/\*\*\s*$/.test(line)) return head + line.replace(/\s*\*\*\s*$/, " ");
|
|
193
|
+
return head + line + "**";
|
|
194
|
+
}
|
|
179
195
|
function CodeBlock({ language, code }) {
|
|
180
196
|
const [copied, setCopied] = React.useState(false);
|
|
181
197
|
const handleCopy = async () => {
|
|
@@ -306,7 +322,14 @@ function MarkdownRendererComponent({
|
|
|
306
322
|
a: (props) => props.href?.startsWith("#cite-") ? renderCitation({ num: props.href.slice(6), children: props.children }) : React__default.default.createElement(Link, props)
|
|
307
323
|
};
|
|
308
324
|
}, [customComponents, renderCitation]);
|
|
309
|
-
const blocks = React.useMemo(
|
|
325
|
+
const blocks = React.useMemo(
|
|
326
|
+
() => splitMarkdownBlocks(
|
|
327
|
+
normalizeCitationMarkup(
|
|
328
|
+
isStreaming ? closeOpenEmphasis(trimOpenCitation(children)) : children
|
|
329
|
+
)
|
|
330
|
+
),
|
|
331
|
+
[children, isStreaming]
|
|
332
|
+
);
|
|
310
333
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
311
334
|
MarkdownErrorBoundary,
|
|
312
335
|
{
|
|
@@ -326,9 +349,10 @@ var MarkdownRenderer = React__default.default.memo(MarkdownRendererComponent);
|
|
|
326
349
|
|
|
327
350
|
exports.MarkdownRenderer = MarkdownRenderer;
|
|
328
351
|
exports.MarkdownStreamingContext = MarkdownStreamingContext;
|
|
352
|
+
exports.closeOpenEmphasis = closeOpenEmphasis;
|
|
329
353
|
exports.markdownBaseComponents = markdownBaseComponents;
|
|
330
354
|
exports.normalizeCitationMarkup = normalizeCitationMarkup;
|
|
331
355
|
exports.splitMarkdownBlocks = splitMarkdownBlocks;
|
|
332
356
|
exports.trimOpenCitation = trimOpenCitation;
|
|
333
|
-
//# sourceMappingURL=chunk-
|
|
334
|
-
//# sourceMappingURL=chunk-
|
|
357
|
+
//# sourceMappingURL=chunk-FUPWPQGK.cjs.map
|
|
358
|
+
//# sourceMappingURL=chunk-FUPWPQGK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ai/markdown-base-components.tsx","../src/ai/markdown-streaming-context.ts","../src/ai/split-markdown-blocks.ts","../src/ai/normalize-citations.ts","../src/ai/MarkdownRenderer.tsx"],"names":["jsx","createContext","useState","jsxs","Check","Copy","cn","Fragment","remarkGfm","rehypeRaw","React","Markdown","useMemo"],"mappings":";;;;;;;;;;;;;;;;;AAeO,IAAM,sBAAA,GAA8C;AAAA,EACzD,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,WAAU,uBAAA,EAAwB,aAAA,EAAY,oBAAA,EAAsB,GAAG,OACxE,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,WAAU,yBAAA,EAA0B,aAAA,EAAY,oBAAA,EAAsB,GAAG,OAC1E,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,WAAU,yBAAA,EAA0B,aAAA,EAAY,oBAAA,EAAsB,GAAG,OAC1E,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,yBAAA,EAA2B,GAAG,OACzC,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,aAAA,EAAe,GAAG,OAC7B,QAAA,EACH,CAAA;AAAA,EAEF,MAAA,EAAQ,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAC5BA,cAAA,CAAC,QAAA,EAAA,EAAO,SAAA,EAAU,eAAA,EAAiB,GAAG,OACnC,QAAA,EACH,CAAA;AAAA,EAEF,UAAA,EAAY,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAChCA,cAAA,CAAC,YAAA,EAAA,EAAW,SAAA,EAAU,gCAAA,EAAkC,GAAG,OACxD,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,WAAU,6BAAA,EAA8B,aAAA,EAAY,uBAAA,EAAyB,GAAG,OACjF,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,WAAU,0BAAA,EAA2B,aAAA,EAAY,yBAAA,EAA2B,GAAG,OAChF,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,QAAA,EAAU,GAAG,OACxB,QAAA,EACH,CAAA;AAAA,EAEF,KAAA,EAAO,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAC3BA,cAAA,CAAC,OAAA,EAAA,EAAM,aAAA,EAAY,gBAAA,EAAkB,GAAG,OACrC,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAI,GAAG,KAAA,EAAQ,QAAA,EAAS,CAAA;AAAA,EAE3B,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAI,GAAG,KAAA,EAAQ,QAAA,EAAS,CAAA;AAAA,EAE3B,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAA,CAAC,IAAA,EAAA,EAAI,GAAG,KAAA,EAAQ,QAAA,EAAS,CAAA;AAAA,EAE3B,CAAA,EAAG,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACvBA,cAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,qBAAA,EAAuB,GAAG,OACpC,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,KAAA,qBACHA,cAAA,CAAC,QAAG,SAAA,EAAU,sBAAA,EAAwB,GAAG,KAAA,EAAO,CAAA;AAAA,EAElD,GAAA,EAAK,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACzBA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EAAW,GAAG,OAC1B,QAAA,EACH,CAAA;AAAA,EAEF,GAAA,EAAK,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACzBA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EAAW,GAAG,OAC1B,QAAA,EACH,CAAA;AAAA,EAEF,GAAA,EAAK,CAAC,EAAE,QAAA,EAAU,SAAA,EAAW,GAAG,KAAA,EAAM,qBACpCA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAuB,GAAG,OAC5B,QAAA,EACH,CAAA;AAAA,EAEF,IAAI,CAAC,KAAA,qBAAgDA,cAAA,CAAC,IAAA,EAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AAAA,EACpE,KAAK,CAAC,EAAE,QAAA,EAAU,GAAG,OAAM,qBACzBA,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,uEAAA;AAAA,MACT,GAAG,KAAA;AAAA,MAEH;AAAA;AAAA,GACH;AAAA,EAEF,IAAA,EAAM,CAAC,EAAE,QAAA,EAAU,OAAO,GAAG,KAAA,EAAM,qBACjCA,cAAA,CAAC,UAAK,KAAA,EAAc,SAAA,EAAU,yCAAA,EAA2C,GAAG,OACzE,QAAA,EACH,CAAA;AAAA,EAEF,IAAA,EAAM,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAC1BA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAU,GAAG,OAC1B,QAAA,EACH;AAEJ;AC/GO,IAAM,wBAAA,GAA2BC,oBAAc,KAAK;;;ACE3D,IAAM,YAAA,GAAe,uBAAA;AACrB,IAAM,aAAA,GAAgB,OAAA;AAEf,SAAS,oBAAoB,OAAA,EAA2B;AAC7D,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AACtB,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,CAAA,GAAI,QAAQ,MAAA,EAAQ;AACzB,IAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,KAAA,EAAO,CAAC,CAAA,EAAG;AAChC,MAAA,OAAA,GAAU,CAAC,OAAA;AACX,MAAA,CAAA,IAAK,CAAA;AACL,MAAA;AAAA,IACF;AACA,IAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,CAAC,CAAA,KAAM,QAAQ,OAAA,CAAQ,CAAA,GAAI,CAAC,CAAA,KAAM,IAAA,EAAM;AAC9D,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,CAAC,CAAA;AACrC,MAAA,MAAM,WAAW,MAAA,CAAO,KAAA,CAAM,OAAO,WAAA,CAAY,IAAI,IAAI,CAAC,CAAA;AAC1D,MAAA,MAAM,aAAa,CAAA,GAAI,CAAA;AACvB,MAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,IAAA,EAAM,UAAU,CAAA;AACpD,MAAA,MAAM,WAAW,OAAA,CAAQ,KAAA,CAAM,YAAY,WAAA,KAAgB,EAAA,GAAK,SAAY,WAAW,CAAA;AACvF,MAAA,MAAM,gBAAgB,YAAA,CAAa,IAAA,CAAK,QAAQ,CAAA,IAAK,YAAA,CAAa,KAAK,QAAQ,CAAA;AAC/E,MAAA,MAAM,kBAAkB,aAAA,CAAc,IAAA,CAAK,QAAQ,CAAA,IAAK,aAAA,CAAc,KAAK,QAAQ,CAAA;AACnF,MAAA,IAAI,iBAAiB,eAAA,EAAiB;AACpC,QAAA,CAAA,IAAK,CAAA;AACL,QAAA;AAAA,MACF;AACA,MAAA,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,UAAU,CAAC,CAAA;AAC5C,MAAA,KAAA,GAAQ,UAAA;AACR,MAAA,CAAA,GAAI,UAAA;AACJ,MAAA;AAAA,IACF;AACA,IAAA,CAAA,EAAA;AAAA,EACF;AACA,EAAA,IAAI,KAAA,GAAQ,QAAQ,MAAA,EAAQ,MAAA,CAAO,KAAK,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAC,CAAA;AAC5D,EAAA,OAAO,MAAA;AACT;;;ACzBA,IAAM,cAAA,GAAiB,wCAAA;AAEvB,IAAM,SAAA,GAAY,mCAAA;AAClB,IAAM,YAAA,GAAe,qCAAA;AACrB,IAAM,gBAAA,GAAmB,oBAAA;AACzB,IAAM,iBAAA,GAAoB,qBAAA;AAG1B,SAAS,UAAA,CAAW,MAAc,KAAA,EAAuB;AACvD,EAAA,MAAM,SAAS,KAAA,GAAQ,KAAA;AACvB,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG,OAAO,KAAK,KAAA,CAAM,KAAK,EAAE,MAAA,GAAS,CAAA;AAC1D,EAAA,MAAM,gBAAgB,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,CAAE,KAAK,EAAE,CAAA;AAChD,EAAA,OAAO,aAAA,CAAc,KAAA,CAAM,KAAK,CAAA,CAAE,MAAA,GAAS,CAAA;AAC7C;AAGA,SAAS,eAAe,GAAA,EAAuB;AAC7C,EAAA,MAAM,IAAA,GAAO,IAAI,CAAC,CAAA;AAClB,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,IAAI,IAAA,GAAO,GAAA;AACX,EAAA,OAAO,IAAA,CAAK,SAAS,CAAA,EAAG;AACtB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,IAAU,CAAA,GAAI,CAAA,GAAI,CAAA;AACpC,IAAA,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,IAAI,CAAC,CAAA;AAC7B,IAAA,IAAA,GAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACxB;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,aAAA,CAAc,IAAA,EAAc,MAAA,EAAgB,KAAA,EAAyC;AAC5F,EAAA,IAAI,IAAA,GAAO,IAAA;AACX,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,IAAI,MAAA,GAAS,EAAA;AAEb,EAAA,IAAI,MAAA,CAAO,IAAA,EAAK,KAAM,EAAA,EAAI;AACxB,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA;AACrC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,IAAU,OAAO,CAAC,CAAA;AAClB,MAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,CAAC,EAAE,MAAM,CAAA;AAAA,IACpC;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAiB,IAAA,CAAK,IAAI,CAAA;AAC1C,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,IAAI,IAAA,GAAO,EAAA;AACX,IAAA,IAAI,OAAO,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,EAAE,MAAM,CAAA;AACvC,IAAA,KAAA,MAAW,SAAS,cAAA,CAAe,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAE,SAAQ,EAAG;AAExD,MAAA,IAAI,UAAA,CAAW,IAAA,EAAM,KAAK,CAAA,GAAI,MAAM,CAAA,EAAG;AACrC,QAAA,IAAA,GAAO,KAAA,GAAQ,IAAA;AACf,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,WAAW,KAAA,EAAO,KAAK,CAAA,GAAI,CAAA,KAAM,GAAG,MAAA,IAAU,KAAA;AAAA,kBACtC,KAAA,GAAQ,IAAA;AAAA,IACtB;AACA,IAAA,IAAA,GAAO,IAAA,GAAO,IAAA;AACd,IAAA,IAAA,GAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,IAAA,CAAK,IAAI,CAAA;AAC5C,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,KAAA,GAAQ,SAAS,CAAC,CAAA;AACxB,IAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,CAAM,CAAA,EAAG,KAAK,MAAA,GAAS,QAAA,CAAS,CAAC,CAAA,CAAE,MAAM,CAAA;AAC5D,IAAA,MAAM,eAAe,UAAA,CAAW,MAAA,GAAS,MAAA,EAAQ,KAAK,IAAI,CAAA,KAAM,CAAA;AAChE,IAAA,IAAI,WAAW,KAAA,EAAO,KAAK,CAAA,GAAI,CAAA,KAAM,KAAK,YAAA,EAAc;AACtD,MAAA,IAAA,GAAO,KAAA;AACP,MAAA,MAAA,GAAS,SAAS,CAAC,CAAA;AAAA,IACrB;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,MAAA,EAAQ,IAAA,EAAM,MAAM,CAAA;AAC9B;AAEA,SAAS,cAAc,IAAA,EAAsB;AAC3C,EAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,UAAU,GAAG,OAAO,IAAA;AACvC,EAAA,OAAO,KAAK,OAAA,CAAQ,SAAA,EAAW,CAAC,KAAA,EAAO,IAAA,EAAc,MAAc,MAAA,KAAmB;AACpF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,MAAM,CAAA;AACnC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,MAAM,MAAM,CAAA;AAC9C,IAAA,MAAM,CAAC,QAAQ,IAAA,EAAM,MAAM,IAAI,aAAA,CAAc,IAAA,EAAM,QAAQ,KAAK,CAAA;AAChE,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAA,IAAU,IAAA,KAAS,MAAM,OAAO,KAAA;AAChD,IAAA,OAAO,GAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,EAAA,EAAK,IAAI,IAAI,MAAM,CAAA,CAAA;AAAA,EAC7C,CAAC,CAAA;AACH;AAEA,SAAS,uBAAuB,IAAA,EAAsB;AACpD,EAAA,OAAO,IAAA,CAAK,SAAS,IAAI,CAAA,GAAI,KAAK,OAAA,CAAQ,cAAA,EAAgB,QAAQ,CAAA,GAAI,IAAA;AACxE;AAEO,SAAS,wBAAwB,QAAA,EAA0B;AAChE,EAAA,IAAI,CAAC,QAAA,CAAS,QAAA,CAAS,UAAU,CAAA,IAAK,CAAC,QAAA,CAAS,QAAA,CAAS,IAAI,CAAA,EAAG,OAAO,QAAA;AACvE,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,OAAO,SACJ,KAAA,CAAM,IAAI,CAAA,CACV,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,IAAI,CAAA,EAAG;AAC9B,MAAA,OAAA,GAAU,CAAC,OAAA;AACX,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,OAAA,GAAU,IAAA,GAAO,sBAAA,CAAuB,aAAA,CAAc,IAAI,CAAC,CAAA;AAAA,EACpE,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AACd;AAGA,IAAM,kBAAA,GAAqB,qEAAA;AAOpB,SAAS,iBAAiB,QAAA,EAA0B;AACzD,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,kBAAA,EAAoB,EAAE,CAAA;AAChD;AAGA,SAAS,UAAU,IAAA,EAAsB;AACvC,EAAA,OAAA,CAAQ,IAAA,CAAK,QAAQ,UAAA,EAAY,EAAE,EAAE,KAAA,CAAM,OAAO,CAAA,IAAK,EAAC,EAAG,MAAA;AAC7D;AAUO,SAAS,kBAAkB,QAAA,EAA0B;AAC1D,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,WAAA,CAAY,IAAI,CAAA,GAAI,CAAA;AACzC,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA;AAClC,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,eAAA,CAAgB,IAAA,CAAK,CAAC,CAAC,CAAA,CAAE,MAAA;AACvE,EAAA,IAAI,IAAA,GAAO,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,SAAS,CAAA,KAAM,CAAA,IAAK,gBAAgB,IAAA,CAAK,IAAI,GAAG,OAAO,QAAA;AAE3D,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAgB,IAAI,CAAA;AACxC,EAAA,IAAI,UAAU,IAAI,CAAA,GAAI,CAAA,KAAM,CAAA,SAAU,IAAA,GAAO,IAAA;AAE7C,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,aAAA,EAAe,IAAI,CAAA;AACvC,EAAA,IAAI,UAAU,IAAI,CAAA,GAAI,CAAA,KAAM,CAAA,SAAU,IAAA,GAAO,IAAA;AAC7C,EAAA,IAAI,UAAA,CAAW,KAAK,IAAI,CAAA,SAAU,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,aAAA,EAAe,GAAG,CAAA;AACxE,EAAA,OAAO,OAAO,IAAA,GAAO,IAAA;AACvB;ACpIA,SAAS,SAAA,CAAU,EAAE,QAAA,EAAU,IAAA,EAAK,EAAuC;AACzE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIC,eAAS,KAAK,CAAA;AAE1C,EAAA,MAAM,aAAa,YAAY;AAC7B,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,CAAU,SAAA,CAAU,SAAA,CAAU,IAAI,CAAA;AACxC,MAAA,SAAA,CAAU,IAAI,CAAA;AACd,MAAA,UAAA,CAAW,MAAM,SAAA,CAAU,KAAK,CAAA,EAAG,GAAI,CAAA;AAAA,IACzC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA;AAEA,EAAA,uBACEC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,2FAAA;AAAA,MACV,aAAA,EAAY,qBAAA;AAAA,MAEZ,QAAA,EAAA;AAAA,wBAAAA,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,0EAAA,EACb,QAAA,EAAA;AAAA,0BAAAH,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yCAAA,EAA2C,sBAAY,MAAA,EAAO,CAAA;AAAA,0BAC9EG,eAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,OAAA,EAAS,UAAA;AAAA,cACT,SAAA,EAAU,+FAAA;AAAA,cACV,KAAA,EAAO,SAAS,SAAA,GAAY,WAAA;AAAA,cAE3B,QAAA,EAAA;AAAA,gBAAA,MAAA,mBAASH,cAAAA,CAACI,iBAAA,EAAA,EAAM,IAAA,EAAM,EAAA,EAAI,oBAAKJ,cAAAA,CAACK,gBAAA,EAAA,EAAK,IAAA,EAAM,EAAA,EAAI,CAAA;AAAA,gCAChDL,cAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,MAAA,GAAS,WAAW,MAAA,EAAO;AAAA;AAAA;AAAA;AACpC,SAAA,EACF,CAAA;AAAA,wBACAA,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6CAAA,EACb,0BAAAA,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAWM,oBAAA,CAAG,aAAa,QAAA,IAAY,CAAA,SAAA,EAAY,QAAQ,CAAA,CAAE,CAAA,EAAI,gBAAK,CAAA,EAC9E;AAAA;AAAA;AAAA,GACF;AAEJ;AASA,SAAS,aAAa,EAAE,IAAA,EAAM,QAAA,EAAU,GAAG,OAAM,EAAwC;AACvF,EAAA,IAAI,IAAA,EAAM,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC9B,IAAA,uBACEN,cAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,2IAAA;AAAA,QACV,WAAA,EAAW,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AAAA,QAEtB;AAAA;AAAA,KACH;AAAA,EAEJ;AACA,EAAA,MAAM,UAAA,GAAa,CAAC,IAAA,IAAQ,IAAA,CAAK,WAAW,GAAG,CAAA,IAAK,IAAA,CAAK,UAAA,CAAW,OAAO,CAAA;AAC3E,EAAA,uBACEA,cAAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,2CAAA;AAAA,MACV,IAAA;AAAA,MACC,GAAI,aAAa,EAAC,GAAI,EAAE,MAAA,EAAQ,QAAA,EAAU,KAAK,qBAAA,EAAsB;AAAA,MACrE,GAAG,KAAA;AAAA,MAEH;AAAA;AAAA,GACH;AAEJ;AASA,IAAM,iBAAA,GAAyC;AAAA,EAC7C,GAAG,sBAAA;AAAA,EACH,CAAA,EAAG,YAAA;AAAA,EACH,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,QAAA,EAAU,GAAG,OACxB,QAAA,EACH,CAAA;AAAA,EAEF,IAAA,EAAM,SAAS,YAAA,CAAa;AAAA,IAC1B,SAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAG;AAAA,GACL,EAA2C;AACzC,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,IAAA,CAAK,SAAA,IAAa,EAAE,CAAA;AACnD,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,uBACEA,cAAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,0DAAA;AAAA,UACV,aAAA,EAAY,sBAAA;AAAA,UACX,GAAG,KAAA;AAAA,UAEH;AAAA;AAAA,OACH;AAAA,IAEJ;AACA,IAAA,uBAAOA,cAAAA,CAAC,SAAA,EAAA,EAAU,QAAA,EAAU,MAAM,CAAC,CAAA,EAAG,IAAA,EAAM,MAAA,CAAO,QAAQ,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,EAAG,CAAA;AAAA,EACnF,CAAA;AAAA;AAAA;AAAA,EAGA,GAAA,EAAK,CAAC,EAAE,QAAA,uBAAsDA,cAAAA,CAAAO,uBAAG,QAAA,EAAS,CAAA;AAAA,EAC1E,UAAA,EAAY,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAChCP,cAAAA,CAAC,YAAA,EAAA,EAAW,SAAA,EAAU,4DAAA,EAA8D,GAAG,OACpF,QAAA,EACH,CAAA;AAAA,EAEF,KAAA,EAAO,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAC3BA,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wDACb,QAAA,kBAAAA,cAAAA,CAAC,WAAM,aAAA,EAAY,gBAAA,EAAiB,WAAU,gCAAA,EAAkC,GAAG,KAAA,EAChF,QAAA,EACH,CAAA,EACF,CAAA;AAAA,EAEF,KAAA,EAAO,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAC3BA,cAAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,eAAA,EAAiB,GAAG,OAClC,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0DAAA,EAA4D,GAAG,OAC1E,QAAA,EACH,CAAA;AAAA,EAEF,EAAA,EAAI,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACxBA,cAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,4CAAA,EAA8C,GAAG,OAC5D,QAAA,EACH,CAAA;AAAA;AAAA,EAGF,GAAA,EAAK,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACzBA,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oCAAA,EAAsC,GAAG,OACrD,QAAA,EACH,CAAA;AAAA,EAEF,GAAA,EAAK,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBACzBA,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iCAAA,EAAmC,GAAG,OAClD,QAAA,EACH,CAAA;AAAA,EAEF,IAAA,EAAM,CAAC,EAAE,QAAA,EAAU,GAAG,KAAA,EAAM,qBAC1BA,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2CAAA,EAA6C,GAAG,OAC7D,QAAA,EACH;AAEJ,CAAA;AAMA,IAAM,aAAA,GAAgB,CAACQ,0BAAS,CAAA;AAChC,IAAM,aAAA,GAAgB,CAACC,0BAAS,CAAA;AAOhC,IAAM,aAAA,GAAgBC,sBAAA,CAAM,IAAA,CAAK,SAAS,aAAA,CAAc;AAAA,EACtD,OAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,uBACEV,cAAAA,CAACW,yBAAA,EAAA,EAAS,aAAA,EAA8B,aAAA,EAA8B,YACnE,QAAA,EAAA,OAAA,EACH,CAAA;AAEJ,CAAC,CAAA;AAGD,IAAM,qBAAA,GAAN,cAAoCD,sBAAA,CAAM,SAAA,CAGxC;AAAA,EACA,KAAA,GAAQ,EAAE,QAAA,EAAU,KAAA,EAAM;AAAA,EAC1B,OAAO,wBAAA,GAA2B;AAChC,IAAA,OAAO,EAAE,UAAU,IAAA,EAAK;AAAA,EAC1B;AAAA,EACA,MAAA,GAAS;AACP,IAAA,OAAO,KAAK,KAAA,CAAM,QAAA,GAAW,KAAK,KAAA,CAAM,QAAA,GAAW,KAAK,KAAA,CAAM,QAAA;AAAA,EAChE;AACF,CAAA;AAuBA,SAAS,yBAAA,CAA0B;AAAA,EACjC,QAAA;AAAA,EACA,UAAA,EAAY,gBAAA;AAAA,EACZ,cAAA;AAAA,EACA,WAAA,GAAc,KAAA;AAAA,EACd,SAAA;AAAA,EACA,MAAA,GAAS;AACX,CAAA,EAA0B;AACxB,EAAA,MAAM,UAAA,GAAaE,cAAQ,MAAM;AAC/B,IAAA,MAAM,OAAO,gBAAA,GACT,EAAE,GAAG,iBAAA,EAAmB,GAAG,kBAAiB,GAC5C,iBAAA;AACJ,IAAA,IAAI,CAAC,gBAAgB,OAAO,IAAA;AAC5B,IAAA,MAAM,IAAA,GAAO,KAAK,CAAA,IAAK,YAAA;AACvB,IAAA,OAAO;AAAA,MACL,GAAG,IAAA;AAAA,MACH,CAAA,EAAG,CAAC,KAAA,KACF,KAAA,CAAM,IAAA,EAAM,WAAW,QAAQ,CAAA,GAC3B,cAAA,CAAe,EAAE,GAAA,EAAK,KAAA,CAAM,KAAK,KAAA,CAAM,CAAC,CAAA,EAAG,QAAA,EAAU,KAAA,CAAM,QAAA,EAAU,CAAA,GACrEF,sBAAA,CAAM,aAAA,CAAc,IAAA,EAA2B,KAAK;AAAA,KAC5D;AAAA,EACF,CAAA,EAAG,CAAC,gBAAA,EAAkB,cAAc,CAAC,CAAA;AAErC,EAAA,MAAM,MAAA,GAASE,aAAA;AAAA,IACb,MACE,mBAAA;AAAA,MACE,uBAAA;AAAA,QACE,WAAA,GAAc,iBAAA,CAAkB,gBAAA,CAAiB,QAAQ,CAAC,CAAA,GAAI;AAAA;AAChE,KACF;AAAA,IACF,CAAC,UAAU,WAAW;AAAA,GACxB;AAEA,EAAA,uBACEZ,cAAAA;AAAA,IAAC,qBAAA;AAAA,IAAA;AAAA,MACC,QAAA,kBAAUA,cAAAA,CAAC,KAAA,EAAA,EAAI,WAAWM,oBAAA,CAAG,iCAAA,EAAmC,SAAS,CAAA,EAAI,QAAA,EAAS,CAAA;AAAA,MAEtF,0BAAAN,cAAAA,CAAC,wBAAA,CAAyB,UAAzB,EAAkC,KAAA,EAAO,aACxC,QAAA,kBAAAA,cAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAWM,oBAAA,CAAG,wDAAA,EAA0D,SAAS,CAAA;AAAA,UACjF,aAAA,EAAa,MAAA;AAAA,UAEZ,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,EAAO,KAAA,qBAClBN,cAAAA,CAAC,aAAA,EAAA,EAA0B,OAAA,EAAS,KAAA,EAAO,UAAA,EAAA,EAAvB,KAA+C,CACpE;AAAA;AAAA,OACH,EACF;AAAA;AAAA,GACF;AAEJ;AAOO,IAAM,gBAAA,GAAmBU,sBAAA,CAAM,IAAA,CAAK,yBAAyB","file":"chunk-FUPWPQGK.cjs","sourcesContent":["import React from 'react'\nimport type { Components } from 'react-markdown'\n\n/**\n * Brand-neutral presentational component overrides for react-markdown, shared by\n * every markdown surface in the workspace (the monolith's `MarkdownRenderer` and\n * the AI kit's `AiMarkdown`). One house style for headings, lists, tables and the\n * inline text elements — token-based, so it themes per app.\n *\n * Deliberately excluded (kept per-consumer): `a` (external-link confirm vs\n * plain), `code`/`pre` (rich CodeBlock + Mermaid vs inline), `span` (doc-entity\n * pills), and `del`/`ins`/`mark` (general emphasis vs redline tracked-changes) —\n * these differ by intent or carry heavy/coupled behaviour, so each renderer owns\n * them and spreads this base underneath.\n */\nexport const markdownBaseComponents: Partial<Components> = {\n h1: ({ children, ...props }: React.ComponentPropsWithoutRef<'h1'>) => (\n <h1 className=\"text-lg font-semibold\" data-testid=\"markdown-heading-1\" {...props}>\n {children}\n </h1>\n ),\n h2: ({ children, ...props }: React.ComponentPropsWithoutRef<'h2'>) => (\n <h2 className=\"font-semibold text-base\" data-testid=\"markdown-heading-2\" {...props}>\n {children}\n </h2>\n ),\n h3: ({ children, ...props }: React.ComponentPropsWithoutRef<'h3'>) => (\n <h3 className=\"font-semibold text-base\" data-testid=\"markdown-heading-3\" {...props}>\n {children}\n </h3>\n ),\n h4: ({ children, ...props }: React.ComponentPropsWithoutRef<'h4'>) => (\n <h4 className=\"font-semibold text-base\" {...props}>\n {children}\n </h4>\n ),\n h5: ({ children, ...props }: React.ComponentPropsWithoutRef<'h5'>) => (\n <h5 className=\"font-medium\" {...props}>\n {children}\n </h5>\n ),\n strong: ({ children, ...props }: React.ComponentPropsWithoutRef<'strong'>) => (\n <strong className=\"font-semibold\" {...props}>\n {children}\n </strong>\n ),\n blockquote: ({ children, ...props }: React.ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote className=\"border-l-2 border-primary pl-4\" {...props}>\n {children}\n </blockquote>\n ),\n ol: ({ children, ...props }: React.ComponentPropsWithoutRef<'ol'>) => (\n <ol className=\"list-decimal space-y-2 pl-6\" data-testid=\"markdown-ordered-list\" {...props}>\n {children}\n </ol>\n ),\n ul: ({ children, ...props }: React.ComponentPropsWithoutRef<'ul'>) => (\n <ul className=\"list-none space-y-2 pl-6\" data-testid=\"markdown-unordered-list\" {...props}>\n {children}\n </ul>\n ),\n li: ({ children, ...props }: React.ComponentPropsWithoutRef<'li'>) => (\n <li className=\"my-1.5\" {...props}>\n {children}\n </li>\n ),\n table: ({ children, ...props }: React.ComponentPropsWithoutRef<'table'>) => (\n <table data-testid=\"markdown-table\" {...props}>\n {children}\n </table>\n ),\n th: ({ children, ...props }: React.ComponentPropsWithoutRef<'th'>) => (\n <th {...props}>{children}</th>\n ),\n td: ({ children, ...props }: React.ComponentPropsWithoutRef<'td'>) => (\n <td {...props}>{children}</td>\n ),\n tr: ({ children, ...props }: React.ComponentPropsWithoutRef<'tr'>) => (\n <tr {...props}>{children}</tr>\n ),\n p: ({ children, ...props }: React.ComponentPropsWithoutRef<'p'>) => (\n <p className=\"whitespace-pre-wrap\" {...props}>\n {children}\n </p>\n ),\n hr: (props: React.ComponentPropsWithoutRef<'hr'>) => (\n <hr className=\"border-foreground/20\" {...props} />\n ),\n sup: ({ children, ...props }: React.ComponentPropsWithoutRef<'sup'>) => (\n <sup className=\"text-xs\" {...props}>\n {children}\n </sup>\n ),\n sub: ({ children, ...props }: React.ComponentPropsWithoutRef<'sub'>) => (\n <sub className=\"text-xs\" {...props}>\n {children}\n </sub>\n ),\n div: ({ children, className, ...props }: React.ComponentPropsWithoutRef<'div'>) => (\n <div className={className} {...props}>\n {children}\n </div>\n ),\n br: (props: React.ComponentPropsWithoutRef<'br'>) => <br {...props} />,\n kbd: ({ children, ...props }: React.ComponentPropsWithoutRef<'kbd'>) => (\n <kbd\n className=\"px-1.5 py-0.5 text-xs font-mono bg-muted border border-border rounded\"\n {...props}\n >\n {children}\n </kbd>\n ),\n abbr: ({ children, title, ...props }: React.ComponentPropsWithoutRef<'abbr'>) => (\n <abbr title={title} className=\"underline decoration-dotted cursor-help\" {...props}>\n {children}\n </abbr>\n ),\n cite: ({ children, ...props }: React.ComponentPropsWithoutRef<'cite'>) => (\n <cite className=\"italic\" {...props}>\n {children}\n </cite>\n ),\n}\n","import { createContext } from 'react'\n\n/**\n * Signals to `MarkdownRenderer`'s component overrides that the surrounding\n * message is still streaming tokens. Heavy renderers can defer their work while\n * this is true to avoid burning CPU on partially complete fences and to keep the\n * UI responsive during long generations.\n *\n * Default `false` means non-streaming usages (parsed documents, static answers,\n * DM bubbles) get the full rendering with no behaviour change.\n */\nexport const MarkdownStreamingContext = createContext(false)\n","/**\n * Splits a markdown string into top-level blocks at `\\n\\n` boundaries.\n *\n * Streaming AI responses arrive token-by-token; passing the full string to\n * react-markdown re-parses the entire AST on every flush. By splitting into\n * blocks and memoizing each, only the trailing (still-growing) block re-parses\n * — completed blocks stay frozen in the DOM.\n *\n * The split avoids three correctness pitfalls:\n * - never splits inside an open ``` code fence (would corrupt the language)\n * - never splits between two adjacent list items (would render as two lists)\n * - never splits between two blockquote lines (would render as two quotes)\n */\nconst LIST_ITEM_RE = /^\\s*([-*+]|\\d+[.)])\\s/\nconst BLOCKQUOTE_RE = /^\\s*>/\n\nexport function splitMarkdownBlocks(content: string): string[] {\n if (!content) return []\n const blocks: string[] = []\n let start = 0\n let inFence = false\n let i = 0\n while (i < content.length) {\n if (content.startsWith('```', i)) {\n inFence = !inFence\n i += 3\n continue\n }\n if (!inFence && content[i] === '\\n' && content[i + 1] === '\\n') {\n const before = content.slice(start, i)\n const lastLine = before.slice(before.lastIndexOf('\\n') + 1)\n const afterStart = i + 2\n const nextNewline = content.indexOf('\\n', afterStart)\n const nextLine = content.slice(afterStart, nextNewline === -1 ? undefined : nextNewline)\n const bothListItems = LIST_ITEM_RE.test(lastLine) && LIST_ITEM_RE.test(nextLine)\n const bothBlockquotes = BLOCKQUOTE_RE.test(lastLine) && BLOCKQUOTE_RE.test(nextLine)\n if (bothListItems || bothBlockquotes) {\n i += 2\n continue\n }\n blocks.push(content.slice(start, afterStart))\n start = afterStart\n i = afterStart\n continue\n }\n i++\n }\n if (start < content.length) blocks.push(content.slice(start))\n return blocks\n}\n","/**\n * Citation markup normaliser.\n *\n * The backend marks a cited statement as a markdown link, `[statement](#cite-N)`, and the\n * statement can include the markdown that surrounds it: a list marker, a heading marker or the\n * opener of a bold/italic span whose closer sits after the link. Inside link text those tokens\n * are not parsed as block or inline syntax, so they show literally and break lists and bold:\n *\n * [- **Claimed quantum (by Claimant)](#cite-1):** **USD 47 million**\n *\n * `normalizeCitationMarkup` hoists the leading tokens out of the link text (and a trailing\n * emphasis closer after it), so the link only wraps the words:\n *\n * - **[Claimed quantum (by Claimant)](#cite-1):** **USD 47 million**\n *\n * It is conservative: emphasis that opens and closes inside the link text is valid markdown and\n * is left alone, an opener is only hoisted when its closer follows on the same line, and fenced\n * code blocks are never touched. The result is idempotent.\n *\n * It also tidies the residue the model leaves when it cites in prose as well: a literal\n * `(*Source: Award.pdf, p. 12*)` shows its asterisks, because `(*` does not open emphasis. It\n * becomes the italic note `*(Source: Award.pdf, p. 12)*`.\n */\n\nconst SOURCE_RESIDUE = /\\(\\*+\\s*(Sources?\\s*:[^\\n]*?)\\s*\\*+\\)/g\n\nconst CITE_LINK = /\\[([^\\]\\n]+)\\]\\((#cite-[\\w-]+)\\)/g\nconst BLOCK_MARKER = /^(?:[-*+]|\\d{1,9}[.)]|#{1,6})[ \\t]+/\nconst LEADING_EMPHASIS = /^(?:\\*\\*|__|\\*|_)+/\nconst TRAILING_EMPHASIS = /(\\*\\*|__|\\*|_)(:?)$/\n\n/** Occurrences of `token` in `text`; a single `*` is counted outside any `**` pair. */\nfunction countToken(text: string, token: string): number {\n const double = token + token\n if (token.length === 2) return text.split(token).length - 1\n const withoutDouble = text.split(double).join('')\n return withoutDouble.split(token).length - 1\n}\n\n/** Split a run of emphasis characters (`***`, `**`, `*`...) into its parser-level tokens. */\nfunction emphasisTokens(run: string): string[] {\n const char = run[0]\n const tokens: string[] = []\n let rest = run\n while (rest.length > 0) {\n const size = rest.length >= 2 ? 2 : 1\n tokens.push(char.repeat(size))\n rest = rest.slice(size)\n }\n return tokens\n}\n\nfunction hoistFromLink(text: string, before: string, after: string): [string, string, string] {\n let body = text\n let prefix = ''\n let suffix = ''\n\n if (before.trim() === '') {\n const marker = BLOCK_MARKER.exec(body)\n if (marker) {\n prefix += marker[0]\n body = body.slice(marker[0].length)\n }\n }\n\n const leading = LEADING_EMPHASIS.exec(body)\n if (leading) {\n let kept = ''\n let rest = body.slice(leading[0].length)\n for (const token of emphasisTokens(leading[0]).reverse()) {\n // Balanced inside the link text: valid as written.\n if (countToken(rest, token) % 2 === 1) {\n kept = token + kept\n continue\n }\n // Unmatched here: hoist only if the line closes it after the link.\n if (countToken(after, token) % 2 === 1) prefix += token\n else kept = token + kept\n }\n body = kept + rest\n rest = ''\n }\n\n const trailing = TRAILING_EMPHASIS.exec(body)\n if (trailing) {\n const token = trailing[1]\n const inner = body.slice(0, body.length - trailing[0].length)\n const openedBefore = countToken(before + prefix, token) % 2 === 1\n if (countToken(inner, token) % 2 === 0 && openedBefore) {\n body = inner\n suffix = trailing[0]\n }\n }\n\n return [prefix, body, suffix]\n}\n\nfunction normalizeLine(line: string): string {\n if (!line.includes('](#cite-')) return line\n return line.replace(CITE_LINK, (match, text: string, href: string, offset: number) => {\n const before = line.slice(0, offset)\n const after = line.slice(offset + match.length)\n const [prefix, body, suffix] = hoistFromLink(text, before, after)\n if (!prefix && !suffix && body === text) return match\n return `${prefix}[${body}](${href})${suffix}`\n })\n}\n\nfunction normalizeSourceResidue(line: string): string {\n return line.includes('(*') ? line.replace(SOURCE_RESIDUE, '*($1)*') : line\n}\n\nexport function normalizeCitationMarkup(markdown: string): string {\n if (!markdown.includes('](#cite-') && !markdown.includes('(*')) return markdown\n let inFence = false\n return markdown\n .split('\\n')\n .map((line) => {\n if (/^\\s*(```|~~~)/.test(line)) {\n inFence = !inFence\n return line\n }\n return inFence ? line : normalizeSourceResidue(normalizeLine(line))\n })\n .join('\\n')\n}\n\n/** A trailing, still-open `[words](#cite-N` marker (or an unclosed `[words`) on the last line. */\nconst OPEN_CITATION_TAIL = /\\[[^\\]\\n]*(?:\\](?:\\((?:#(?:c(?:i(?:t(?:e(?:-[\\w-]*)?)?)?)?)?)?)?)?$/\n\n/**\n * Drops an unfinished citation marker from the end of text that is still streaming (or was\n * stopped mid-marker), so `[Change of control](#cite-` never shows as raw markup: the words appear\n * once the marker is complete. Complete markers and everything else are left alone.\n */\nexport function trimOpenCitation(markdown: string): string {\n return markdown.replace(OPEN_CITATION_TAIL, '')\n}\n\n/** `**` pairs outside inline code in a line. */\nfunction boldMarks(line: string): number {\n return (line.replace(/`[^`]*`/g, '').match(/\\*\\*/g) ?? []).length\n}\n\n/**\n * Makes the tail of text that is still streaming (or was stopped) render cleanly: a `**` opened\n * in the last line and not yet closed (`| Valuation | **[USD 6.2 million](#cite-2)`) would show as\n * literal asterisks until its closer arrives, because an unclosed emphasis is not emphasis. The\n * open bold is closed at the end of the line, or removed when it has no text yet (`| **`, or a\n * half-typed closer `**USD 6*`). Text with balanced emphasis, and every line but the last, is\n * left alone. Apply after `trimOpenCitation`.\n */\nexport function closeOpenEmphasis(markdown: string): string {\n const cut = markdown.lastIndexOf('\\n') + 1\n const head = markdown.slice(0, cut)\n const fences = head.split('\\n').filter((l) => /^\\s*(```|~~~)/.test(l)).length\n let line = markdown.slice(cut)\n if (fences % 2 === 1 || /^\\s*(```|~~~)/.test(line)) return markdown\n // A half-typed opener: the first `*` of `**` after a space or a cell border.\n line = line.replace(/(^|[\\s|])\\*$/, '$1')\n if (boldMarks(line) % 2 === 0) return head + line\n // A half-typed closer: `**USD 6*` -> the second asterisk has not arrived.\n line = line.replace(/([^*\\s])\\*$/, '$1')\n if (boldMarks(line) % 2 === 0) return head + line\n if (/\\*\\*\\s*$/.test(line)) return head + line.replace(/\\s*\\*\\*\\s*$/, ' ')\n return head + line + '**'\n}\n","import React, { useMemo, useState } from 'react'\nimport Markdown, { type Components } from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport rehypeRaw from 'rehype-raw'\nimport { Copy, Check } from 'lucide-react'\nimport { cn } from '../lib/utils'\nimport { markdownBaseComponents } from './markdown-base-components'\nimport { MarkdownStreamingContext } from './markdown-streaming-context'\nimport { splitMarkdownBlocks } from './split-markdown-blocks'\nimport { closeOpenEmphasis, normalizeCitationMarkup, trimOpenCitation } from './normalize-citations'\n\n/**\n * MarkdownRenderer — the single, full-featured markdown surface for the kit.\n *\n * Renders AI answers, chat/DM messages and parsed-document panes with one house\n * style: headings, paragraphs, bold/italic, ordered/unordered lists, GFM tables,\n * fenced code blocks (monospace + copy button), inline code, blockquotes, safe\n * links (`rel=\"noopener\"`, new tab) and horizontal rules.\n *\n * Styling is 100% semantic Tailwind tokens (`text-foreground`,\n * `text-muted-foreground`, `border-border`, `bg-muted`, `text-primary`) so it\n * themes per firm — no hardcoded brand colours. It sizes to its container, so it\n * looks right in a compact chat bubble and in a full-width document pane alike.\n *\n * Streaming: the content is split into block-level chunks (see\n * `splitMarkdownBlocks`) and each chunk is memoised, so streaming token updates\n * only re-parse the trailing block instead of the whole message. Pass\n * `isStreaming` to let heavy custom components defer via `MarkdownStreamingContext`.\n *\n * Extending: pass `components` to override any element (the kit's `AiMarkdown`\n * and `CitationRenderer` layer their accent links / citation popovers on top).\n */\n\n/** Fenced code block with a language label and copy-to-clipboard button. */\nfunction CodeBlock({ language, code }: { language: string; code: string }) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(code)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Clipboard unavailable (insecure context / permissions) — no-op.\n }\n }\n\n return (\n <div\n className=\"code-block relative my-3 overflow-hidden rounded-md border border-current/20 bg-current/5\"\n data-testid=\"markdown-code-block\"\n >\n <div className=\"flex items-center justify-between border-b border-current/20 px-3 py-1.5\">\n <span className=\"font-mono text-xs text-muted-foreground\">{language || 'code'}</span>\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground\"\n title={copied ? 'Copied!' : 'Copy code'}\n >\n {copied ? <Check size={12} /> : <Copy size={12} />}\n <span>{copied ? 'Copied' : 'Copy'}</span>\n </button>\n </div>\n <pre className=\"overflow-x-auto p-3 text-sm leading-relaxed\">\n <code className={cn('font-mono', language && `language-${language}`)}>{code}</code>\n </pre>\n </div>\n )\n}\n\n/**\n * Links. Internal hash/anchor links stay in-page; everything else opens safely in a new tab\n * (`rel=\"noopener noreferrer\"` prevents reverse-tabnabbing). A backend citation marker\n * (`#cite-N`) has no popover here: the cited words stay in the surface's own colour with a quiet\n * superscript number after them (no underline, so a cited sentence does not read as a link).\n * Pass `renderCitation` to `MarkdownRenderer` to swap in a real source popover.\n */\nfunction MarkdownLink({ href, children, ...props }: React.ComponentPropsWithoutRef<'a'>) {\n if (href?.startsWith('#cite-')) {\n return (\n <span\n className=\"cited-text after:ml-px after:align-super after:text-[0.7em] after:font-medium after:text-muted-foreground after:content-[attr(data-cite)]\"\n data-cite={href.slice(6)}\n >\n {children}\n </span>\n )\n }\n const isInternal = !href || href.startsWith('#') || href.startsWith('cite:')\n return (\n <a\n className=\"text-primary underline underline-offset-2\"\n href={href}\n {...(isInternal ? {} : { target: '_blank', rel: 'noopener noreferrer' })}\n {...props}\n >\n {children}\n </a>\n )\n}\n\n/**\n * Default component overrides. Spreads the shared brand-neutral base\n * (`markdownBaseComponents`: headings, lists, paragraphs, emphasis, hr…) and adds\n * the elements that carry behaviour or need self-contained styling: safe links,\n * code (inline + fenced), bordered tables and blockquotes. Module-scoped so the\n * reference is stable across renders and react-markdown can skip re-parsing.\n */\nconst defaultComponents: Partial<Components> = {\n ...markdownBaseComponents,\n a: MarkdownLink,\n em: ({ children, ...props }: React.ComponentPropsWithoutRef<'em'>) => (\n <em className=\"italic\" {...props}>\n {children}\n </em>\n ),\n code: function MarkdownCode({\n className,\n children,\n ...props\n }: React.ComponentPropsWithoutRef<'code'>) {\n const match = /language-(\\w+)/.exec(className || '')\n if (!match) {\n return (\n <code\n className=\"rounded bg-current/10 px-1 py-0.5 font-mono text-[0.9em]\"\n data-testid=\"markdown-inline-code\"\n {...props}\n >\n {children}\n </code>\n )\n }\n return <CodeBlock language={match[1]} code={String(children).replace(/\\n$/, '')} />\n },\n // The CodeBlock renders its own <pre>; unwrap react-markdown's wrapper so we\n // don't nest <pre><pre>.\n pre: ({ children }: React.ComponentPropsWithoutRef<'pre'>) => <>{children}</>,\n blockquote: ({ children, ...props }: React.ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote className=\"border-l-2 border-border pl-4 italic text-muted-foreground\" {...props}>\n {children}\n </blockquote>\n ),\n table: ({ children, ...props }: React.ComponentPropsWithoutRef<'table'>) => (\n <div className=\"my-3 overflow-x-auto rounded-lg border border-border\">\n <table data-testid=\"markdown-table\" className=\"w-full border-collapse text-sm\" {...props}>\n {children}\n </table>\n </div>\n ),\n thead: ({ children, ...props }: React.ComponentPropsWithoutRef<'thead'>) => (\n <thead className=\"bg-current/10\" {...props}>\n {children}\n </thead>\n ),\n th: ({ children, ...props }: React.ComponentPropsWithoutRef<'th'>) => (\n <th className=\"border-b border-border px-3 py-2 text-left font-semibold\" {...props}>\n {children}\n </th>\n ),\n td: ({ children, ...props }: React.ComponentPropsWithoutRef<'td'>) => (\n <td className=\"border-b border-border px-3 py-2 align-top\" {...props}>\n {children}\n </td>\n ),\n // General emphasis marks (GFM `~~strikethrough~~` → <del>, raw <ins>/<mark>).\n del: ({ children, ...props }: React.ComponentPropsWithoutRef<'del'>) => (\n <del className=\"text-muted-foreground line-through\" {...props}>\n {children}\n </del>\n ),\n ins: ({ children, ...props }: React.ComponentPropsWithoutRef<'ins'>) => (\n <ins className=\"underline decoration-primary/60\" {...props}>\n {children}\n </ins>\n ),\n mark: ({ children, ...props }: React.ComponentPropsWithoutRef<'mark'>) => (\n <mark className=\"rounded bg-primary/15 px-0.5 text-inherit\" {...props}>\n {children}\n </mark>\n ),\n}\n\n// Stable module-scope plugin arrays so react-markdown compares them by reference\n// and skips re-running the remark/rehype pipeline when nothing else changed.\n// `rehype-raw` enables inline HTML (e.g. redline <del>/<ins>); no math/mermaid\n// plugins are bundled to keep the kit light.\nconst remarkPlugins = [remarkGfm]\nconst rehypePlugins = [rehypeRaw]\n\n/**\n * One parsed markdown block, memoised on (content, components) so already-rendered\n * blocks don't re-parse when a later block streams new tokens. This is the core\n * of the streaming-rendering optimisation.\n */\nconst MemoizedBlock = React.memo(function MarkdownBlock({\n content,\n components,\n}: {\n content: string\n components: Partial<Components>\n}) {\n return (\n <Markdown remarkPlugins={remarkPlugins} rehypePlugins={rehypePlugins} components={components}>\n {content}\n </Markdown>\n )\n})\n\n/** Prevents a malformed-markdown render error from crashing the whole surface. */\nclass MarkdownErrorBoundary extends React.Component<\n { fallback: React.ReactNode; children: React.ReactNode },\n { hasError: boolean }\n> {\n state = { hasError: false }\n static getDerivedStateFromError() {\n return { hasError: true }\n }\n render() {\n return this.state.hasError ? this.props.fallback : this.props.children\n }\n}\n\nexport interface MarkdownRendererProps {\n /** Markdown content to render. */\n children: string\n /** Custom component overrides merged on top of the defaults. */\n components?: Partial<Components>\n /**\n * When true, signals heavy custom components (via `MarkdownStreamingContext`)\n * to defer their work while tokens are still arriving. Defaults to false.\n */\n isStreaming?: boolean\n /**\n * Renders a citation marker `[words](#cite-N)`: `children` are the cited words, `num` the N.\n * Keep it referentially stable (`useCallback`/`useMemo`), or every block re-parses.\n */\n renderCitation?: (citation: { num: string; children: React.ReactNode }) => React.ReactNode\n /** Extra classes on the wrapper (font-size, prose width, etc.). */\n className?: string\n /** Overrides the `data-testid` on the wrapper (default `markdown-renderer`). */\n testId?: string\n}\n\nfunction MarkdownRendererComponent({\n children,\n components: customComponents,\n renderCitation,\n isStreaming = false,\n className,\n testId = 'markdown-renderer',\n}: MarkdownRendererProps) {\n const components = useMemo(() => {\n const base = customComponents\n ? { ...defaultComponents, ...customComponents }\n : defaultComponents\n if (!renderCitation) return base\n const Link = base.a ?? MarkdownLink\n return {\n ...base,\n a: (props: React.ComponentPropsWithoutRef<'a'>) =>\n props.href?.startsWith('#cite-')\n ? renderCitation({ num: props.href.slice(6), children: props.children })\n : React.createElement(Link as React.ElementType, props),\n }\n }, [customComponents, renderCitation])\n\n const blocks = useMemo(\n () =>\n splitMarkdownBlocks(\n normalizeCitationMarkup(\n isStreaming ? closeOpenEmphasis(trimOpenCitation(children)) : children\n )\n ),\n [children, isStreaming]\n )\n\n return (\n <MarkdownErrorBoundary\n fallback={<div className={cn('whitespace-pre-wrap break-words', className)}>{children}</div>}\n >\n <MarkdownStreamingContext.Provider value={isStreaming}>\n <div\n className={cn('markdown-content space-y-3 break-words leading-relaxed', className)}\n data-testid={testId}\n >\n {blocks.map((block, index) => (\n <MemoizedBlock key={index} content={block} components={components} />\n ))}\n </div>\n </MarkdownStreamingContext.Provider>\n </MarkdownErrorBoundary>\n )\n}\n\n/**\n * Memoised so a stable message in a long thread doesn't re-parse when unrelated\n * tokens arrive elsewhere; a streaming message gets a fresh `children` each flush\n * and re-renders (only its trailing block re-parses, thanks to `MemoizedBlock`).\n */\nexport const MarkdownRenderer = React.memo(MarkdownRendererComponent)\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MarkdownRenderer } from './chunk-
|
|
1
|
+
import { MarkdownRenderer } from './chunk-77G7DSUW.js';
|
|
2
2
|
import { getCollisionPadding, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator } from './chunk-N5SVBDLC.js';
|
|
3
3
|
import { cn } from './chunk-SN5YV6FF.js';
|
|
4
4
|
import * as React from 'react';
|
|
@@ -3666,5 +3666,5 @@ function DocumentCard({
|
|
|
3666
3666
|
}
|
|
3667
3667
|
|
|
3668
3668
|
export { AgentBadge, AiMarkdown, ArbiBotHeadIcon, AudIcon, Avatar, AvatarFallback, AvatarImage, BASE_COLORS2 as BASE_COLORS, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DictateProvider, DocumentCard, DocumentEntity, ENTITY_MAPPINGS, EmlIcon, EntityIcon, EntityPill, FILE_TYPE_COLORS, HoverCard, HoverCardContent, HoverCardTrigger, IconToggle, ImgIcon, InlineMicButton, Input, Label, MarkMenu, MicRecordingOverlay, MicWaveformIndicator, NEUTRAL_GRAY2 as NEUTRAL_GRAY, PLACEHOLDER_COLOR, PassageCard, PdfIcon, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PresenceLabel, Progress, ProjectEntity, RadioGroup, RadioGroupItem, RagDot, RelevanceDot, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Slider, StatusPill, Switch, TAG_TYPE_ICONS, TAG_TYPE_LABELS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagEntity, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserEntity, UserMenu, VISIBILITY_ICONS, VidIcon, VisibilityIcon, badgeVariants, buttonVariants, cardVariants, classifyMediaError, configureEntityRegistry, configureRagLabels, configureStatusRegistry, formatElapsed, getDocIcon, getEntityColor2 as getEntityColor, getEntityColorStyles, getEntityIcon, getEntityLabel, getStatusVariant, getTagTypeIcon, getTagTypeLabel, getWorkspaceColor, toggleVariants, useAudioRecorder };
|
|
3669
|
-
//# sourceMappingURL=chunk-
|
|
3670
|
-
//# sourceMappingURL=chunk-
|
|
3669
|
+
//# sourceMappingURL=chunk-U7RBOJK3.js.map
|
|
3670
|
+
//# sourceMappingURL=chunk-U7RBOJK3.js.map
|