import { A as Artifact, a as CanvasEvent, E as ElementSelection, S as StreamEvent, C as CanvasTransport, F as FileData, b as SlidesData, T as TableData, D as DocumentData, c as ChartData, H as HtmlData } from './types-CRfW09Y2.js'; export { d as ArtifactStatus, e as CanvasAppend, f as CanvasCommit, g as CanvasCreate, h as CanvasNodePatch, i as CanvasPatch, j as CanvasReplace, k as CanvasStatus, l as ChartArtifact, m as ChartOptions, n as ChartSeries, o as ChatEvent, p as DOCUMENT_FILE_SUFFIXES, q as DocumentArtifact, r as DoneEvent, s as ErrorEvent, t as FileArtifact, u as HtmlArtifact, K as KnownArtifact, M as MessageDelta, v as MessageEnd, x as Slide, y as SlideElement, z as SlidePage, B as SlideTableCell, G as SlidesArtifact, I as TableArtifact, J as TableColumn, L as ToolEnd, N as ToolStart, O as TransportRequest, P as isCanvasEvent, Q as isChatEvent, R as isDocumentSelection, w as withSelections } from './types-CRfW09Y2.js'; import * as react from 'react'; import { ReactNode, ComponentType } from 'react'; import { StoreApi } from 'zustand/vanilla'; /** * The reconciler — the single place artifact state is mutated. * * `reduceCanvas(state, event)` is a pure function: given the current canvas * state and one canvas event, it returns the next state. The store, hooks, and * components never branch on event `type` — they read the reconciled artifacts. * That keeps streaming (`append`), partial updates (`patch`), and versioning * (`replace`) auditable in one reducer. */ interface CanvasState { /** Current (latest-version) artifact per id. */ artifacts: Record; /** Version snapshots per id, oldest first. Grows on `canvas.replace`. */ history: Record; /** Creation order — drives tab ordering in the panel. */ order: string[]; /** The artifact the panel currently focuses. */ activeId: string | null; } declare function emptyCanvasState(): CanvasState; declare function reduceCanvas(state: CanvasState, event: CanvasEvent): CanvasState; /** * The snapshots the version rail counts: the described ones. * * The history also holds the *working* entry an edit opens, which the next * commit folds into the version it continues. Counting that entry made the * rail read v2/2 while typing and v1/1 the moment it saved — a number that * goes backwards reads as work being lost. A version is something that was * committed; what is being typed is the current state of one, not another one. */ declare function versionRail(snapshots: Artifact[]): Artifact[]; /** Update the live artifact after a content change. A committed (described) * tail is frozen — new work opens a fresh working entry on top of it instead * of overwriting the snapshot. */ declare function updateLive(state: CanvasState, artifact: Artifact): CanvasState; /** * RFC 7386 JSON Merge Patch: `null` deletes a key, plain objects merge * recursively, everything else (arrays, scalars) replaces. */ declare function mergePatch(target: unknown, patch: unknown): unknown; /** * SSE client — POST a chat message and yield parsed `StreamEvent`s. * * We use `fetch` + `ReadableStream` rather than the browser `EventSource` * because the chat endpoint is a POST (EventSource is GET-only) and we want an * `AbortSignal` for cancellation. Frames are separated by a blank line; each * `data:` payload is one JSON `StreamEvent`. */ interface ChatRequest { threadId: string; message: string; /** Element context for a targeted edit (set when editing selected elements). */ selections?: ElementSelection[]; } interface StreamOptions { signal?: AbortSignal; headers?: Record; } /** Open the chat stream and yield events until the server sends `done`. */ declare function streamChat(endpoint: string, request: ChatRequest, options?: StreamOptions): AsyncGenerator; /** Turn a byte stream of SSE frames into a stream of typed events. */ declare function parseSSE(body: ReadableStream, signal?: AbortSignal): AsyncGenerator; /** * The iframe inspector — makes an `html` artifact directly editable. * * `withInspector(html)` injects a small, self-contained script + style into the * page rendered inside the sandboxed iframe. That script: * * 1. stamps every element with a deterministic `data-cid` (a tree path like * `e-0-2`), so a selection survives re-renders and the agent can target it; * 2. outlines the element under the cursor on hover; * 3. on click, marks it selected and `postMessage`s a selection payload — * including a snapshot of its key computed styles — to the parent window; * 4. on double-click, makes a text element `contenteditable`; on blur it posts * the edited element back as `node_edit` (the host commits it as a * `canvas.node_patch`); * 5. responds to parent commands: `set_style` (apply a style live), `commit` * (post the element's current HTML back as `node_edit`), and `clear`. * * The script runs inside a `sandbox="allow-scripts"` iframe with a null origin, * so it cannot reach the parent DOM, cookies, or storage — only `postMessage`. */ declare const INSPECTOR_MARK = "langchain-canvas"; /** Inject the inspector into an HTML string, before `` when present. The * injected nodes are tagged `data-lcx` so a full-document save can strip them. * Also ensures a responsive viewport meta so device-width media queries behave * the same in the preview, in export, and on a real device. * * With `readOnly`, the script resolves asset references and stops: nothing is * selectable or editable, and the frame answers no commands. * * With `assetBaseUrl`, the inspector also resolves canvas-asset references * (`src="assets/…"` / `src="sources/…"`) for display: the original relative * src is kept in `data-lcx-src` and restored on every serialization, so the * stored document never sees a resolved URL. */ declare function withInspector(html: string, assetBaseUrl?: string, options?: { readOnly?: boolean; }): string; /** Computed-style properties surfaced to the style panel (camelCase). */ declare const STYLE_PROPS: readonly ["color", "backgroundColor", "fontSize", "fontWeight", "textAlign", "lineHeight", "letterSpacing", "padding", "borderRadius", "width"]; /** Keeps every link inside the frame. A `srcdoc` document resolves a bare * `#section` against the host page's URL, so a plain anchor click tries to load * the host site inside the iframe — which the host's frame-ancestors policy * refuses, leaving a "refused to connect" page where the document was. In-page * anchors scroll to their target instead (read-only only: in edit mode a click * selects the element and must not move the page); every other link and every * form submit is dropped, so a page can never lead out of the canvas. Runs * before anything else the inspector wires, in both modes. */ declare const NAV_GUARD_SCRIPT = "\nif (!window.__LCX_NAV_GUARD) {\nwindow.__LCX_NAV_GUARD = true;\ndocument.addEventListener(\"click\", function (e) {\n var t = e.target;\n var a = t instanceof Element ? t.closest(\"a[href]\") : null;\n if (!a) return;\n e.preventDefault();\n if (!window.__LCX_READONLY) return;\n var href = a.getAttribute(\"href\") || \"\";\n if (href.charAt(0) !== \"#\") return;\n var id = \"\";\n try { id = decodeURIComponent(href.slice(1)); } catch (err) { id = href.slice(1); }\n var target = id ? (document.getElementById(id) || document.getElementsByName(id)[0]) : null;\n (target || document.documentElement).scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n}, true);\ndocument.addEventListener(\"submit\", function (e) { e.preventDefault(); }, true);\n}\n"; /** * Schema-driven playback — render the canvas from a scripted list of wire * events, with no backend, no LLM, and no API key. * * The canvas is defined entirely by the wire protocol (`StreamEvent`s). That * means you can develop and demo the UI purely against the schema: hand it a * fixture and watch it render exactly as a real LangGraph agent would drive it. * `mockStream` turns an event array into a timed async stream, shaped identically * to `streamChat`, so anything that consumes one consumes the other. */ interface MockStreamOptions { /** Delay between events, ms. Simulates streaming cadence. Default 120. */ delayMs?: number; signal?: AbortSignal; } /** Yield a fixed list of events over time — a drop-in for `streamChat`. */ declare function mockStream(events: StreamEvent[], options?: MockStreamOptions): AsyncGenerator; /** * Which canvas files are edited through a copy. * * An upload under `sources/` stays the person's original; the tools put an * editable copy at the canvas root under a name derived from it. Once that * copy exists the upload's own tab says nothing the copy does not — so the * tab bar shows the copy alone. The names are the Python tools' rules, * parity-pinned in `test_protocol_parity.py`. */ declare const SOURCES_PREFIX = "sources/"; /** In front of a Word copy's name (see `_WORKING_COPY_MARKER` in tools.py). */ declare const WORKING_COPY_MARKER = "Editing - "; /** The canvas-root ids a copy of `sourceId` may live under. */ declare function workingCopyIds(sourceId: string): string[]; /** The ids the tab bar shows: every artifact except a source whose copy is open. */ declare function visibleTabs(order: string[]): string[]; /** * `sseTransport` — the default socket: the Canvas Wire Protocol over SSE. * * Speaks to a reference-style server (`POST endpoint` with * `{thread_id, message, selections}`, answered by an SSE stream of * `StreamEvent` frames). This is exactly what `useCanvasStream` always did; * it is now one `CanvasTransport` implementation among several. */ interface SseTransportOptions { /** Chat SSE endpoint. Defaults to `/api/chat`. */ endpoint?: string; /** Extra request headers (e.g. auth). */ headers?: Record; } declare function sseTransport(options?: SseTransportOptions): CanvasTransport; /** * `mockTransport` — scripted offline playback as a socket implementation. * * Wraps the `mockStream` player in the `CanvasTransport` contract: the script * maps a user message to the `StreamEvent[]` to play. Returning `null` falls * through to the wrapped transport (a live backend), which is how the demo * mixes canned examples with real chat. */ type MockScript = (message: string) => StreamEvent[] | null; declare function mockTransport(script: MockScript, fallback?: CanvasTransport, options?: Pick): CanvasTransport; /** * The canvas store — chat transcript + reconciled canvas state in one place. * * This is a *factory*, not a singleton: `createCanvasStore()` returns an * isolated store so an app can host several independent canvas/chat instances. * `` (see `context.tsx`) wires one up; provider-less apps share a * lazily-created default store, keeping the simple API working. * * Every wire event flows through `applyEvent` → the pure `reduceCanvas` reducer * for canvas events, folded into `messages` for chat events, so streaming, * patching, and versioning stay in one auditable place. */ /** Fired when the *user* edits an artifact in the canvas (a table cell, a chart * value, document text, a slide/HTML element). The host wires this to sync the * edit back to the agent/backend so the next turn sees it. */ type UserEditHandler = (artifact: Artifact) => void; interface ChatMessage { id: string; role: "user" | "assistant"; text: string; /** Artifact ids this assistant message produced — drives inline artifact cards. */ artifactIds?: string[]; } /** A command the editing UI forwards to the active html artifact's iframe. */ interface IframeCommand { artifactId: string; /** style · structure (duplicate/delete/move/insert/insert_html) · group/ungroup · set_src · set_slide_style · clear. */ type: "set_style" | "style_persist" | "commit" | "clear" | "set_src" | "set_slide_style" | "scroll_to" | "duplicate" | "delete" | "move_up" | "move_down" | "insert" | "insert_html" | "group" | "ungroup"; /** Target element (omitted for document-level inserts with no selection). */ cid?: string; /** Members to wrap for `group`. */ cids?: string[]; prop?: string; value?: string; /** Style map to apply to the slide root for `set_slide_style` (e.g. background, color). */ style?: Record; /** Heading index to scroll into view for `scroll_to`. */ index?: number; /** Tag/block to insert for `insert` (e.g. "h2", "p", "button", "img", "hr", "section"). */ block?: string; /** HTML fragment to insert for `insert_html` (a built-in section template). */ html?: string; /** Monotonic counter so re-issuing an identical command still fires. */ seq: number; } interface CanvasStore { canvas: CanvasState; messages: ChatMessage[]; isStreaming: boolean; /** The agent is working on this canvas: hand edits are refused until it is done. */ isBusy: boolean; error: string | null; /** Elements the user selected inside an `html` artifact (click = 1, marquee = N). */ selections: ElementSelection[]; /** Last command forwarded to the html iframe (style panel → renderer bus). */ iframeCommand: IframeCommand | null; /** Snapshots for undo/redo, per artifact — only the person's own edits are * recorded, and an agent write to a file clears that file's stacks: what * the agent produced is a version on the rail, not a step to undo. */ undoStack: Record; redoStack: Record; /** Host callback fired after a user edit reconciles — the write-back hook. */ onUserEdit: UserEditHandler | null; /** Fires every pending debounced save at once (see `useCanvasSave`). */ saveFlusher: (() => Promise) | null; /** URL prefix that resolves a canvas-relative asset path (see `resolveAssetUrl`). * Renderers use it to display `assets/` / `sources/` references live; the * export menu uses it to inline them. Null = no file endpoint (references * stay unresolved, everything else behaves as before). */ assetBaseUrl: string | null; /** URL prefix that renders one page of a stored file as an image (see * `resolveCanvasPageUrl`). Null = no page endpoint; paged files fall back * to their cover. */ pageBaseUrl: string | null; /** The host shows pages to look at, not to edit: an html artifact renders * without the in-frame inspector and without its edit toolbar. */ readOnly: boolean; /** The shown artifact's rendered body HTML (editor chrome stripped), for a * host-drawn export control — `` registers it while an artifact is * on screen. Null = nothing on screen. */ renderedHtml: (() => string | null) | null; applyEvent: (event: StreamEvent) => void; /** Apply a batch of events in a single store write (one re-render per frame). */ applyEvents: (events: StreamEvent[]) => void; /** Apply a *user*-initiated event, recording a snapshot so it can be undone. */ applyUserEvent: (event: StreamEvent) => void; /** Step the active artifact back / forward. Each step is an edit like any * other: it is refused while the agent works and it reaches `onUserEdit`, * so what is on screen after undo is what gets saved. */ undo: () => void; redo: () => void; /** Hand pending saves through now (the host registers the flusher). Blurs * an edit in progress first so its value is part of what lands. */ flushSaves: () => Promise; setSaveFlusher: (flush: (() => Promise) | null) => void; addUserMessage: (text: string) => void; setStreaming: (value: boolean) => void; /** Freeze or thaw hand editing (the host flips this around an agent run). */ setBusy: (value: boolean) => void; setActiveArtifact: (id: string) => void; setSelections: (selections: ElementSelection[]) => void; sendIframeCommand: (command: Omit) => void; /** Register (or clear) the user-edit write-back handler. */ setOnUserEdit: (handler: UserEditHandler | null) => void; setAssetBaseUrl: (url: string | null) => void; setPageBaseUrl: (url: string | null) => void; setReadOnly: (value: boolean) => void; setRenderedHtml: (getter: (() => string | null) | null) => void; reset: () => void; } /** Create an isolated canvas store. */ declare function createCanvasStore(): StoreApi; interface CanvasProviderProps { children: ReactNode; /** Bring your own store (e.g. shared across trees); one is created otherwise. */ store?: StoreApi; } declare function CanvasProvider({ children, store }: CanvasProviderProps): react.JSX.Element; /** The raw store API for the nearest provider (or the default store). */ declare function useCanvasStoreApi(): StoreApi; /** Subscribe to a slice of the canvas store. */ declare function useCanvasStore(selector: (state: CanvasStore) => T): T; interface UseCanvasStreamOptions { /** * How to reach the agent backend. Defaults to the reference Canvas Wire * Protocol over SSE (`sseTransport`); pass `langgraphTransport(...)` (from * the `/langgraph` entry) or your own `CanvasTransport` to speak to a * different backend. */ transport?: CanvasTransport; /** Chat SSE endpoint for the default transport. Defaults to `/api/chat`. */ endpoint?: string; /** Conversation thread id (for server-side memory). Defaults to a fresh uuid. */ threadId?: string; /** * Offline mock: given the user's message, return a scripted `StreamEvent[]` * to play instead of hitting the network — an OpenAPI-style "try it" with no * real LLM call. Return `null` to fall through to the live transport. */ mock?: (message: string) => StreamEvent[] | null; } declare function useCanvasStream(options?: UseCanvasStreamOptions): { sendMessage: (text: string, withSelections?: ElementSelection[]) => Promise; stop: () => void | undefined; reset: () => void; setActiveArtifact: (id: string) => void; selections: ElementSelection[]; editSelection: (instruction: string) => void; clearSelection: () => void; messages: ChatMessage[]; canvas: CanvasState; isStreaming: boolean; error: string | null; threadId: string; }; declare function useCanvasReplay(): { play: (events: StreamEvent[], options?: MockStreamOptions) => Promise; stop: () => void | undefined; reset: () => void; canvas: CanvasState; isPlaying: boolean; }; /** * `useArtifactPatch` — let a renderer commit an inline edit back to the store. * * Editing an artifact on the canvas is just a client-side `canvas.patch`: it * flows through the exact same reconciler an agent's edits do, so the edited * value is the one that renders, versions, and exports. Renderers stay in sync * with the single source of truth instead of holding a private copy. */ declare function useArtifactPatch(id: string): (patch: Record) => void; /** * `useCanvasSave` — debounced whole-artifact persistence for user edits. * * The store's `onUserEdit` handler fires per committed user edit (never for * agent streaming). This hook turns an `onSave` handler into a debounced * per-edit callback for that signal: after `debounceMs` of quiet it hands the * latest reconciled artifact to `onSave`. The host decides where it goes — a * `CanvasStore`-backed endpoint, local storage, anywhere. * * `` wires this automatically (composed with the host's * own `onUserEdit`, both sharing the store's single user-edit slot). Headless * hosts can call the hook themselves and register the returned callback via * `setOnUserEdit`. * * `baseRevision` is the artifact's last known store revision (stamped into * `meta.revision` by `canvas.commit` events); hosts pass it to their save * endpoint so a stale write can be rejected instead of overwriting. */ interface CanvasSavePayload { artifactId: string; artifact: Artifact; /** Store revision the user's edit is based on, when known. */ baseRevision: string | null; } type CanvasSaveHandler = (payload: CanvasSavePayload) => void | Promise; /** The per-edit callback, with `flush` to hand every pending save through now. */ type CanvasSaver = ((artifact: Artifact) => void) & { flush: () => Promise; }; declare function useCanvasSave(onSave: CanvasSaveHandler | undefined, debounceMs?: number): CanvasSaver | null; /** * Schema fixtures — scripted wire-event sequences that render the canvas with no * backend. Feed one to `useCanvasReplay().play(scenario.events)`. * * Each scenario is nothing but `StreamEvent`s: exactly what a LangGraph agent * would emit over the wire. They double as living documentation of the protocol * and as a zero-dependency way to develop renderers. */ interface Scenario { id: string; title: string; description: string; events: StreamEvent[]; } declare const scenarios: Scenario[]; interface RendererProps { artifact: Artifact; } type ArtifactRenderer = ComponentType>; type ArtifactRegistry = Record; interface CanvasRegistryProviderProps { registry: ArtifactRegistry; children: ReactNode; } declare function CanvasRegistryProvider({ registry, children }: CanvasRegistryProviderProps): react.JSX.Element; /** Resolve the renderer for an artifact type, or `undefined` if unregistered. */ declare function useRenderer(type: string): ArtifactRenderer | undefined; /** Merge registries — later entries win. Handy for extending the built-ins. */ declare function mergeRegistries(...registries: ArtifactRegistry[]): ArtifactRegistry; /** One host-supplied entry appended to the menu (a server-side export, say). */ interface ExportExtra { /** Menu label, e.g. "PowerPoint". */ label: string; /** Small extension chip after the label, e.g. "pptx". */ extension?: string; run: () => void | Promise; } interface ExportMenuProps { artifact: Artifact; getRenderedHtml: () => string | null; /** Extra entries appended after the built-in ones — nothing is replaced. */ extras?: ExportExtra[]; } declare function ExportMenu({ artifact, getRenderedHtml, extras }: ExportMenuProps): react.JSX.Element; /** * `useCanvasImport` — open local files onto the canvas. * * Turns a `File` (from a file picker or a drag-and-drop) into canvas events and * applies them through the store, so the imported document/sheet/page becomes a * first-class artifact you can edit and re-export. Returns the id of the last * artifact created so callers can focus it. */ interface CanvasImportOptions { /** * Fired once per successfully imported file with the artifact that now * renders on the canvas — the hook for a host to persist an imported * table/document to its store right away. */ onImported?: (artifact: Artifact, file: File) => void; } declare function useCanvasImport({ onImported }?: CanvasImportOptions): { importFiles: (files: Iterable) => Promise; canImport: (file: File) => boolean; }; interface CanvasLabels { busy: string; dropToOpen: string; loading: string; noRenderer: (type: string) => string; emptyTitle: string; emptyHint: string; emptyOpen: string; emptyFormats: string; emptyFormatsAny: string; statusWriting: string; statusError: string; statusReady: string; undo: string; redo: string; undoRedoGroup: string; versionsGroup: string; previousVersion: string; nextVersion: string; openVersions: string; versionsList: string; versionOf: (n: number, total: number) => string; versionItem: (n: number) => string; snapshot: string; viewingVersion: (n: number, total: number) => string; backToLatest: string; exportMenu: string; exportOpenInTab: string; exportCopyHtml: string; exportCopied: string; exportHtml: string; exportPdf: string; exportMarkdown: string; exportWord: string; exportCsv: string; exportJson: string; renderFailed: string; download: string; firstPage: (name: string) => string; previewOf: (name: string) => string; docxBanner: string; docxWords: (n: number) => string; docxPointingAt: (address: string) => string; docxSubstituted: (fonts: string) => string; docxShapesHidden: (n: number) => string; docxBulletsRedrawn: (fonts: string) => string; docxNoPageNumbers: string; docxShapesHiddenHint: string; docxBulletsRedrawnHint: string; tableLoading: string; tableWaiting: string; tableCalculating: string; chartWaiting: string; slidesEmpty: string; slideTableEmpty: string; addColumn: string; addRow: string; sortBy: string; sortPick: string; ascending: string; descending: string; filterRows: string; filterPlaceholder: string; tableHint: string; chartTitle: string; chartTitlePlaceholder: string; editData: string; done: string; seriesName: string; remove: string; axisLabelPlaceholder: string; yAxis: string; stacked: string; seriesColor: string; sliceColor: (name: string) => string; addChartRow: string; downloadPng: string; downloadPngTitle: string; addText: string; addTextTitle: string; addTable: string; addTableTitle: string; addImage: string; addImageTitle: string; addShape: string; addShapeTitle: string; addSlide: string; layoutPick: string; layoutPickTitle: string; backgroundColor: string; padding: string; paddingTitle: string; theme: string; themePick: string; backgroundImage: string; backgroundImageTitle: string; present: string; presentTitle: string; moveUp: string; moveDown: string; duplicateSlide: string; deleteSlide: string; previousSlide: string; nextSlide: string; speakerNotes: string; fontSize: string; alignLeft: string; alignCenter: string; alignRight: string; duplicate: string; bringForward: string; sendBack: string; deleteElement: string; textColor: string; fillColor: string; gridLineColor: string; dragToResizeColumn: string; bold: string; italic: string; inlineCode: string; heading1: string; heading2: string; bulletList: string; numberedList: string; quote: string; link: string; clickToEdit: string; readingTime: (words: number, minutes: number) => string; viewportDesktop: string; viewportTablet: string; viewportMobile: string; pagePick: string; pagePickTitle: string; sectionPick: string; sectionPickTitle: string; outlinePick: string; outlinePickTitle: string; slideLayoutPickTitle: string; slideThemePickTitle: string; shapePick: string; shapePickTitle: string; fontPick: string; fontPickTitle: string; group: string; ungroup: string; groupHint: string; groupNeedsTwo: string; htmlSource: string; previewWidth: string; addLabel: string; selectionLabel: string; slideBackgroundImage: string; a11yCheck: string; a11yCheckTitle: string; a11yOk: string; a11yIssues: (n: number) => string; dismiss: string; modeDesign: string; modeCode: string; styleText: string; styleBackground: string; styleSize: string; styleWeight: string; styleAlign: string; styleLineHeight: string; styleLetterSpacing: string; stylePadding: string; styleRadius: string; styleWidth: string; styleGradient: string; styleSolidColor: string; } declare const DEFAULT_LABELS: CanvasLabels; /** Optional chrome. Every flag defaults to `true` — the package's own look. */ interface CanvasChrome { /** The per-artifact header row (title, status, actions). */ header: boolean; statusBadge: boolean; undoRedo: boolean; versions: boolean; exportMenu: boolean; /** The "Preview only" note above a Word preview. */ docxBanner: boolean; /** The word-count / font-substitution line under a Word preview. */ docxStatus: boolean; /** The "mime · size · detail" facts under a file card's name. */ fileFacts: boolean; /** The Download link on a file card — off when the host's own export * control is the one download door. */ fileDownload: boolean; /** The version rail on a stored file's tab — off when the file is viewed * only and the host keeps version history elsewhere. */ fileVersions: boolean; /** The Desktop / Tablet / Mobile width switch above a web page — off when * pages are only looked at on a desktop; the page then takes the full width. */ htmlPreviewWidth: boolean; } declare const DEFAULT_CHROME: CanvasChrome; interface CanvasProps { /** Renderer map. Defaults to the built-in html/document/chart/table renderers. */ registry?: ArtifactRegistry; /** Rendered when no artifact has been opened yet. */ emptyState?: ReactNode; /** * Extra Export-menu entries for the shown artifact, appended after the * built-in ones — the seam for host-side (server) exports such as * slides→pptx or table→xlsx. Return `[]`/`undefined` for none. */ exportExtras?: (artifact: Artifact) => ExportExtra[] | undefined; /** * Handle a targeted edit of the selected element (from `useCanvasStream`'s * `editSelection`). When provided, clicking an element in an `html` artifact * reveals a quick-edit bar. */ onEditElement?: (instruction: string) => void; /** * Fired after the *user* edits an artifact directly in the canvas — a table * cell, a chart value, document text, a slide/HTML element — with the * reconciled artifact. Wire this to sync the edit back to the agent/backend so * the next turn sees it. Fires per committed edit (table edits are debounced); * debounce further on the host before hitting the network. */ onUserEdit?: (artifact: Artifact) => void; /** * Persist user edits: the debounced companion to `onUserEdit` (see * `useCanvasSave`). Called after edits go quiet, with the artifact and the * `baseRevision` to hand a store-backed save endpoint. When omitted, edits * stay in-memory exactly as before. */ onSave?: CanvasSaveHandler; /** * Fired with the raw files whenever the user opens files (picker or drop), * before any import parsing — the hook for a host to upload originals to * its store so the agent can read them. When provided, the file picker * accepts every file type (the canvas still previews only what it can * import; the host decides what to do with the rest). */ onFilesOpened?: (files: File[]) => void; /** Fired per successfully imported file with its canvas artifact (see `useCanvasImport`). */ onImported?: CanvasImportOptions["onImported"]; /** * URL prefix that resolves a canvas-relative asset path (`assets/…`, * `sources/…`) to fetchable bytes — the whole encoded path is appended, e.g. * `http://host/api/canvas//file?path=`. With it, asset references in * artifacts display live and export inlined as `data:` URIs. Omit it and * references stay unresolved — everything else behaves exactly as before. */ assetBaseUrl?: string; /** * URL prefix that renders one page of a stored file (`.pdf`, `.pptx`, * `.docx`) as an image — the encoded path is appended, then * `&page=N&width=W`, e.g. `http://host/api/canvas//file/page?path=`. * With it, a file whose `pageCount` is known opens as a page viewer; * without it, the cover shows. */ pageBaseUrl?: string; /** The agent is working: hand editing is frozen and a banner says so. */ busy?: boolean; /** What the banner reads while `busy` (default `labels.busy`). */ busyLabel?: string; /** * Pages are for looking at, not hand editing: an `.html` artifact renders * without the in-frame inspector (no hover, selection, drag or text * editing) and without its edit toolbar; only the device-width switch * stays. Asset references still resolve, and agent edits still land * through the store. Off by default. */ readOnly?: boolean; /** * Override any user-facing string the panel renders (a partial map — the * rest keep their defaults). See `CanvasLabels` for every key. */ labels?: Partial; /** * Leave out pieces of chrome the host draws itself (header, status badge, * undo/redo, version rail, export menu, Word-preview notes, file facts). * Every flag defaults to `true`. */ chrome?: Partial; } declare function Canvas({ registry, emptyState, exportExtras, onEditElement, onUserEdit, onSave, onFilesOpened, onImported, assetBaseUrl, pageBaseUrl, busy, busyLabel, readOnly, labels, chrome, }: CanvasProps): react.JSX.Element; interface SelectionBarProps { selections: ElementSelection[]; onEdit: (instruction: string) => void; onClear: () => void; } declare function SelectionBar({ selections, onEdit, onClear }: SelectionBarProps): react.JSX.Element; declare function StylePanel({ selection }: { selection: ElementSelection; }): react.JSX.Element; /** * `` — an inline reference to an artifact, for the chat transcript. * * Assistant messages carry the ids of the artifacts they produced * (`message.artifactIds`); render a card per id under the bubble so the artifact * shows up *in the conversation* (like ChatGPT), and clicking it focuses that * artifact in the `` panel. */ declare function ArtifactCard({ artifactId }: { artifactId: string; }): react.JSX.Element | null; declare function FileRenderer$1({ artifact }: RendererProps): react.JSX.Element; declare function SlidesRenderer$1({ artifact }: RendererProps): react.JSX.Element; declare function TableRenderer$1({ artifact, readOnly, }: RendererProps & { readOnly?: boolean; }): react.JSX.Element; declare function DocumentRenderer$1({ artifact }: RendererProps): react.JSX.Element; declare function ChartRenderer$1({ artifact }: RendererProps): react.JSX.Element; declare function HtmlRenderer({ artifact }: RendererProps): react.JSX.Element; declare const ChartRenderer: react.LazyExoticComponent; declare const DocumentRenderer: react.LazyExoticComponent; declare const TableRenderer: react.LazyExoticComponent; declare const SlidesRenderer: react.LazyExoticComponent; declare const FileRenderer: react.LazyExoticComponent; /** * The batteries-included renderers. `html` is the base substrate (sandboxed * iframe); the rest are structured conveniences, lazily loaded. Pass to * `` or merge with your own. They render under ``'s * Suspense boundary, so the on-demand chunks resolve transparently. */ declare const builtinRenderers: ArtifactRegistry; /** Browser download helpers — trigger a file save from an in-memory string. */ /** Save `content` as a file named `filename` with the given MIME type. */ declare function downloadBlob(filename: string, mime: string, content: BlobPart): void; /** * Turn a title into a safe file stem: "Q1 Report!" -> "q1-report", * "매출 보고서 (초안)" -> "매출-보고서-초안". Letters and digits of any script * survive; everything else (punctuation, path separators, whitespace) folds * into single dashes. */ declare function slugify(text: string): string; /** * The client-side export actions for one artifact, as data. * * `` renders exactly this list; a host that draws its own export * control (one button, its own dropdown) builds the same list and gets the * same files — every path still leaves through the asset inliner, so exported * files stay self-contained. */ interface ExportAction { /** Stable key: `open-tab` · `copy` · `html` · `pdf` · a data exporter's extension. */ id: string; label: string; /** Small extension chip after the label, e.g. "pptx". */ extension?: string; run: () => Promise; } interface ExportActionOptions { /** The panel body's rendered HTML (editor chrome stripped), or null when unknown. */ getRenderedHtml: () => string | null; /** The host's file endpoint prefix, or null (references stay unresolved). */ assetBaseUrl: string | null; labels?: Partial>; } type ExportLabelKey = "exportOpenInTab" | "exportCopyHtml" | "exportHtml" | "exportPdf" | "exportMarkdown" | "exportWord" | "exportCsv" | "exportJson"; declare function buildExportActions(artifact: Artifact, options: ExportActionOptions): ExportAction[]; interface FileExport { /** Menu label, e.g. "Excel". */ label: string; /** File extension without the dot, e.g. "csv". */ extension: string; mime: string; /** Build the file contents (text or binary; may be async for Office formats). */ build: (artifact: Artifact) => BlobPart | Promise; } /** Per-type data exporters, keyed by `artifact.type`. */ declare const dataExporters: Record; /** Wrap already-rendered inner HTML into a standalone, styled `.html` document. */ declare function toStandaloneHtml(title: string, renderedHtml: string): string; /** * A print-ready HTML document with one landscape page per slide — fed to the * browser's print pipeline to produce a multi-page PDF. Elements keep their * percentage geometry, so pages match the on-canvas layout exactly. * * The page is the deck's own page at `PAGE_DPI`, which is the density * `fontSize` is stored at — so stored px are CSS px here and text needs no * scaling at all. Viewport units would resolve against whatever box the * printing frame happens to have, which is how the same document came out * one size in the print preview and another in the saved file. */ declare function slidesToPrintHtml(data: SlidesData, title: string): string; interface PrintFrameOptions { /** Lay a fluid web page out at paper width and keep each card on one page * (`markWholeBoxes`). A slide sheet sets its own pages and leaves this off. */ wholeBoxes?: boolean; } declare function printToPdf(html: string, options?: PrintFrameOptions): void; /** * File → artifact importers — the inverse of `export/exporters.ts`. * * `langchain-canvas` isn't only a viewer for agent output: you can open a real * file and edit it on the canvas, then export it back out (round-trip). Each * importer maps a file to a `canvas.create` + `canvas.status: complete` event * pair, so an opened file flows through the exact same reconciler path an * agent's stream would — no special-casing downstream. * * Dependency policy mirrors the exporters: every format here is parsed inline * with zero dependencies. A spreadsheet is opened on the Python side instead * (`langchain_canvas.xlsx_import`), which reads a workbook down to its fonts, * fills, merges and images — more than a browser should carry to do well. */ /** Extensions we can turn into an artifact, for `accept="…"` and drop filtering. */ declare const IMPORTABLE_EXTENSIONS: readonly [".csv", ".md", ".markdown", ".txt", ".html", ".htm", ".json"]; /** True when the file has an extension we know how to import. */ declare const canImport: (file: File) => boolean; /** * Parse a file into canvas events. Rejects if the extension is unsupported so * callers can surface a clear message. Text parsing is synchronous; `.xlsx` * awaits its dynamic import. */ declare function importFile(file: File): Promise; /** RFC-4180-ish CSV parser: handles quoted fields, embedded commas, and "" escapes. */ declare function parseCsv(text: string): TableData; /** * Canvas asset references — relative paths that point at files on the canvas. * * The reference contract: inside canvas content, a relative path starting with * `assets/` (files brought in by the agent) or `sources/` (the user's uploads) * points at a file on the *same* canvas — `` in an * html page, `![logo](assets/logo.png)` in a document, `src: "assets/logo.png"` * on a slide image element. * * Display resolves a reference against the host's file endpoint * (`resolveAssetUrl`), keeping the stored content relative. Export restores * self-containment at the door (`inlineArtifactAssets` / `inlineHtmlAssets`): * every reference becomes a `data:` URI so the exported file carries its * images. The unit of self-containment is the canvas folder while * collaborating, and the single file once exported. * * The Python twin lives in `langchain_canvas/assets.py`; the prefix list below * is compared against it by the protocol parity tests. */ declare const ASSET_REFERENCE_PREFIXES: readonly ["assets/", "sources/"]; /** * The canvas-root-relative path `src` refers to, or `null`. * * References are root-relative by contract, but a model writing a page that * lives in a folder often produces the document-relative form * (`../sources/photo.png`). Store paths can never contain `..` (the store * contract rejects them), and `assets/` / `sources/` exist only at the root — * so folding leading `./` / `../` segments onto the root reading is lossless * tolerance, not guesswork. Stored content is never rewritten; only consumers * (display, export inlining) interpret leniently. */ declare function normalizeAssetReference(src: string | undefined | null): string | null; declare function isAssetReference(src: string | undefined | null): src is string; /** * Absolute URL for a canvas-relative asset path. `assetBaseUrl` is a prefix the * whole (URI-encoded) path is appended to — e.g. the reference server's * `http://host/api/canvas//file?path=`. */ declare function resolveAssetUrl(src: string, assetBaseUrl: string): string; /** * Absolute URL for a stored canvas file, wherever on the canvas it sits. * * Not the same question as `isAssetReference`. That one reads a string found * *inside* content and asks whether it points at a canvas file — a guess that * has to be conservative, because most strings in a document are not paths. A * `file` artifact's `path` needs no guessing: it came from the store, so it is * a canvas file by definition, at the root or under any folder. Asking the * reference gate instead would leave every file outside `assets/` / `sources/` * with no URL — no preview, no download — and widening that gate to fix it * would make body-text scanning claim paths it should leave alone. */ declare function resolveCanvasFileUrl(path: string, assetBaseUrl: string): string; /** * Absolute URL for one rendered page of a stored file. `pageBaseUrl` is a * prefix the encoded path is appended to, followed by the 1-based page and * the wanted pixel width; `version` (the artifact's version) rides along so a * new commit never shows a cached image of the old bytes. */ declare function resolveCanvasPageUrl(path: string, page: number, width: number, pageBaseUrl: string, version?: number | string): string; /** Fetch one canvas asset and encode it as a `data:` URI (null on any failure). */ declare function fetchAssetDataUri(path: string, assetBaseUrl: string): Promise; /** * Replace canvas-asset references in an HTML string with `data:` URIs. * * Handles both the stored form (`src="assets/logo.png"`) and the display form a * rendered DOM serializes (`src=""`). A reference * that cannot be fetched is left untouched — honest: the export shows exactly * what could be resolved. Only `src` attributes are rewritten; CSS `url(...)` * references are out of contract. */ declare function inlineHtmlAssets(html: string, assetBaseUrl: string): Promise; /** * An artifact with every canvas-asset reference inlined as a `data:` URI — * the export chokepoint. `html` inlines its page source; `slides` inlines * image elements and the image-layout `image`; other types (and a missing * `assetBaseUrl`) pass through unchanged, so hosts without a file endpoint * keep today's behavior exactly. */ declare function inlineArtifactAssets(artifact: T, assetBaseUrl: string | null | undefined): Promise; /** * Display-time resolver for canvas-asset references. * * Returns a function that maps a `src` to a displayable URL: a canvas-relative * reference (`assets/…`, `sources/…`) resolves against the host's asset * endpoint; anything else — and every reference when no endpoint is configured * — passes through untouched. Resolution is display-only: stored artifact data * always keeps the relative reference. */ declare function useAssetUrl(): (src: string | undefined) => string | undefined; export { ASSET_REFERENCE_PREFIXES, Artifact, ArtifactCard, type ArtifactRegistry, type ArtifactRenderer, Canvas, type CanvasChrome, CanvasEvent, type CanvasLabels, type CanvasProps, CanvasProvider, type CanvasProviderProps, CanvasRegistryProvider, type CanvasSaveHandler, type CanvasSavePayload, type CanvasState, type CanvasStore, CanvasTransport, ChartData, ChartRenderer, type ChatMessage, type ChatRequest, DEFAULT_CHROME, DEFAULT_LABELS, DocumentData, DocumentRenderer, ElementSelection, type ExportAction, type ExportActionOptions, ExportMenu, FileData, type FileExport, FileRenderer, HtmlData, HtmlRenderer, IMPORTABLE_EXTENSIONS, INSPECTOR_MARK, type IframeCommand, type MockScript, type MockStreamOptions, NAV_GUARD_SCRIPT, type RendererProps, SOURCES_PREFIX, STYLE_PROPS, type Scenario, SelectionBar, SlidesData, SlidesRenderer, type SseTransportOptions, StreamEvent, type StreamOptions, StylePanel, TableData, TableRenderer, type UseCanvasStreamOptions, type UserEditHandler, WORKING_COPY_MARKER, buildExportActions, builtinRenderers, canImport, createCanvasStore, dataExporters, downloadBlob, emptyCanvasState, fetchAssetDataUri, importFile, inlineArtifactAssets, inlineHtmlAssets, isAssetReference, mergePatch, mergeRegistries, mockStream, mockTransport, normalizeAssetReference, parseCsv, parseSSE, printToPdf, reduceCanvas, resolveAssetUrl, resolveCanvasFileUrl, resolveCanvasPageUrl, scenarios, slidesToPrintHtml, slugify, sseTransport, streamChat, toStandaloneHtml, updateLive, useArtifactPatch, useAssetUrl, useCanvasImport, useCanvasReplay, useCanvasSave, useCanvasStore, useCanvasStoreApi, useCanvasStream, useRenderer, versionRail, visibleTabs, withInspector, workingCopyIds };