@braincrew-lab/langchain-canvas 0.7.4 → 0.7.6

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.
@@ -1,5 +1,5 @@
1
- import { useAssetUrl } from './chunk-HCF2DXCR.js';
2
- import './chunk-7T5DRR3F.js';
1
+ import { useAssetUrl } from './chunk-HCOQ6XCQ.js';
2
+ import './chunk-HMYM6BTB.js';
3
3
  import { useArtifactPatch } from './chunk-N5JW2BKI.js';
4
4
  import './chunk-RAPTQ6VH.js';
5
5
  import { useState, useRef } from 'react';
@@ -141,6 +141,107 @@ function docxStats(root) {
141
141
  substitutedFonts: substitutedFonts(root)
142
142
  };
143
143
  }
144
+
145
+ // src/io/symbolBullets.ts
146
+ var SYMBOL_FONT_BULLETS = {
147
+ symbol: {
148
+ 61623: "\u2022"
149
+ // • bullet — Word's default list bullet
150
+ },
151
+ wingdings: {
152
+ 61548: "\u25CF",
153
+ // ● black circle
154
+ 61549: "\u274D",
155
+ // ❍ shadowed white circle
156
+ 61550: "\u25A0",
157
+ // ■ black square
158
+ 61551: "\u25A1",
159
+ // □ white square
160
+ 61553: "\u2751",
161
+ // ❑ lower-right shadowed white square
162
+ 61557: "\u25C6",
163
+ // ◆ black diamond
164
+ 61607: "\u25AA",
165
+ // ▪ black small square
166
+ 61656: "\u27A2",
167
+ // ➢ three-d top-lighted right arrowhead
168
+ 61692: "\u2714",
169
+ // ✔ heavy check mark
170
+ 61694: "\u2611"
171
+ // ☑ ballot box with check
172
+ }
173
+ };
174
+ function isPrivateUse(codePoint) {
175
+ return codePoint >= 57344 && codePoint <= 63743;
176
+ }
177
+ function primaryFont(fontFamily) {
178
+ const first = fontFamily.split(",")[0] ?? "";
179
+ return first.trim().replace(/^['"]|['"]$/g, "").toLowerCase();
180
+ }
181
+ function standardBullet(codePoint, fontFamily) {
182
+ const table = SYMBOL_FONT_BULLETS[primaryFont(fontFamily)];
183
+ return table?.[codePoint] ?? null;
184
+ }
185
+ function drawnOnPage(root, selectorText) {
186
+ return selectorText.split(",").some((part) => {
187
+ const base = part.trim().replace(/::?(before|after)\s*$/i, "").trim();
188
+ if (!base) return false;
189
+ try {
190
+ return root.querySelector(base) !== null;
191
+ } catch {
192
+ return false;
193
+ }
194
+ });
195
+ }
196
+ function styleRules(sheet) {
197
+ const found = [];
198
+ const stack = [...sheet.cssRules];
199
+ while (stack.length) {
200
+ const rule = stack.pop();
201
+ if (rule.cssRules?.length) {
202
+ stack.push(...rule.cssRules);
203
+ continue;
204
+ }
205
+ if (rule.style && rule.selectorText) found.push(rule);
206
+ }
207
+ return found;
208
+ }
209
+ function restoreSymbolBullets(root) {
210
+ const swaps = [];
211
+ for (const style of Array.from(root.querySelectorAll("style"))) {
212
+ let rules;
213
+ try {
214
+ rules = style.sheet ? styleRules(style.sheet) : [];
215
+ } catch {
216
+ continue;
217
+ }
218
+ for (const rule of rules) {
219
+ const content = rule.style.getPropertyValue("content");
220
+ if (!content) continue;
221
+ const font = rule.style.getPropertyValue("font-family");
222
+ if (!font) continue;
223
+ if (!drawnOnPage(root, rule.selectorText)) continue;
224
+ let next = "";
225
+ let changed = false;
226
+ for (const character of content) {
227
+ const code = character.codePointAt(0) ?? 0;
228
+ const standard = isPrivateUse(code) ? standardBullet(code, font) : null;
229
+ if (standard === null) {
230
+ next += character;
231
+ continue;
232
+ }
233
+ next += standard;
234
+ changed = true;
235
+ swaps.push({ from: character, to: standard, font: primaryFont(font) });
236
+ }
237
+ if (changed) rule.style.setProperty("content", next);
238
+ }
239
+ }
240
+ return swaps;
241
+ }
242
+ function redrawnFonts(swaps) {
243
+ return [...new Set(swaps.map((swap) => swap.font))];
244
+ }
144
245
  var BANNER = "Preview only \u2014 to change it, ask in chat or select some text.";
145
246
  function DocxPreview({
146
247
  artifactId,
@@ -151,6 +252,7 @@ function DocxPreview({
151
252
  const hostRef = useRef(null);
152
253
  const [status, setStatus] = useState("loading");
153
254
  const [stats, setStats] = useState(null);
255
+ const [redrawn, setRedrawn] = useState([]);
154
256
  const [picked, setPicked] = useState(null);
155
257
  const setSelections = useCanvasStore((s) => s.setSelections);
156
258
  useEffect(() => {
@@ -160,6 +262,7 @@ function DocxPreview({
160
262
  if (!host) return;
161
263
  setStatus("loading");
162
264
  setStats(null);
265
+ setRedrawn([]);
163
266
  setPicked(null);
164
267
  (async () => {
165
268
  const { renderAsync } = await loadOptional(
@@ -181,6 +284,7 @@ function DocxPreview({
181
284
  });
182
285
  if (!live) return;
183
286
  stampDocxAddresses(host);
287
+ setRedrawn(redrawnFonts(restoreSymbolBullets(host)));
184
288
  setStats(docxStats(host));
185
289
  setStatus("ready");
186
290
  let fittedFor = host.clientWidth;
@@ -262,7 +366,18 @@ function DocxPreview({
262
366
  stats.substitutedFonts.length > 0 && /* @__PURE__ */ jsxs("span", { className: "cv-docx__fonts", children: [
263
367
  "substituted: ",
264
368
  stats.substitutedFonts.join(", ")
265
- ] })
369
+ ] }),
370
+ redrawn.length > 0 && /* @__PURE__ */ jsxs(
371
+ "span",
372
+ {
373
+ className: "cv-docx__redrawn",
374
+ title: "This document writes its list bullets as characters in a symbol font's own private area, which no other font can draw. They are shown here as the standard characters that mean the same mark; the stored file is unchanged.",
375
+ children: [
376
+ "bullets redrawn: ",
377
+ redrawn.join(", ")
378
+ ]
379
+ }
380
+ )
266
381
  ]
267
382
  }
268
383
  )
@@ -1,4 +1,4 @@
1
- import { isAssetReference, resolveAssetUrl } from './chunk-7T5DRR3F.js';
1
+ import { resolveCanvasFileUrl } from './chunk-HMYM6BTB.js';
2
2
  import { useCanvasStore } from './chunk-RAPTQ6VH.js';
3
3
  import { lazy, Suspense } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -10,7 +10,7 @@ function formatSize(size) {
10
10
  return `${(size / (1024 * 1024)).toFixed(1)} MB`;
11
11
  }
12
12
  var DocxPreview = lazy(
13
- () => import('./DocxPreview-QK4K5427.js').then((m) => ({ default: m.DocxPreview }))
13
+ () => import('./DocxPreview-NGT3Z5KW.js').then((m) => ({ default: m.DocxPreview }))
14
14
  );
15
15
  function iconFor(mediaType, name) {
16
16
  if (mediaType?.startsWith("image/")) return "\u{1F5BC}\uFE0F";
@@ -24,7 +24,7 @@ function iconFor(mediaType, name) {
24
24
  function FileRenderer({ artifact }) {
25
25
  const { path, name, mediaType, size, cover, excerpt, detail } = artifact.data;
26
26
  const assetBaseUrl = useCanvasStore((s) => s.assetBaseUrl);
27
- const href = assetBaseUrl && isAssetReference(path) ? resolveAssetUrl(path, assetBaseUrl) : null;
27
+ const href = assetBaseUrl && path ? resolveCanvasFileUrl(path, assetBaseUrl) : null;
28
28
  const isImage = Boolean(mediaType?.startsWith("image/"));
29
29
  const isWord = `${path} ${name}`.toLowerCase().includes(".docx");
30
30
  const facts = [mediaType, formatSize(size), detail].filter(Boolean).join(" \xB7 ");
@@ -1,6 +1,6 @@
1
1
  import { deckPage, pageAspect, DEFAULT_SLIDE_PAGE_IN, resolveElements, fontScaleFor } from './chunk-MZ5WQWTS.js';
2
- import { useAssetUrl } from './chunk-HCF2DXCR.js';
3
- import './chunk-7T5DRR3F.js';
2
+ import { useAssetUrl } from './chunk-HCOQ6XCQ.js';
3
+ import './chunk-HMYM6BTB.js';
4
4
  import { useArtifactPatch } from './chunk-N5JW2BKI.js';
5
5
  import './chunk-RAPTQ6VH.js';
6
6
  import { useState, useRef, useEffect } from 'react';
@@ -0,0 +1,30 @@
1
+ // src/protocol/selection.ts
2
+ var DOCUMENT_FILE_SUFFIXES = [".docx"];
3
+ function isDocumentSelection(selection) {
4
+ const id = selection.artifactId.toLowerCase();
5
+ return DOCUMENT_FILE_SUFFIXES.some((suffix) => id.endsWith(suffix));
6
+ }
7
+ function withSelections(message, selections) {
8
+ if (selections.length === 0) return message;
9
+ const artifactId = selections[0].artifactId;
10
+ if (selections.every(isDocumentSelection)) {
11
+ const listed2 = selections.map((s) => `- [${s.cid}]${s.text ? `: \u201C${s.text}\u201D` : ""}`).join("\n");
12
+ return `${message}
13
+
14
+ [Targeted edit] The user pointed at this place in \`${artifactId}\`:
15
+ ${listed2}
16
+ First call read_canvas on the file for its current revision and the same addresses, then change that place with edit_canvas (or insert_document_paragraph / remove_document_paragraph / replace_document_image). Those take a text anchor, not the address \u2014 copy it from the read_canvas output, because the numbers move as soon as a paragraph is added or removed.`;
17
+ }
18
+ const listed = selections.map((s) => {
19
+ const shown = s.text ? ` \u2014 \u201C${s.text}\u201D` : "";
20
+ return s.outerHtml ? `- \`${s.selector}\`${shown}
21
+ ${s.outerHtml}` : `- \`${s.selector}\`${shown}`;
22
+ }).join("\n");
23
+ return `${message}
24
+
25
+ [Targeted edit] Apply the change to these selected element(s) in file \`${artifactId}\`:
26
+ ${listed}
27
+ First call read_canvas on the file for its current content and revision, then call edit_canvas with that element's exact markup from the file as \`old\` and your replacement as \`new\`. The markup listed above is the file's own; the screen adds attributes of its own for pointing, which are never stored, so do not look for them and do not add them.`;
28
+ }
29
+
30
+ export { DOCUMENT_FILE_SUFFIXES, isDocumentSelection, withSelections };
@@ -1,4 +1,4 @@
1
- import { isAssetReference, resolveAssetUrl } from './chunk-7T5DRR3F.js';
1
+ import { isAssetReference, resolveAssetUrl } from './chunk-HMYM6BTB.js';
2
2
  import { useCanvasStore } from './chunk-RAPTQ6VH.js';
3
3
  import { useCallback } from 'react';
4
4
 
@@ -14,6 +14,9 @@ function isAssetReference(src) {
14
14
  function resolveAssetUrl(src, assetBaseUrl) {
15
15
  return assetBaseUrl + encodeURIComponent(normalizeAssetReference(src) ?? src);
16
16
  }
17
+ function resolveCanvasFileUrl(path, assetBaseUrl) {
18
+ return assetBaseUrl + encodeURIComponent(path);
19
+ }
17
20
  var REF_ALTERNATION = ASSET_REFERENCE_PREFIXES.map((p) => p.slice(0, -1)).join("|");
18
21
  var srcAttrPattern = () => new RegExp(`(src=(["']))((?:\\.\\.?/)*(?:${REF_ALTERNATION})/[^"']+)(\\2)`, "g");
19
22
  var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -106,4 +109,4 @@ async function inlineArtifactAssets(artifact, assetBaseUrl) {
106
109
  return artifact;
107
110
  }
108
111
 
109
- export { ASSET_REFERENCE_PREFIXES, fetchAssetDataUri, inlineArtifactAssets, inlineHtmlAssets, isAssetReference, normalizeAssetReference, resolveAssetUrl };
112
+ export { ASSET_REFERENCE_PREFIXES, fetchAssetDataUri, inlineArtifactAssets, inlineHtmlAssets, isAssetReference, normalizeAssetReference, resolveAssetUrl, resolveCanvasFileUrl };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- 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-CzJ4zeUR.js';
2
- 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 DocumentArtifact, q as DoneEvent, r as ErrorEvent, s as FileArtifact, t as HtmlArtifact, K as KnownArtifact, M as MessageDelta, u as MessageEnd, v as Slide, w as SlideElement, x as SlidePage, y as SlidesArtifact, z as TableArtifact, B as TableColumn, G as ToolEnd, I as ToolStart, J as TransportRequest, L as isCanvasEvent, N as isChatEvent } from './types-CzJ4zeUR.js';
1
+ 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-CKgpjs_G.js';
2
+ 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 SlidesArtifact, G as TableArtifact, I as TableColumn, J as ToolEnd, L as ToolStart, N as TransportRequest, O as isCanvasEvent, P as isChatEvent, Q as isDocumentSelection, w as withSelections } from './types-CKgpjs_G.js';
3
3
  import * as react from 'react';
4
4
  import { ReactNode, ComponentType } from 'react';
5
5
  import { StoreApi } from 'zustand/vanilla';
@@ -600,6 +600,19 @@ declare function isAssetReference(src: string | undefined | null): src is string
600
600
  * `http://host/api/canvas/<id>/file?path=`.
601
601
  */
602
602
  declare function resolveAssetUrl(src: string, assetBaseUrl: string): string;
603
+ /**
604
+ * Absolute URL for a stored canvas file, wherever on the canvas it sits.
605
+ *
606
+ * Not the same question as `isAssetReference`. That one reads a string found
607
+ * *inside* content and asks whether it points at a canvas file — a guess that
608
+ * has to be conservative, because most strings in a document are not paths. A
609
+ * `file` artifact's `path` needs no guessing: it came from the store, so it is
610
+ * a canvas file by definition, at the root or under any folder. Asking the
611
+ * reference gate instead would leave every file outside `assets/` / `sources/`
612
+ * with no URL — no preview, no download — and widening that gate to fix it
613
+ * would make body-text scanning claim paths it should leave alone.
614
+ */
615
+ declare function resolveCanvasFileUrl(path: string, assetBaseUrl: string): string;
603
616
  /** Fetch one canvas asset and encode it as a `data:` URI (null on any failure). */
604
617
  declare function fetchAssetDataUri(path: string, assetBaseUrl: string): Promise<string | null>;
605
618
  /**
@@ -632,4 +645,4 @@ declare function inlineArtifactAssets<T extends Artifact>(artifact: T, assetBase
632
645
  */
633
646
  declare function useAssetUrl(): (src: string | undefined) => string | undefined;
634
647
 
635
- export { ASSET_REFERENCE_PREFIXES, Artifact, ArtifactCard, type ArtifactRegistry, type ArtifactRenderer, Canvas, CanvasEvent, type CanvasProps, CanvasProvider, type CanvasProviderProps, CanvasRegistryProvider, type CanvasSaveHandler, type CanvasSavePayload, type CanvasState, type CanvasStore, CanvasTransport, ChartData, ChartRenderer, type ChatMessage, type ChatRequest, DocumentData, DocumentRenderer, ElementSelection, ExportMenu, FileData, type FileExport, FileRenderer, HtmlData, HtmlRenderer, IMPORTABLE_EXTENSIONS, INSPECTOR_MARK, type IframeCommand, type MockScript, type MockStreamOptions, type RendererProps, STYLE_PROPS, type Scenario, SelectionBar, SlidesData, SlidesRenderer, type SseTransportOptions, StreamEvent, type StreamOptions, StylePanel, TableData, TableRenderer, type UseCanvasStreamOptions, type UserEditHandler, builtinRenderers, canImport, createCanvasStore, dataExporters, downloadBlob, emptyCanvasState, fetchAssetDataUri, importFile, inlineArtifactAssets, inlineHtmlAssets, isAssetReference, mergePatch, mergeRegistries, mockStream, mockTransport, normalizeAssetReference, parseCsv, parseSSE, printToPdf, reduceCanvas, resolveAssetUrl, scenarios, slidesToPrintHtml, slugify, sseTransport, streamChat, toStandaloneHtml, useArtifactPatch, useAssetUrl, useCanvasImport, useCanvasReplay, useCanvasSave, useCanvasStore, useCanvasStoreApi, useCanvasStream, useRenderer, withInspector };
648
+ export { ASSET_REFERENCE_PREFIXES, Artifact, ArtifactCard, type ArtifactRegistry, type ArtifactRenderer, Canvas, CanvasEvent, type CanvasProps, CanvasProvider, type CanvasProviderProps, CanvasRegistryProvider, type CanvasSaveHandler, type CanvasSavePayload, type CanvasState, type CanvasStore, CanvasTransport, ChartData, ChartRenderer, type ChatMessage, type ChatRequest, DocumentData, DocumentRenderer, ElementSelection, ExportMenu, FileData, type FileExport, FileRenderer, HtmlData, HtmlRenderer, IMPORTABLE_EXTENSIONS, INSPECTOR_MARK, type IframeCommand, type MockScript, type MockStreamOptions, type RendererProps, STYLE_PROPS, type Scenario, SelectionBar, SlidesData, SlidesRenderer, type SseTransportOptions, StreamEvent, type StreamOptions, StylePanel, TableData, TableRenderer, type UseCanvasStreamOptions, type UserEditHandler, builtinRenderers, canImport, createCanvasStore, dataExporters, downloadBlob, emptyCanvasState, fetchAssetDataUri, importFile, inlineArtifactAssets, inlineHtmlAssets, isAssetReference, mergePatch, mergeRegistries, mockStream, mockTransport, normalizeAssetReference, parseCsv, parseSSE, printToPdf, reduceCanvas, resolveAssetUrl, resolveCanvasFileUrl, scenarios, slidesToPrintHtml, slugify, sseTransport, streamChat, toStandaloneHtml, useArtifactPatch, useAssetUrl, useCanvasImport, useCanvasReplay, useCanvasSave, useCanvasStore, useCanvasStoreApi, useCanvasStream, useRenderer, withInspector };
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  "use client";
2
+ export { DOCUMENT_FILE_SUFFIXES, isDocumentSelection, withSelections } from './chunk-ASMMPDYS.js';
2
3
  import { projectSheetIntoRows, mergeRowsIntoSheet } from './chunk-IFNRLN4Y.js';
3
4
  import { loadOptional } from './chunk-YZZSJJMQ.js';
4
5
  import { deckPage, resolveElements } from './chunk-MZ5WQWTS.js';
5
- export { useAssetUrl } from './chunk-HCF2DXCR.js';
6
- import { inlineArtifactAssets, inlineHtmlAssets } from './chunk-7T5DRR3F.js';
7
- export { ASSET_REFERENCE_PREFIXES, fetchAssetDataUri, inlineArtifactAssets, inlineHtmlAssets, isAssetReference, normalizeAssetReference, resolveAssetUrl } from './chunk-7T5DRR3F.js';
6
+ export { useAssetUrl } from './chunk-HCOQ6XCQ.js';
7
+ import { inlineArtifactAssets, inlineHtmlAssets } from './chunk-HMYM6BTB.js';
8
+ export { ASSET_REFERENCE_PREFIXES, fetchAssetDataUri, inlineArtifactAssets, inlineHtmlAssets, isAssetReference, normalizeAssetReference, resolveAssetUrl, resolveCanvasFileUrl } from './chunk-HMYM6BTB.js';
8
9
  export { useArtifactPatch } from './chunk-N5JW2BKI.js';
9
10
  import { useCanvasStoreApi, useCanvasStore } from './chunk-RAPTQ6VH.js';
10
11
  export { CanvasProvider, createCanvasStore, emptyCanvasState, isCanvasEvent, isChatEvent, mergePatch, reduceCanvas, useCanvasStore, useCanvasStoreApi } from './chunk-RAPTQ6VH.js';
@@ -164,15 +165,19 @@ var INSPECTOR_SCRIPT = `
164
165
  }
165
166
  }
166
167
  }
167
- function emitEdit(el) {
168
- // Serialize the *canonical* HTML \u2014 strip the inspector's own injected
169
- // attributes/classes so they never persist into the stored source or exports.
170
- var cid = el.getAttribute("data-cid");
168
+ // The element's markup as the *stored file* has it: the inspector's own
169
+ // attributes and classes exist only on screen, so anything that leaves this
170
+ // frame \u2014 a saved edit, or the markup an agent is asked to match \u2014 has to be
171
+ // scrubbed first, or it names something the file does not contain.
172
+ function canonicalHtml(el) {
171
173
  var clone = el.cloneNode(true);
172
174
  scrub(clone);
173
175
  var inner = clone.querySelectorAll ? clone.querySelectorAll("[data-cid],[contenteditable],[data-lcx-src],.lcx-hover,.lcx-selected") : [];
174
176
  for (var i = 0; i < inner.length; i++) scrub(inner[i]);
175
- parent.postMessage({ source: MARK, type: "node_edit", cid: cid, html: clone.outerHTML }, "*");
177
+ return clone.outerHTML;
178
+ }
179
+ function emitEdit(el) {
180
+ parent.postMessage({ source: MARK, type: "node_edit", cid: el.getAttribute("data-cid"), html: canonicalHtml(el) }, "*");
176
181
  }
177
182
  // A structural change (insert/delete/move) shifts every cid, so we save the
178
183
  // whole document: clone <html>, drop the injected inspector nodes, scrub the
@@ -427,7 +432,7 @@ var INSPECTOR_SCRIPT = `
427
432
  selector: selectorFor(t),
428
433
  tag: t.tagName.toLowerCase(),
429
434
  text: (t.textContent || "").trim().slice(0, 80),
430
- outerHtml: t.outerHTML.slice(0, 4000),
435
+ outerHtml: canonicalHtml(t).slice(0, 4000),
431
436
  styles: stylesOf(t),
432
437
  isGroup: !!gid
433
438
  }, "*");
@@ -788,7 +793,7 @@ function useCanvasStream(options = {}) {
788
793
  const error = useCanvasStore((s) => s.error);
789
794
  const selections = useCanvasStore((s) => s.selections);
790
795
  const sendMessage = useCallback(
791
- async (text, withSelections) => {
796
+ async (text, withSelections2) => {
792
797
  const store = api.getState();
793
798
  if (store.isStreaming || !text.trim()) return;
794
799
  store.addUserMessage(text);
@@ -799,7 +804,7 @@ function useCanvasStream(options = {}) {
799
804
  const stream = transport.stream({
800
805
  threadId: threadIdRef.current,
801
806
  message: text,
802
- selections: withSelections,
807
+ selections: withSelections2,
803
808
  signal: controller.signal
804
809
  });
805
810
  for await (const event of stream) {
@@ -2256,10 +2261,10 @@ function HtmlRenderer({ artifact: artifact2 }) {
2256
2261
 
2257
2262
  // src/components/renderers/index.ts
2258
2263
  var ChartRenderer = lazy(() => import('./ChartRenderer-TBTWNPV7.js').then((m) => ({ default: m.ChartRenderer })));
2259
- var DocumentRenderer = lazy(() => import('./DocumentRenderer-ER5TSNA6.js').then((m) => ({ default: m.DocumentRenderer })));
2264
+ var DocumentRenderer = lazy(() => import('./DocumentRenderer-ZGJXDVKG.js').then((m) => ({ default: m.DocumentRenderer })));
2260
2265
  var TableRenderer = lazy(() => import('./TableRenderer-YTOF2ZIC.js').then((m) => ({ default: m.TableRenderer })));
2261
- var SlidesRenderer = lazy(() => import('./SlidesRenderer-AHE5ANBZ.js').then((m) => ({ default: m.SlidesRenderer })));
2262
- var FileRenderer = lazy(() => import('./FileRenderer-W2CR7BI2.js').then((m) => ({ default: m.FileRenderer })));
2266
+ var SlidesRenderer = lazy(() => import('./SlidesRenderer-4QWZVWWD.js').then((m) => ({ default: m.SlidesRenderer })));
2267
+ var FileRenderer = lazy(() => import('./FileRenderer-TZSZVVLY.js').then((m) => ({ default: m.FileRenderer })));
2263
2268
  var builtinRenderers = {
2264
2269
  html: HtmlRenderer,
2265
2270
  document: DocumentRenderer,
@@ -1,4 +1,5 @@
1
- import { C as CanvasTransport, E as ElementSelection, S as StreamEvent } from '../types-CzJ4zeUR.js';
1
+ import { C as CanvasTransport, S as StreamEvent } from '../types-CKgpjs_G.js';
2
+ export { w as withSelections } from '../types-CKgpjs_G.js';
2
3
 
3
4
  /**
4
5
  * `langgraphTransport` — speak to a LangGraph server without a translator
@@ -24,8 +25,6 @@ interface LangGraphTransportOptions {
24
25
  /** Extra headers (e.g. auth) passed to the SDK client. */
25
26
  headers?: Record<string, string>;
26
27
  }
27
- /** Frame a targeted edit so the agent changes only the selected element(s). */
28
- declare function withSelections(message: string, selections: ElementSelection[]): string;
29
28
  /**
30
29
  * LangGraph requires UUID thread ids; the canvas allows any string. Non-UUID
31
30
  * ids map deterministically (RFC 4122 v5 over `canvas-thread:<id>`), matching
@@ -65,4 +64,4 @@ declare function translateLangGraphStream(chunks: AsyncIterable<LangGraphStreamC
65
64
  messageId?: string;
66
65
  }): AsyncGenerator<StreamEvent>;
67
66
 
68
- export { type LangGraphStreamChunk, type LangGraphTransportOptions, chunkText, langgraphTransport, threadUuid, translateLangGraphStream, withSelections };
67
+ export { type LangGraphStreamChunk, type LangGraphTransportOptions, chunkText, langgraphTransport, threadUuid, translateLangGraphStream };
@@ -1,7 +1,7 @@
1
+ import { withSelections } from '../chunk-ASMMPDYS.js';
2
+ export { withSelections } from '../chunk-ASMMPDYS.js';
1
3
  import { Client } from '@langchain/langgraph-sdk';
2
4
 
3
- // src/langgraph/transport.ts
4
-
5
5
  // src/langgraph/translate.ts
6
6
  function chunkText(content) {
7
7
  if (typeof content === "string") return content;
@@ -60,16 +60,6 @@ async function* translateLangGraphStream(chunks, options = {}) {
60
60
  }
61
61
 
62
62
  // src/langgraph/transport.ts
63
- function withSelections(message, selections) {
64
- if (selections.length === 0) return message;
65
- const listed = selections.map((s) => `- \`${s.selector}\` (data-cid=${s.cid})`).join("\n");
66
- const artifactId = selections[0].artifactId;
67
- return `${message}
68
-
69
- [Targeted edit] Apply the change to these selected element(s) in file \`${artifactId}\`:
70
- ${listed}
71
- First call read_canvas on the file to get its current content and revision, then call edit_canvas with the element's exact current outer HTML as \`old\` and your replacement as \`new\` (keep the data-cid attribute).`;
72
- }
73
63
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
74
64
  var NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
75
65
  async function threadUuid(threadId) {
@@ -108,4 +98,4 @@ function langgraphTransport(options) {
108
98
  };
109
99
  }
110
100
 
111
- export { chunkText, langgraphTransport, threadUuid, translateLangGraphStream, withSelections };
101
+ export { chunkText, langgraphTransport, threadUuid, translateLangGraphStream };
package/dist/styles.css CHANGED
@@ -1309,6 +1309,7 @@
1309
1309
  }
1310
1310
  .cv-docx__picked { color: var(--cv-accent); }
1311
1311
  .cv-docx__fonts { color: var(--cv-warn, #b45309); }
1312
+ .cv-docx__redrawn { color: var(--cv-warn, #b45309); }
1312
1313
 
1313
1314
  /* Tablet / narrow desktop: tighten paddings, let toolbars wrap. */
1314
1315
  @media (max-width: 900px) {
@@ -292,6 +292,33 @@ interface ElementSelection {
292
292
  /** True when the element is a group wrapper (offers "Ungroup"). */
293
293
  isGroup?: boolean;
294
294
  }
295
+ /**
296
+ * File suffixes whose selections address a document, not a DOM element.
297
+ *
298
+ * The twin of `DOCUMENT_OP_SUFFIXES` in `langchain_canvas.document_ops`; the
299
+ * protocol parity test compares the two, so a format the tools learn to edit
300
+ * cannot quietly keep the wrong framing here.
301
+ */
302
+ declare const DOCUMENT_FILE_SUFFIXES: readonly [".docx"];
303
+ /** True when this selection points into a document file rather than a page. */
304
+ declare function isDocumentSelection(selection: ElementSelection): boolean;
305
+ /**
306
+ * Frame a targeted edit so the agent changes only what the user pointed at.
307
+ *
308
+ * The two kinds of canvas artifact are addressed in different languages and
309
+ * have different tools, so one framing cannot serve both. A document is
310
+ * addressed by position for *reading* only — `[p12]` moves the moment a
311
+ * paragraph is inserted — so the instruction hands over the words at that place
312
+ * and says to use them as the anchor. A page is edited by matching its markup,
313
+ * so the instruction hands over the element's markup as the *file* has it.
314
+ *
315
+ * Both halves are about naming something the agent can actually find. The
316
+ * screen's own pointing attributes (`data-cid` and friends) are stripped before
317
+ * the source is stored, so an instruction that names one sends the agent
318
+ * looking through the file for something that was never written there — and a
319
+ * careful agent then refuses the edit rather than guessing.
320
+ */
321
+ declare function withSelections(message: string, selections: ElementSelection[]): string;
295
322
 
296
323
  /**
297
324
  * `CanvasTransport` — the socket between the canvas UI and an agent backend.
@@ -325,4 +352,4 @@ interface CanvasTransport {
325
352
  stream(request: TransportRequest): AsyncIterable<StreamEvent>;
326
353
  }
327
354
 
328
- export { type Artifact as A, type TableColumn as B, type CanvasTransport as C, type DocumentData as D, type ElementSelection as E, type FileData as F, type ToolEnd as G, type HtmlData as H, type ToolStart as I, type TransportRequest as J, type KnownArtifact as K, isCanvasEvent as L, type MessageDelta as M, isChatEvent as N, type StreamEvent as S, type TableData as T, type CanvasEvent as a, type SlidesData as b, type ChartData as c, type ArtifactStatus as d, type CanvasAppend as e, type CanvasCommit as f, type CanvasCreate as g, type CanvasNodePatch as h, type CanvasPatch as i, type CanvasReplace as j, type CanvasStatus as k, type ChartArtifact as l, type ChartOptions as m, type ChartSeries as n, type ChatEvent as o, type DocumentArtifact as p, type DoneEvent as q, type ErrorEvent as r, type FileArtifact as s, type HtmlArtifact as t, type MessageEnd as u, type Slide as v, type SlideElement as w, type SlidePage as x, type SlidesArtifact as y, type TableArtifact as z };
355
+ export { type Artifact as A, type SlidesArtifact as B, type CanvasTransport as C, type DocumentData as D, type ElementSelection as E, type FileData as F, type TableArtifact as G, type HtmlData as H, type TableColumn as I, type ToolEnd as J, type KnownArtifact as K, type ToolStart as L, type MessageDelta as M, type TransportRequest as N, isCanvasEvent as O, isChatEvent as P, isDocumentSelection as Q, type StreamEvent as S, type TableData as T, type CanvasEvent as a, type SlidesData as b, type ChartData as c, type ArtifactStatus as d, type CanvasAppend as e, type CanvasCommit as f, type CanvasCreate as g, type CanvasNodePatch as h, type CanvasPatch as i, type CanvasReplace as j, type CanvasStatus as k, type ChartArtifact as l, type ChartOptions as m, type ChartSeries as n, type ChatEvent as o, DOCUMENT_FILE_SUFFIXES as p, type DocumentArtifact as q, type DoneEvent as r, type ErrorEvent as s, type FileArtifact as t, type HtmlArtifact as u, type MessageEnd as v, withSelections as w, type Slide as x, type SlideElement as y, type SlidePage as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@braincrew-lab/langchain-canvas",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "A live canvas for LangChain agents — stream documents, charts, and rich artifacts into a React panel.",
5
5
  "license": "MIT",
6
6
  "author": "Brain Crew (https://github.com/braincrew-lab)",