@bendyline/squisq-editor-react 2.11.0 → 2.11.1

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.
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  markdownToTiptap,
8
8
  tiptapToMarkdown
9
- } from "./chunk-TCLNRATG.js";
9
+ } from "./chunk-A2W4GYPG.js";
10
10
  import {
11
11
  ImageEditor,
12
12
  ImageViewer,
@@ -395,6 +395,7 @@ function EditorProvider({
395
395
  proofingIgnoreStore = null,
396
396
  documentLinkProvider = null,
397
397
  fenceRenderers = null,
398
+ onCopyCode,
398
399
  linkSchemes,
399
400
  allowRecording = true,
400
401
  allowNarrate = true,
@@ -892,6 +893,7 @@ function EditorProvider({
892
893
  articleId,
893
894
  documentLinkProvider,
894
895
  fenceRenderers,
896
+ onCopyCode,
895
897
  linkSchemes,
896
898
  fileName,
897
899
  saveCoverImageOutput,
@@ -962,6 +964,7 @@ function EditorProvider({
962
964
  articleId,
963
965
  documentLinkProvider,
964
966
  fenceRenderers,
967
+ onCopyCode,
965
968
  linkSchemes,
966
969
  fileName,
967
970
  saveCoverImageOutput,
@@ -5327,6 +5330,10 @@ function collectTextblockRuns(doc) {
5327
5330
  let text = "";
5328
5331
  node2.descendants((child, offset) => {
5329
5332
  if (child.isText && child.text) {
5333
+ if (child.marks.some((mark) => mark.type.name === "code")) {
5334
+ text += " ".repeat(child.text.length);
5335
+ return true;
5336
+ }
5330
5337
  const from = text.length;
5331
5338
  text += child.text;
5332
5339
  spans.push({ from, to: text.length, docFrom: pos + 1 + offset });
@@ -5603,7 +5610,9 @@ function useProofing() {
5603
5610
  if (!editor || !model2) return;
5604
5611
  const versionId = model2.getVersionId();
5605
5612
  const source = model2.getValue();
5606
- const { text: blankedText, blanked } = blankProtectedSpans(source);
5613
+ const { text: blankedText, blanked } = blankProtectedSpans(source, {
5614
+ markdownCode: true
5615
+ });
5607
5616
  const results = await provider.lint(blankedText, { language: "markdown" });
5608
5617
  if (passId !== passIdRef.current) return;
5609
5618
  if (monacoRef.current !== editor || editor.getModel() !== model2) return;
@@ -11413,25 +11422,182 @@ var SPECIAL_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
11413
11422
  "timeline",
11414
11423
  "mermaid"
11415
11424
  ]);
11416
- var MONACO_LANGUAGE_ALIASES2 = {
11417
- c: "c",
11418
- "c++": "cpp",
11419
- "c#": "csharp",
11425
+ var FENCE_LANGUAGE_ALIASES = {
11426
+ cc: "cpp",
11427
+ cjs: "javascript",
11428
+ console: "bash",
11429
+ containerfile: "dockerfile",
11420
11430
  cs: "csharp",
11431
+ cts: "typescript",
11432
+ "c#": "csharp",
11433
+ "c++": "cpp",
11421
11434
  cxx: "cpp",
11422
11435
  docker: "dockerfile",
11436
+ golang: "go",
11437
+ hh: "cpp",
11438
+ hpp: "cpp",
11423
11439
  htm: "html",
11424
11440
  js: "javascript",
11425
- jsx: "javascript",
11426
- jsonc: "json",
11441
+ ksh: "bash",
11442
+ kt: "kotlin",
11443
+ kts: "kotlin",
11427
11444
  md: "markdown",
11445
+ mjs: "javascript",
11446
+ mts: "typescript",
11428
11447
  py: "python",
11448
+ python3: "python",
11429
11449
  rb: "ruby",
11430
- sh: "shell",
11431
- shell: "shell",
11450
+ rs: "rust",
11451
+ sh: "bash",
11452
+ shell: "bash",
11432
11453
  ts: "typescript",
11433
- tsx: "typescript",
11434
- yml: "yaml"
11454
+ yml: "yaml",
11455
+ zsh: "bash"
11456
+ };
11457
+ var EXTRA_LANGUAGE_LABELS = {
11458
+ apache: "Apache",
11459
+ asm: "Assembly",
11460
+ assembly: "Assembly",
11461
+ astro: "Astro",
11462
+ bat: "Batch",
11463
+ batch: "Batch",
11464
+ c: "C",
11465
+ clj: "Clojure",
11466
+ cljs: "ClojureScript",
11467
+ clojure: "Clojure",
11468
+ cmake: "CMake",
11469
+ cmd: "Batch",
11470
+ cobol: "COBOL",
11471
+ crystal: "Crystal",
11472
+ csv: "CSV",
11473
+ dart: "Dart",
11474
+ diff: "Diff",
11475
+ dot: "Graphviz",
11476
+ elisp: "Emacs Lisp",
11477
+ elixir: "Elixir",
11478
+ erl: "Erlang",
11479
+ erlang: "Erlang",
11480
+ ex: "Elixir",
11481
+ exs: "Elixir",
11482
+ fish: "Fish",
11483
+ fortran: "Fortran",
11484
+ fs: "F#",
11485
+ fsharp: "F#",
11486
+ "f#": "F#",
11487
+ gql: "GraphQL",
11488
+ gradle: "Gradle",
11489
+ graphql: "GraphQL",
11490
+ graphviz: "Graphviz",
11491
+ groovy: "Groovy",
11492
+ h: "C",
11493
+ handlebars: "Handlebars",
11494
+ haskell: "Haskell",
11495
+ hbs: "Handlebars",
11496
+ hcl: "HCL",
11497
+ hs: "Haskell",
11498
+ http: "HTTP",
11499
+ ini: "INI",
11500
+ jade: "Pug",
11501
+ jl: "Julia",
11502
+ jsonl: "JSON Lines",
11503
+ julia: "Julia",
11504
+ kql: "Kusto",
11505
+ kusto: "Kusto",
11506
+ latex: "LaTeX",
11507
+ less: "Less",
11508
+ lisp: "Lisp",
11509
+ lua: "Lua",
11510
+ make: "Makefile",
11511
+ makefile: "Makefile",
11512
+ matlab: "MATLAB",
11513
+ mysql: "MySQL",
11514
+ ndjson: "JSON Lines",
11515
+ nginx: "nginx",
11516
+ nim: "Nim",
11517
+ objc: "Objective-C",
11518
+ "objective-c": "Objective-C",
11519
+ objectivec: "Objective-C",
11520
+ ocaml: "OCaml",
11521
+ pascal: "Pascal",
11522
+ patch: "Diff",
11523
+ perl: "Perl",
11524
+ pgsql: "PostgreSQL",
11525
+ pl: "Perl",
11526
+ plsql: "PL/SQL",
11527
+ postgres: "PostgreSQL",
11528
+ postgresql: "PostgreSQL",
11529
+ powershell: "PowerShell",
11530
+ prisma: "Prisma",
11531
+ prolog: "Prolog",
11532
+ proto: "Protocol Buffers",
11533
+ protobuf: "Protocol Buffers",
11534
+ ps1: "PowerShell",
11535
+ psql: "PostgreSQL",
11536
+ pug: "Pug",
11537
+ pwsh: "PowerShell",
11538
+ r: "R",
11539
+ racket: "Racket",
11540
+ razor: "Razor",
11541
+ regex: "Regex",
11542
+ sass: "Sass",
11543
+ scala: "Scala",
11544
+ scheme: "Scheme",
11545
+ scss: "SCSS",
11546
+ sol: "Solidity",
11547
+ solidity: "Solidity",
11548
+ sqlite: "SQLite",
11549
+ stylus: "Stylus",
11550
+ svelte: "Svelte",
11551
+ svg: "SVG",
11552
+ tex: "LaTeX",
11553
+ terraform: "Terraform",
11554
+ tf: "Terraform",
11555
+ toml: "TOML",
11556
+ tsql: "T-SQL",
11557
+ tsv: "TSV",
11558
+ vb: "Visual Basic",
11559
+ vbnet: "Visual Basic",
11560
+ verilog: "Verilog",
11561
+ vhdl: "VHDL",
11562
+ "visual-basic": "Visual Basic",
11563
+ vue: "Vue",
11564
+ wasm: "WebAssembly",
11565
+ wat: "WebAssembly",
11566
+ xml: "XML",
11567
+ zig: "Zig"
11568
+ };
11569
+ var MONACO_LANGUAGE_ALIASES2 = {
11570
+ batch: "bat",
11571
+ c: "c",
11572
+ clj: "clojure",
11573
+ cljs: "clojure",
11574
+ cmd: "bat",
11575
+ ex: "elixir",
11576
+ exs: "elixir",
11577
+ fs: "fsharp",
11578
+ "f#": "fsharp",
11579
+ gql: "graphql",
11580
+ hbs: "handlebars",
11581
+ jade: "pug",
11582
+ jl: "julia",
11583
+ jsonl: "json",
11584
+ jsx: "javascript",
11585
+ ndjson: "json",
11586
+ objc: "objective-c",
11587
+ objectivec: "objective-c",
11588
+ pl: "perl",
11589
+ postgres: "pgsql",
11590
+ postgresql: "pgsql",
11591
+ proto: "protobuf",
11592
+ ps1: "powershell",
11593
+ psql: "pgsql",
11594
+ pwsh: "powershell",
11595
+ sol: "solidity",
11596
+ svg: "xml",
11597
+ terraform: "hcl",
11598
+ tf: "hcl",
11599
+ vbnet: "vb",
11600
+ "visual-basic": "vb"
11435
11601
  };
11436
11602
  function codeSnippetFenceLanguageToken(language) {
11437
11603
  if (typeof language !== "string") return "";
@@ -11441,16 +11607,25 @@ function isCodeSnippetFenceLanguage(language) {
11441
11607
  const token = codeSnippetFenceLanguageToken(language);
11442
11608
  return token.length > 0 && !SPECIAL_FENCE_LANGUAGES.has(token);
11443
11609
  }
11610
+ function catalogEntryForToken(token) {
11611
+ const direct = BY_FENCE_LANGUAGE.get(token);
11612
+ if (direct) return direct;
11613
+ const canonical = FENCE_LANGUAGE_ALIASES[token];
11614
+ return canonical ? BY_FENCE_LANGUAGE.get(canonical) : void 0;
11615
+ }
11444
11616
  function monacoLanguageForFence(language) {
11445
11617
  const token = codeSnippetFenceLanguageToken(language);
11446
- const catalogEntry = BY_FENCE_LANGUAGE.get(token);
11618
+ const catalogEntry = catalogEntryForToken(token);
11447
11619
  return (catalogEntry?.monacoLanguage ?? MONACO_LANGUAGE_ALIASES2[token] ?? token) || "plaintext";
11448
11620
  }
11449
11621
  function codeSnippetLanguageLabel(language) {
11450
11622
  const token = codeSnippetFenceLanguageToken(language);
11451
- const catalogEntry = BY_FENCE_LANGUAGE.get(token);
11623
+ const catalogEntry = catalogEntryForToken(token);
11452
11624
  if (catalogEntry) return catalogEntry.label;
11453
- return token ? token.replace(/(^|[-_])([a-z])/g, (_match, _prefix, letter) => letter.toUpperCase()) : "Code";
11625
+ const friendlyName = EXTRA_LANGUAGE_LABELS[token];
11626
+ if (friendlyName) return friendlyName;
11627
+ if (!token) return "Code";
11628
+ return token.split(/[-_.]+/).filter((word) => word.length > 0).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
11454
11629
  }
11455
11630
  function codeSnippetMarkdown(language, source) {
11456
11631
  return `
@@ -12772,6 +12947,14 @@ function anchorOffsets(anchor, w, h2) {
12772
12947
  // src/scene/SceneViewport.tsx
12773
12948
  import { forwardRef, useId as useId7 } from "react";
12774
12949
  import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
12950
+ var BASE_GRID_STEP = 24;
12951
+ var MIN_SCREEN_STEP = 18;
12952
+ var MAX_DOT_RADIUS = 2;
12953
+ function dotGrid(scale) {
12954
+ let step = BASE_GRID_STEP * (Number.isFinite(scale) && scale > 0 ? scale : 1);
12955
+ for (let i = 0; i < 8 && step < MIN_SCREEN_STEP; i++) step *= 2;
12956
+ return { step, radius: Math.min(MAX_DOT_RADIUS, step / BASE_GRID_STEP) };
12957
+ }
12775
12958
  var SceneViewport = forwardRef(function SceneViewport2({
12776
12959
  width,
12777
12960
  height,
@@ -12789,6 +12972,7 @@ var SceneViewport = forwardRef(function SceneViewport2({
12789
12972
  }, ref) {
12790
12973
  const t = transform;
12791
12974
  const gridId = `squisq-scene-dot-grid-${useId7().replace(/:/g, "")}`;
12975
+ const grid = dotGrid(t.scale);
12792
12976
  const groupTransform = `translate(${t.tx} ${t.ty}) scale(${t.scale})`;
12793
12977
  return /* @__PURE__ */ jsxs20(
12794
12978
  "svg",
@@ -12815,10 +12999,10 @@ var SceneViewport = forwardRef(function SceneViewport2({
12815
12999
  id: gridId,
12816
13000
  x: t.tx,
12817
13001
  y: t.ty,
12818
- width: 24 * t.scale,
12819
- height: 24 * t.scale,
13002
+ width: grid.step,
13003
+ height: grid.step,
12820
13004
  patternUnits: "userSpaceOnUse",
12821
- children: /* @__PURE__ */ jsx25("circle", { cx: 1, cy: 1, r: 1, className: "squisq-scene-dot" })
13005
+ children: /* @__PURE__ */ jsx25("circle", { cx: grid.radius, cy: grid.radius, r: grid.radius, className: "squisq-scene-dot" })
12822
13006
  }
12823
13007
  ) }),
12824
13008
  /* @__PURE__ */ jsx25("rect", { width: "100%", height: "100%", fill: `url(#${gridId})` }),
@@ -21013,6 +21197,7 @@ import {
21013
21197
  useState as useState36
21014
21198
  } from "react";
21015
21199
  import { createPortal as createPortal11 } from "react-dom";
21200
+ import { CellSelection } from "@tiptap/pm/tables";
21016
21201
  import { jsx as jsx46, jsxs as jsxs36 } from "react/jsx-runtime";
21017
21202
  var EditorContextMenuRegistry = createContext6(null);
21018
21203
  var ownsContextMenuProps = { "data-editor-context-menu": "own" };
@@ -21088,6 +21273,88 @@ function shouldShowItem(item, context) {
21088
21273
  function resolveDisabled(item, context) {
21089
21274
  return typeof item.disabled === "function" ? item.disabled(context) : Boolean(item.disabled);
21090
21275
  }
21276
+ function tableActionScope(editor, context) {
21277
+ if (context.view !== "wysiwyg" || !editor?.view.dom.contains(context.target)) return null;
21278
+ const cell = context.target.closest("td, th");
21279
+ if (!cell || !editor.view.dom.contains(cell)) return null;
21280
+ const { selection } = editor.state;
21281
+ if (!(selection instanceof CellSelection)) return { row: true, column: true };
21282
+ const selectsRows = selection.isRowSelection();
21283
+ const selectsColumns = selection.isColSelection();
21284
+ return {
21285
+ row: selectsRows || !selectsColumns,
21286
+ column: selectsColumns || !selectsRows
21287
+ };
21288
+ }
21289
+ function tableMenuItems(editor, context) {
21290
+ const scope = tableActionScope(editor, context);
21291
+ if (!scope || !editor) return [];
21292
+ const disabled = !context.editable;
21293
+ const items = [];
21294
+ if (scope.row) {
21295
+ items.push(
21296
+ {
21297
+ id: "squisq.table.insert-row-above",
21298
+ label: "Insert row above",
21299
+ group: "table-row",
21300
+ disabled,
21301
+ onSelect: () => {
21302
+ editor.chain().focus().addRowBefore().run();
21303
+ }
21304
+ },
21305
+ {
21306
+ id: "squisq.table.insert-row-below",
21307
+ label: "Insert row below",
21308
+ group: "table-row",
21309
+ disabled,
21310
+ onSelect: () => {
21311
+ editor.chain().focus().addRowAfter().run();
21312
+ }
21313
+ },
21314
+ {
21315
+ id: "squisq.table.delete-row",
21316
+ label: "Delete this row",
21317
+ group: "table-row",
21318
+ disabled,
21319
+ onSelect: () => {
21320
+ editor.chain().focus().deleteRow().run();
21321
+ }
21322
+ }
21323
+ );
21324
+ }
21325
+ if (scope.column) {
21326
+ items.push(
21327
+ {
21328
+ id: "squisq.table.insert-column-left",
21329
+ label: "Insert column to the left",
21330
+ group: "table-column",
21331
+ disabled,
21332
+ onSelect: () => {
21333
+ editor.chain().focus().addColumnBefore().run();
21334
+ }
21335
+ },
21336
+ {
21337
+ id: "squisq.table.insert-column-right",
21338
+ label: "Insert column to the right",
21339
+ group: "table-column",
21340
+ disabled,
21341
+ onSelect: () => {
21342
+ editor.chain().focus().addColumnAfter().run();
21343
+ }
21344
+ },
21345
+ {
21346
+ id: "squisq.table.delete-column",
21347
+ label: "Delete column",
21348
+ group: "table-column",
21349
+ disabled,
21350
+ onSelect: () => {
21351
+ editor.chain().focus().deleteColumn().run();
21352
+ }
21353
+ }
21354
+ );
21355
+ }
21356
+ return items;
21357
+ }
21091
21358
  function shortcutModifier() {
21092
21359
  return /Mac|iPhone|iPad/.test(navigator.platform) ? "\u2318" : "Ctrl+";
21093
21360
  }
@@ -21260,15 +21527,16 @@ function EditorContextMenuProvider({
21260
21527
  onSelect: interaction.paste
21261
21528
  }
21262
21529
  ];
21530
+ const tableItems = tableMenuItems(tiptapEditor, context);
21263
21531
  const hostItems = Array.from(itemGettersRef.current).flatMap((getItems) => getItems());
21264
- const items = [...baseItems, ...hostItems].filter((item) => shouldShowItem(item, context)).map((item) => ({ item, disabled: resolveDisabled(item, context) }));
21532
+ const items = [...baseItems, ...tableItems, ...hostItems].filter((item) => shouldShowItem(item, context)).map((item) => ({ item, disabled: resolveDisabled(item, context) }));
21265
21533
  if (!items.some((item) => !item.disabled)) return false;
21266
21534
  const nextMenu = { context, items, x: clientX, y: clientY, error: null };
21267
21535
  setMenuStyle(computeMenuStyle(nextMenu));
21268
21536
  setMenu(nextMenu);
21269
21537
  return true;
21270
21538
  },
21271
- [buildInteraction]
21539
+ [buildInteraction, tiptapEditor]
21272
21540
  );
21273
21541
  useEffect28(() => {
21274
21542
  const root = rootRef.current;
@@ -27414,7 +27682,7 @@ import { createElement as createElement10 } from "react";
27414
27682
  import { createRoot as createRoot4 } from "react-dom/client";
27415
27683
 
27416
27684
  // src/codeSnippet/CodeSnippetWidget.tsx
27417
- import { useCallback as useCallback37, useEffect as useEffect37, useState as useState47 } from "react";
27685
+ import { useCallback as useCallback37, useEffect as useEffect37, useRef as useRef39, useState as useState47 } from "react";
27418
27686
 
27419
27687
  // src/codeSnippet/codeSnippetData.ts
27420
27688
  import { useEffect as useEffect36, useMemo as useMemo34, useState as useState46 } from "react";
@@ -27485,6 +27753,26 @@ function useHostColorScheme(host) {
27485
27753
  }, [host]);
27486
27754
  return scheme;
27487
27755
  }
27756
+ var COPY_LABELS = {
27757
+ idle: "Copy",
27758
+ copied: "Copied",
27759
+ failed: "Copy failed"
27760
+ };
27761
+ var COPY_ICONS = {
27762
+ idle: "fa-regular fa-copy",
27763
+ copied: "fa-solid fa-check",
27764
+ failed: "fa-solid fa-triangle-exclamation"
27765
+ };
27766
+ async function writeSnippetToClipboard(source, language, handler) {
27767
+ if (handler) {
27768
+ await handler(source, language ? { language } : {});
27769
+ return;
27770
+ }
27771
+ if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
27772
+ throw new Error("Clipboard access is unavailable in this host");
27773
+ }
27774
+ await navigator.clipboard.writeText(source);
27775
+ }
27488
27776
  function useEditorEditable(editor) {
27489
27777
  const [editable, setEditable] = useState47(editor.isEditable);
27490
27778
  useEffect37(() => {
@@ -27502,13 +27790,36 @@ function CodeSnippetWidget({
27502
27790
  editor,
27503
27791
  blockId,
27504
27792
  host,
27505
- focusOnMount = false
27793
+ focusOnMount = false,
27794
+ onCopyCode
27506
27795
  }) {
27507
27796
  const data = useCodeSnippetData(editor, blockId);
27508
27797
  const { ready } = useMonacoLoader(data?.monacoLanguage);
27509
27798
  const colorScheme = useHostColorScheme(host);
27510
27799
  const editable = useEditorEditable(editor);
27511
27800
  const [modelInstanceId] = useState47(allocateCodeSnippetModelInstanceId);
27801
+ const [copyStatus, setCopyStatus] = useState47("idle");
27802
+ const copyResetTimer = useRef39();
27803
+ const sourceRef = useRef39("");
27804
+ sourceRef.current = data?.source ?? "";
27805
+ const languageRef = useRef39("");
27806
+ languageRef.current = data?.fenceLanguage ?? "";
27807
+ useEffect37(
27808
+ () => () => {
27809
+ if (copyResetTimer.current !== void 0) clearTimeout(copyResetTimer.current);
27810
+ },
27811
+ []
27812
+ );
27813
+ const handleCopy = useCallback37(async () => {
27814
+ try {
27815
+ await writeSnippetToClipboard(sourceRef.current, languageRef.current, onCopyCode?.());
27816
+ setCopyStatus("copied");
27817
+ } catch {
27818
+ setCopyStatus("failed");
27819
+ }
27820
+ if (copyResetTimer.current !== void 0) clearTimeout(copyResetTimer.current);
27821
+ copyResetTimer.current = setTimeout(() => setCopyStatus("idle"), 1600);
27822
+ }, [onCopyCode]);
27512
27823
  const handleChange = useCallback37(
27513
27824
  (value) => {
27514
27825
  if (!editable) return;
@@ -27534,10 +27845,28 @@ function CodeSnippetWidget({
27534
27845
  "data-language": data.fenceLanguage,
27535
27846
  style: { height: codeSnippetAutoHeight(data.source) },
27536
27847
  children: [
27537
- /* @__PURE__ */ jsx53("div", { className: "squisq-code-snippet-header", children: /* @__PURE__ */ jsxs42("span", { className: "squisq-code-snippet-title", children: [
27538
- /* @__PURE__ */ jsx53(Icon, { icon: "fa-solid fa-file-code" }),
27539
- /* @__PURE__ */ jsx53("span", { children: data.label })
27540
- ] }) }),
27848
+ /* @__PURE__ */ jsxs42("div", { className: "squisq-code-snippet-header", children: [
27849
+ /* @__PURE__ */ jsxs42("span", { className: "squisq-code-snippet-title", children: [
27850
+ /* @__PURE__ */ jsx53(Icon, { icon: "fa-solid fa-file-code" }),
27851
+ /* @__PURE__ */ jsx53("span", { children: data.label })
27852
+ ] }),
27853
+ /* @__PURE__ */ jsxs42(
27854
+ "button",
27855
+ {
27856
+ type: "button",
27857
+ className: "squisq-code-snippet-copy",
27858
+ "data-copy-state": copyStatus,
27859
+ onClick: () => void handleCopy(),
27860
+ onMouseDown: (event) => event.preventDefault(),
27861
+ title: COPY_LABELS[copyStatus],
27862
+ "aria-label": "Copy " + data.label + " snippet to clipboard",
27863
+ children: [
27864
+ /* @__PURE__ */ jsx53(Icon, { icon: COPY_ICONS[copyStatus] }),
27865
+ /* @__PURE__ */ jsx53("span", { children: COPY_LABELS[copyStatus] })
27866
+ ]
27867
+ }
27868
+ )
27869
+ ] }),
27541
27870
  /* @__PURE__ */ jsx53("div", { className: "squisq-code-snippet-editor", "aria-label": `${data.label} code editor`, children: ready && colorScheme !== null ? /* @__PURE__ */ jsx53(
27542
27871
  Ft,
27543
27872
  {
@@ -27581,7 +27910,7 @@ function findCodeSnippetBlockPos(editor, blockId) {
27581
27910
  const state = CODE_SNIPPET_KEY.getState(editor.state);
27582
27911
  return state?.entries.find((entry) => entry.id === blockId)?.pos ?? null;
27583
27912
  }
27584
- function buildDecorations5(doc, entries, editor, focusBlockId = null, reserved) {
27913
+ function buildDecorations5(doc, entries, editor, focusBlockId = null, reserved, onCopyCode) {
27585
27914
  const decorations = [];
27586
27915
  for (const entry of entries) {
27587
27916
  const node2 = doc.nodeAt(entry.pos);
@@ -27607,7 +27936,8 @@ function buildDecorations5(doc, entries, editor, focusBlockId = null, reserved)
27607
27936
  editor,
27608
27937
  blockId,
27609
27938
  host: view.dom.parentElement ?? view.dom,
27610
- focusOnMount: entry.id === focusBlockId
27939
+ focusOnMount: entry.id === focusBlockId,
27940
+ onCopyCode
27611
27941
  })
27612
27942
  );
27613
27943
  container.__squisqCodeSnippetRoot = { root };
@@ -27656,7 +27986,7 @@ function remapEntries2(tr, previous, doc, reserved) {
27656
27986
  });
27657
27987
  return { entries, seq };
27658
27988
  }
27659
- function applyState4(tr, previous, editor, doc, reserved) {
27989
+ function applyState4(tr, previous, editor, doc, reserved, onCopyCode) {
27660
27990
  if (!tr.docChanged) return previous;
27661
27991
  const { entries, seq } = remapEntries2(tr, previous, doc, reserved);
27662
27992
  const requestedFocusPos = tr.getMeta(CODE_SNIPPET_FOCUS_INSERTED_META);
@@ -27665,7 +27995,7 @@ function applyState4(tr, previous, editor, doc, reserved) {
27665
27995
  entries,
27666
27996
  seq,
27667
27997
  focusBlockId,
27668
- decorations: buildDecorations5(doc, entries, editor, focusBlockId, reserved)
27998
+ decorations: buildDecorations5(doc, entries, editor, focusBlockId, reserved, onCopyCode)
27669
27999
  };
27670
28000
  }
27671
28001
  var CodeSnippetExtension = Extension7.create({
@@ -27677,6 +28007,7 @@ var CodeSnippetExtension = Extension7.create({
27677
28007
  if (this.options.enabled === false) return [];
27678
28008
  const editor = this.editor;
27679
28009
  const reserved = this.options.reservedLanguages && this.options.reservedLanguages.length > 0 ? new Set(this.options.reservedLanguages.map((lang) => codeSnippetFenceLanguageToken(lang))) : void 0;
28010
+ const onCopyCode = this.options.onCopyCode;
27680
28011
  return [
27681
28012
  new Plugin7({
27682
28013
  key: CODE_SNIPPET_KEY,
@@ -27694,10 +28025,10 @@ var CodeSnippetExtension = Extension7.create({
27694
28025
  entries,
27695
28026
  seq,
27696
28027
  focusBlockId: null,
27697
- decorations: buildDecorations5(state.doc, entries, editor, null, reserved)
28028
+ decorations: buildDecorations5(state.doc, entries, editor, null, reserved, onCopyCode)
27698
28029
  };
27699
28030
  },
27700
- apply: (tr, previous, _oldState, newState) => applyState4(tr, previous, editor, newState.doc, reserved)
28031
+ apply: (tr, previous, _oldState, newState) => applyState4(tr, previous, editor, newState.doc, reserved, onCopyCode)
27701
28032
  },
27702
28033
  props: {
27703
28034
  decorations(state) {
@@ -28557,7 +28888,7 @@ async function createXlsxFormulaSession(meta, options = {}) {
28557
28888
  }
28558
28889
 
28559
28890
  // src/dataCard/DataCardWidget.tsx
28560
- import { useCallback as useCallback38, useEffect as useEffect39, useMemo as useMemo36, useRef as useRef39, useState as useState49 } from "react";
28891
+ import { useCallback as useCallback38, useEffect as useEffect39, useMemo as useMemo36, useRef as useRef40, useState as useState49 } from "react";
28561
28892
  import { EMPTY_TABLE_VIEW_STATE } from "@bendyline/squisq/table";
28562
28893
 
28563
28894
  // src/dataCard/DataCardExtension.ts
@@ -28749,7 +29080,7 @@ function DataCardWidget({
28749
29080
  const [saving, setSaving] = useState49(false);
28750
29081
  const [saveNotice, setSaveNotice] = useState49(null);
28751
29082
  const [formulaDirty, setFormulaDirty] = useState49(0);
28752
- const gridRef = useRef39(null);
29083
+ const gridRef = useRef40(null);
28753
29084
  const href = link?.href ?? null;
28754
29085
  const cardPos = link?.pos ?? null;
28755
29086
  useEffect39(() => {
@@ -29012,7 +29343,7 @@ import {
29012
29343
  } from "@bendyline/squisq/doc";
29013
29344
 
29014
29345
  // src/treeview/TreeOutlineWidget.tsx
29015
- import { useCallback as useCallback39, useRef as useRef40, useState as useState50 } from "react";
29346
+ import { useCallback as useCallback39, useRef as useRef41, useState as useState50 } from "react";
29016
29347
 
29017
29348
  // src/treeview/treeViewCommands.ts
29018
29349
  import { parseTree, renderTree } from "@bendyline/squisq/doc";
@@ -29250,7 +29581,7 @@ function dropPositionForPointer(event) {
29250
29581
  function TreeOutlineWidget({ editor, blockId }) {
29251
29582
  const view = useTreeViewData(editor, blockId);
29252
29583
  const [collapsed, setCollapsed] = useState50(() => /* @__PURE__ */ new Set());
29253
- const activeDragRef = useRef40(null);
29584
+ const activeDragRef = useRef41(null);
29254
29585
  const [draggedId, setDraggedId] = useState50(null);
29255
29586
  const [dropTarget, setDropTarget] = useState50(null);
29256
29587
  const dispatch = useCallback39(
@@ -29730,7 +30061,7 @@ function shouldPasteAsTreeFence(text) {
29730
30061
  }
29731
30062
 
29732
30063
  // src/timeline/timelineData.ts
29733
- import { useEffect as useEffect42, useMemo as useMemo39, useRef as useRef42, useState as useState53 } from "react";
30064
+ import { useEffect as useEffect42, useMemo as useMemo39, useRef as useRef43, useState as useState53 } from "react";
29734
30065
 
29735
30066
  // src/timeline/TimelineViewExtension.ts
29736
30067
  import { Extension as Extension12 } from "@tiptap/core";
@@ -29745,7 +30076,7 @@ import {
29745
30076
  } from "@bendyline/squisq/doc";
29746
30077
 
29747
30078
  // src/timeline/TimelineEditorWidget.tsx
29748
- import { useCallback as useCallback40, useEffect as useEffect41, useMemo as useMemo38, useRef as useRef41, useState as useState52 } from "react";
30079
+ import { useCallback as useCallback40, useEffect as useEffect41, useMemo as useMemo38, useRef as useRef42, useState as useState52 } from "react";
29749
30080
  import {
29750
30081
  asciiTimelineToTemplateData
29751
30082
  } from "@bendyline/squisq/doc";
@@ -30234,7 +30565,7 @@ function TimelineEditorWidget({ editor, blockId }) {
30234
30565
  const [editingTrackId, setEditingTrackId] = useState52(null);
30235
30566
  const [hover, setHover] = useState52(null);
30236
30567
  const [dragged, setDragged] = useState52(null);
30237
- const suppressClickEventId = useRef41(null);
30568
+ const suppressClickEventId = useRef42(null);
30238
30569
  const [announcement, setAnnouncement] = useState52("");
30239
30570
  const dispatch = useCallback40(
30240
30571
  (command) => {
@@ -31085,7 +31416,7 @@ var TimelineViewExtension = Extension12.create({
31085
31416
  // src/timeline/timelineData.ts
31086
31417
  function useTimelineData(editor, blockId) {
31087
31418
  const [version, setVersion] = useState53(0);
31088
- const dataCache = useRef42(null);
31419
+ const dataCache = useRef43(null);
31089
31420
  useEffect42(() => {
31090
31421
  const onEditorChange = () => setVersion((value) => value + 1);
31091
31422
  editor.on("transaction", onEditorChange);
@@ -31121,7 +31452,7 @@ function shouldPasteAsTimelineFence(text) {
31121
31452
  }
31122
31453
 
31123
31454
  // src/BlockPropertiesPopover.tsx
31124
- import { useEffect as useEffect43, useId as useId13, useRef as useRef43, useState as useState54 } from "react";
31455
+ import { useEffect as useEffect43, useId as useId13, useRef as useRef44, useState as useState54 } from "react";
31125
31456
  import { createPortal as createPortal12 } from "react-dom";
31126
31457
  import { jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
31127
31458
  var TRANSITION_FLYOUT = ".squisq-transition-flyout";
@@ -31135,7 +31466,7 @@ function BlockPropertiesPopover({
31135
31466
  accentColor,
31136
31467
  onClose
31137
31468
  }) {
31138
- const panelRef = useRef43(null);
31469
+ const panelRef = useRef44(null);
31139
31470
  const panelId = `squisq-block-props-portal-${useId13().replace(/:/g, "")}`;
31140
31471
  const [inner, setInner] = useState54(blockAttrs);
31141
31472
  const [templateInner, setTemplateInner] = useState54(templateParams);
@@ -31305,7 +31636,7 @@ function persistFromWrite(bodyMd, state) {
31305
31636
  }
31306
31637
 
31307
31638
  // src/WysiwygEditor.tsx
31308
- import { useCallback as useCallback41, useEffect as useEffect47, useMemo as useMemo40, useRef as useRef45, useState as useState58 } from "react";
31639
+ import { useCallback as useCallback41, useEffect as useEffect47, useMemo as useMemo40, useRef as useRef46, useState as useState58 } from "react";
31309
31640
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
31310
31641
  import { Selection } from "@tiptap/pm/state";
31311
31642
  import StarterKit2 from "@tiptap/starter-kit";
@@ -31393,7 +31724,7 @@ var InlineIcon = Node2.create({
31393
31724
  });
31394
31725
 
31395
31726
  // src/ImageNodeView.tsx
31396
- import { useEffect as useEffect44, useRef as useRef44, useState as useState55 } from "react";
31727
+ import { useEffect as useEffect44, useRef as useRef45, useState as useState55 } from "react";
31397
31728
  import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
31398
31729
  import Image from "@tiptap/extension-image";
31399
31730
 
@@ -31415,7 +31746,7 @@ function ImageComponent({ node: node2, selected, editor, updateAttributes }) {
31415
31746
  const { mediaProvider, imageDisplayMode, openImageEdit, mediaRevision } = useEditorContext();
31416
31747
  const [resolvedSrc, setResolvedSrc] = useState55(src);
31417
31748
  const [hovered, setHovered] = useState55(false);
31418
- const imgRef = useRef44(null);
31749
+ const imgRef = useRef45(null);
31419
31750
  const [previewWidth, setPreviewWidth] = useState55(null);
31420
31751
  const isThumbnail = imageDisplayMode === "thumbnail";
31421
31752
  const isEditable = editor?.isEditable ?? true;
@@ -32322,6 +32653,7 @@ function WysiwygEditor({
32322
32653
  mediaProvider,
32323
32654
  mentionProvider,
32324
32655
  fenceRenderers,
32656
+ onCopyCode,
32325
32657
  blockTagVisibility,
32326
32658
  themeInheritance,
32327
32659
  colorScheme,
@@ -32334,10 +32666,10 @@ function WysiwygEditor({
32334
32666
  } = useEditorContext();
32335
32667
  const wrapPolicyEnabled = preserveSourceWrapping && layoutMode === "document";
32336
32668
  const previewSettings = usePreviewSettingsOptional();
32337
- const setEditorSourceRef = useRef45(setEditorSource);
32669
+ const setEditorSourceRef = useRef46(setEditorSource);
32338
32670
  setEditorSourceRef.current = setEditorSource;
32339
32671
  const activeTheme = previewSettings?.activeTheme;
32340
- const mermaidThemeStoreRef = useRef45(null);
32672
+ const mermaidThemeStoreRef = useRef46(null);
32341
32673
  if (mermaidThemeStoreRef.current === null) {
32342
32674
  mermaidThemeStoreRef.current = createMermaidThemeStore(activeTheme ?? DEFAULT_THEME4);
32343
32675
  }
@@ -32361,40 +32693,44 @@ function WysiwygEditor({
32361
32693
  },
32362
32694
  [docTemplates, onDocTemplatesChange]
32363
32695
  );
32364
- const mentionProviderRef = useRef45(mentionProvider);
32696
+ const mentionProviderRef = useRef46(mentionProvider);
32365
32697
  useEffect47(() => {
32366
32698
  mentionProviderRef.current = mentionProvider;
32367
32699
  }, [mentionProvider]);
32368
- const fenceRenderersRef = useRef45(fenceRenderers);
32700
+ const fenceRenderersRef = useRef46(fenceRenderers);
32369
32701
  useEffect47(() => {
32370
32702
  fenceRenderersRef.current = fenceRenderers;
32371
32703
  }, [fenceRenderers]);
32372
- const activeThemeRef = useRef45(activeTheme);
32704
+ const onCopyCodeRef = useRef46(onCopyCode);
32705
+ useEffect47(() => {
32706
+ onCopyCodeRef.current = onCopyCode;
32707
+ }, [onCopyCode]);
32708
+ const activeThemeRef = useRef46(activeTheme);
32373
32709
  useEffect47(() => {
32374
32710
  activeThemeRef.current = activeTheme;
32375
32711
  }, [activeTheme]);
32376
32712
  const resolvedPlaceholder = useMemo40(() => placeholder ?? pickEmptyPrompt(), [placeholder]);
32377
- const isExternalUpdate = useRef45(false);
32378
- const lastSourceRef = useRef45(editorSource);
32379
- const pendingLocalSourcesRef = useRef45([]);
32380
- const mediaProviderRef = useRef45(mediaProvider);
32381
- const mediaRevisionRef = useRef45(mediaRevision);
32713
+ const isExternalUpdate = useRef46(false);
32714
+ const lastSourceRef = useRef46(editorSource);
32715
+ const pendingLocalSourcesRef = useRef46([]);
32716
+ const mediaProviderRef = useRef46(mediaProvider);
32717
+ const mediaRevisionRef = useRef46(mediaRevision);
32382
32718
  useEffect47(() => {
32383
32719
  mediaRevisionRef.current = mediaRevision;
32384
32720
  }, [mediaRevision]);
32385
- const onOpenFilesPanelRef = useRef45(onOpenFilesPanel);
32721
+ const onOpenFilesPanelRef = useRef46(onOpenFilesPanel);
32386
32722
  useEffect47(() => {
32387
32723
  onOpenFilesPanelRef.current = onOpenFilesPanel;
32388
32724
  }, [onOpenFilesPanel]);
32389
- const calcEngineFactoryRef = useRef45(calcEngineFactory);
32725
+ const calcEngineFactoryRef = useRef46(calcEngineFactory);
32390
32726
  useEffect47(() => {
32391
32727
  calcEngineFactoryRef.current = calcEngineFactory;
32392
32728
  }, [calcEngineFactory]);
32393
- const workspaceContainerRef = useRef45(workspaceContainer);
32729
+ const workspaceContainerRef = useRef46(workspaceContainer);
32394
32730
  useEffect47(() => {
32395
32731
  workspaceContainerRef.current = workspaceContainer;
32396
32732
  }, [workspaceContainer]);
32397
- const bumpMediaRevisionRef = useRef45(bumpMediaRevision);
32733
+ const bumpMediaRevisionRef = useRef46(bumpMediaRevision);
32398
32734
  useEffect47(() => {
32399
32735
  bumpMediaRevisionRef.current = bumpMediaRevision;
32400
32736
  }, [bumpMediaRevision]);
@@ -32420,9 +32756,9 @@ function WysiwygEditor({
32420
32756
  cancelled = true;
32421
32757
  };
32422
32758
  }, [mediaProvider, mediaRevision]);
32423
- const frontmatterRef = useRef45(stripFrontmatter(editorSource).frontmatter);
32424
- const wrapStateRef = useRef45(null);
32425
- const initialDisplayBodyRef = useRef45(void 0);
32759
+ const frontmatterRef = useRef46(stripFrontmatter(editorSource).frontmatter);
32760
+ const wrapStateRef = useRef46(null);
32761
+ const initialDisplayBodyRef = useRef46(void 0);
32426
32762
  if (initialDisplayBodyRef.current === void 0) {
32427
32763
  const body = stripFrontmatter(editorSource).body;
32428
32764
  if (wrapPolicyEnabled) {
@@ -32433,7 +32769,7 @@ function WysiwygEditor({
32433
32769
  initialDisplayBodyRef.current = body;
32434
32770
  }
32435
32771
  }
32436
- const submitOnEnterRef = useRef45(submitOnEnter);
32772
+ const submitOnEnterRef = useRef46(submitOnEnter);
32437
32773
  useEffect47(() => {
32438
32774
  submitOnEnterRef.current = submitOnEnter;
32439
32775
  }, [submitOnEnter]);
@@ -32454,7 +32790,8 @@ function WysiwygEditor({
32454
32790
  AsciiDiagramExtension.configure({ textChannel: sceneTextChannel }),
32455
32791
  MermaidDiagramExtension.configure({ themeStore: mermaidThemeStore }),
32456
32792
  CodeSnippetExtension.configure({
32457
- reservedLanguages: fenceRendererLangs(fenceRenderers ?? void 0)
32793
+ reservedLanguages: fenceRendererLangs(fenceRenderers ?? void 0),
32794
+ onCopyCode: () => onCopyCodeRef.current
32458
32795
  }),
32459
32796
  HostFenceExtension.configure({
32460
32797
  renderers: () => fenceRenderersRef.current ?? void 0,
@@ -32653,7 +32990,7 @@ function WysiwygEditor({
32653
32990
  useEffect47(() => {
32654
32991
  if (editor) editor.setEditable(!readOnly);
32655
32992
  }, [editor, readOnly]);
32656
- const containerRef = useRef45(null);
32993
+ const containerRef = useRef46(null);
32657
32994
  const [badgeMenu, setBadgeMenu] = useState58(null);
32658
32995
  const [propsMenu, setPropsMenu] = useState58(null);
32659
32996
  const closeBadgeMenu = useCallback41(() => {
@@ -32975,7 +33312,7 @@ function moveSelectionToDropPoint(view, event) {
32975
33312
  }
32976
33313
 
32977
33314
  // src/InlinePreviewGutter.tsx
32978
- import { useLayoutEffect as useLayoutEffect9, useMemo as useMemo42, useRef as useRef46, useState as useState60 } from "react";
33315
+ import { useLayoutEffect as useLayoutEffect9, useMemo as useMemo42, useRef as useRef47, useState as useState60 } from "react";
32979
33316
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS5 } from "@bendyline/squisq/schemas";
32980
33317
  import {
32981
33318
  flattenBlocks as flattenBlocks4,
@@ -33351,7 +33688,7 @@ function InlinePreviewGutter({
33351
33688
  mediaProvider = null
33352
33689
  }) {
33353
33690
  const { doc } = useEditorContext();
33354
- const gutterRef = useRef46(null);
33691
+ const gutterRef = useRef47(null);
33355
33692
  const { entries: headingEntries, scrollToBlock } = useHeadingLayout(gutterRef);
33356
33693
  const previewSettings = usePreviewSettingsOptional();
33357
33694
  const activeTheme = previewSettings?.activeTheme ?? DEFAULT_THEME5;
@@ -33604,7 +33941,7 @@ import {
33604
33941
  useCallback as useCallback43,
33605
33942
  useEffect as useEffect49,
33606
33943
  useMemo as useMemo43,
33607
- useRef as useRef47,
33944
+ useRef as useRef48,
33608
33945
  useState as useState61
33609
33946
  } from "react";
33610
33947
  import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate2 } from "@bendyline/squisq/doc";
@@ -33724,18 +34061,18 @@ function OutlinePanel({ width, className, readOnly = false }) {
33724
34061
  monacoEditor,
33725
34062
  tiptapEditor
33726
34063
  } = useEditorContext();
33727
- const paneRef = useRef47(null);
34064
+ const paneRef = useRef48(null);
33728
34065
  const cursorActiveId = useActiveOutlineBlockId();
33729
- const activeDragRef = useRef47(null);
34066
+ const activeDragRef = useRef48(null);
33730
34067
  const [draggedBlockId, setDraggedBlockId] = useState61(null);
33731
34068
  const [dropTarget, setDropTarget] = useState61(null);
33732
34069
  const nextOutlineBlocks = doc?.blocks ?? EMPTY_BLOCKS;
33733
- const outlineBlocksRef = useRef47(nextOutlineBlocks);
34070
+ const outlineBlocksRef = useRef48(nextOutlineBlocks);
33734
34071
  if (!sameOutlineStructure(outlineBlocksRef.current, nextOutlineBlocks)) {
33735
34072
  outlineBlocksRef.current = nextOutlineBlocks;
33736
34073
  }
33737
34074
  const outlineBlocks = outlineBlocksRef.current;
33738
- const interactionRef = useRef47({
34075
+ const interactionRef = useRef48({
33739
34076
  doc,
33740
34077
  markdownSource,
33741
34078
  setMarkdownSource,
@@ -34058,7 +34395,7 @@ function OutlineNode({
34058
34395
  function useActiveOutlineBlockId() {
34059
34396
  const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
34060
34397
  const flatBlocks = useMemo43(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
34061
- const flatBlocksRef = useRef47(flatBlocks);
34398
+ const flatBlocksRef = useRef48(flatBlocks);
34062
34399
  flatBlocksRef.current = flatBlocks;
34063
34400
  const headingLocations = flatBlocks.map((block) => `${block.id}:${block.sourceHeading?.position?.start.line ?? ""}`).join("\0");
34064
34401
  const [activeId, setActiveId] = useState61(null);
@@ -34174,7 +34511,7 @@ function bumpHeadingLevelInSource(source, line, delta) {
34174
34511
  }
34175
34512
 
34176
34513
  // src/codeContext/CodeContextZones.tsx
34177
- import { useCallback as useCallback45, useEffect as useEffect51, useMemo as useMemo45, useRef as useRef49, useState as useState62 } from "react";
34514
+ import { useCallback as useCallback45, useEffect as useEffect51, useMemo as useMemo45, useRef as useRef50, useState as useState62 } from "react";
34178
34515
  import { createPortal as createPortal13 } from "react-dom";
34179
34516
 
34180
34517
  // src/codeContext/diffContextSections.ts
@@ -34298,7 +34635,7 @@ function setOrdinal(zone, ordinal) {
34298
34635
  // src/codeContext/CodeContextSectionView.tsx
34299
34636
  import { parseMarkdown as parseMarkdown8 } from "@bendyline/squisq/markdown";
34300
34637
  import { MarkdownRenderer } from "@bendyline/squisq-react";
34301
- import { useCallback as useCallback44, useEffect as useEffect50, useMemo as useMemo44, useRef as useRef48 } from "react";
34638
+ import { useCallback as useCallback44, useEffect as useEffect50, useMemo as useMemo44, useRef as useRef49 } from "react";
34302
34639
  import { jsx as jsx65, jsxs as jsxs52 } from "react/jsx-runtime";
34303
34640
  function CodeContextSectionView({
34304
34641
  section,
@@ -34309,7 +34646,7 @@ function CodeContextSectionView({
34309
34646
  onRevealLine,
34310
34647
  onMeasure
34311
34648
  }) {
34312
- const rootRef = useRef48(null);
34649
+ const rootRef = useRef49(null);
34313
34650
  const stripNodes = useMemo44(
34314
34651
  () => parseMarkdown8(section.summaryMarkdown).children,
34315
34652
  [section.summaryMarkdown]
@@ -34393,7 +34730,7 @@ function CodeContextZones({ options }) {
34393
34730
  const [manager, setManager] = useState62(null);
34394
34731
  const [, setZonesVersion] = useState62(0);
34395
34732
  const [expandedById, setExpandedById] = useState62({});
34396
- const seenIds = useRef49(/* @__PURE__ */ new Set());
34733
+ const seenIds = useRef50(/* @__PURE__ */ new Set());
34397
34734
  useEffect51(() => {
34398
34735
  if (!monacoEditor) return;
34399
34736
  const mgr = new CodeContextZoneManager(monacoEditor);
@@ -34853,7 +35190,7 @@ function placeClipInBlock(source, fromLine, targetHeadingLine, spec, startAt) {
34853
35190
  }
34854
35191
 
34855
35192
  // src/TimelineTrack.tsx
34856
- import { useCallback as useCallback47, useEffect as useEffect54, useMemo as useMemo46, useRef as useRef52, useState as useState65 } from "react";
35193
+ import { useCallback as useCallback47, useEffect as useEffect54, useMemo as useMemo46, useRef as useRef53, useState as useState65 } from "react";
34857
35194
  import {
34858
35195
  resolveMediaSchedule as resolveMediaSchedule2,
34859
35196
  getDocPlaybackDuration,
@@ -34978,7 +35315,7 @@ function collectTimelinePlaybackSchedule(doc, scheduled) {
34978
35315
  }
34979
35316
 
34980
35317
  // src/useTimelineClock.ts
34981
- import { useCallback as useCallback46, useEffect as useEffect52, useRef as useRef50, useState as useState63 } from "react";
35318
+ import { useCallback as useCallback46, useEffect as useEffect52, useRef as useRef51, useState as useState63 } from "react";
34982
35319
  function advanceTime(prev, dt, total) {
34983
35320
  if (total <= 0) return 0;
34984
35321
  return Math.min(total, Math.max(0, prev + dt));
@@ -35000,11 +35337,11 @@ function playTimelineMediaAt(root, time) {
35000
35337
  function useTimelineClock(total) {
35001
35338
  const [currentTime, setCurrentTime] = useState63(0);
35002
35339
  const [isPlaying, setIsPlaying] = useState63(false);
35003
- const rafRef = useRef50(null);
35004
- const lastRef = useRef50(0);
35005
- const currentTimeRef = useRef50(0);
35006
- const isPlayingRef = useRef50(false);
35007
- const mediaHostRef = useRef50(null);
35340
+ const rafRef = useRef51(null);
35341
+ const lastRef = useRef51(0);
35342
+ const currentTimeRef = useRef51(0);
35343
+ const isPlayingRef = useRef51(false);
35344
+ const mediaHostRef = useRef51(null);
35008
35345
  currentTimeRef.current = currentTime;
35009
35346
  isPlayingRef.current = isPlaying;
35010
35347
  useEffect52(() => {
@@ -35072,7 +35409,7 @@ function timelineMediaLabel(src, kind) {
35072
35409
  }
35073
35410
 
35074
35411
  // src/TimelineItemMenu.tsx
35075
- import { useEffect as useEffect53, useLayoutEffect as useLayoutEffect10, useRef as useRef51, useState as useState64 } from "react";
35412
+ import { useEffect as useEffect53, useLayoutEffect as useLayoutEffect10, useRef as useRef52, useState as useState64 } from "react";
35076
35413
  import { createPortal as createPortal14 } from "react-dom";
35077
35414
  import { Fragment as Fragment20, jsx as jsx68, jsxs as jsxs54 } from "react/jsx-runtime";
35078
35415
  function TimelineItemMenu({
@@ -35086,7 +35423,7 @@ function TimelineItemMenu({
35086
35423
  onVideoPatch,
35087
35424
  onClose
35088
35425
  }) {
35089
- const panelRef = useRef51(null);
35426
+ const panelRef = useRef52(null);
35090
35427
  const [style, setStyle] = useState64(() => menuStyle(anchor));
35091
35428
  useLayoutEffect10(() => {
35092
35429
  const panel = panelRef.current;
@@ -35515,7 +35852,7 @@ function TimelineTrack({
35515
35852
  const [drag, setDrag] = useState65(null);
35516
35853
  const [itemMenu, setItemMenu] = useState65(null);
35517
35854
  const [pxPerSecond, setPxPerSecond] = useState65(DEFAULT_PX_PER_SECOND);
35518
- const scrollRef = useRef52(null);
35855
+ const scrollRef = useRef53(null);
35519
35856
  const blocks = useMemo46(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
35520
35857
  const previewSettings = usePreviewSettingsOptional();
35521
35858
  const previewTheme = previewSettings?.activeTheme ?? DEFAULT_THEME6;
@@ -35585,7 +35922,7 @@ function TimelineTrack({
35585
35922
  },
35586
35923
  [blocks]
35587
35924
  );
35588
- const followedBlockRef = useRef52(null);
35925
+ const followedBlockRef = useRef53(null);
35589
35926
  useEffect54(() => {
35590
35927
  if (!isPlaying) {
35591
35928
  followedBlockRef.current = null;
@@ -35655,9 +35992,9 @@ function TimelineTrack({
35655
35992
  ro.observe(el);
35656
35993
  return () => ro.disconnect();
35657
35994
  }, []);
35658
- const scaleRef = useRef52(pxPerSecond);
35995
+ const scaleRef = useRef53(pxPerSecond);
35659
35996
  scaleRef.current = pxPerSecond;
35660
- const dragRef = useRef52(null);
35997
+ const dragRef = useRef53(null);
35661
35998
  dragRef.current = drag;
35662
35999
  const isDragging = drag != null && !drag.committed;
35663
36000
  useEffect54(() => {
@@ -36613,7 +36950,7 @@ function TimelineToolbar({
36613
36950
  }
36614
36951
 
36615
36952
  // src/PlainHtmlPreview.tsx
36616
- import { useCallback as useCallback48, useEffect as useEffect56, useMemo as useMemo49, useRef as useRef53, useState as useState67 } from "react";
36953
+ import { useCallback as useCallback48, useEffect as useEffect56, useMemo as useMemo49, useRef as useRef54, useState as useState67 } from "react";
36617
36954
  import { parseMarkdown as parseMarkdown9 } from "@bendyline/squisq/markdown";
36618
36955
 
36619
36956
  // src/utils/collectInlineFontAwesomeCss.ts
@@ -36683,9 +37020,9 @@ function PlainHtmlPreview({
36683
37020
  showCodeCopyButton = false,
36684
37021
  onCopyCode
36685
37022
  }) {
36686
- const iframeRef = useRef53(null);
36687
- const removeFrameLinkHandlerRef = useRef53(() => void 0);
36688
- const removeFrameCodeCopyControlsRef = useRef53(() => void 0);
37023
+ const iframeRef = useRef54(null);
37024
+ const removeFrameLinkHandlerRef = useRef54(() => void 0);
37025
+ const removeFrameCodeCopyControlsRef = useRef54(() => void 0);
36689
37026
  const setIframeRef = useCallback48(
36690
37027
  (frame) => {
36691
37028
  iframeRef.current = frame;
@@ -36944,7 +37281,7 @@ function collectImageRefs(doc) {
36944
37281
  }
36945
37282
 
36946
37283
  // src/PreviewPanel.tsx
36947
- import { useState as useState70, useEffect as useEffect60, useMemo as useMemo53, useCallback as useCallback52, useRef as useRef57 } from "react";
37284
+ import { useState as useState70, useEffect as useEffect60, useMemo as useMemo53, useCallback as useCallback52, useRef as useRef58 } from "react";
36948
37285
  import { createPortal as createPortal16 } from "react-dom";
36949
37286
  import {
36950
37287
  DashboardView,
@@ -37093,7 +37430,7 @@ import {
37093
37430
  useId as useId14,
37094
37431
  useLayoutEffect as useLayoutEffect11,
37095
37432
  useMemo as useMemo50,
37096
- useRef as useRef54,
37433
+ useRef as useRef55,
37097
37434
  useState as useState68
37098
37435
  } from "react";
37099
37436
  import { createPortal as createPortal15 } from "react-dom";
@@ -37201,12 +37538,12 @@ function PresentationModeProvider({
37201
37538
  const [popupRoot, setPopupRoot] = useState68(null);
37202
37539
  const [error, setError] = useState68(null);
37203
37540
  const [fullscreenExitStyle, setFullscreenExitStyle] = useState68(null);
37204
- const activeTargetRef = useRef54(activeTarget);
37541
+ const activeTargetRef = useRef55(activeTarget);
37205
37542
  activeTargetRef.current = activeTarget;
37206
- const previousActiveTargetRef = useRef54(null);
37207
- const returnFocusRef = useRef54(null);
37208
- const popupRef = useRef54(null);
37209
- const popupCleanupRef = useRef54(null);
37543
+ const previousActiveTargetRef = useRef55(null);
37544
+ const returnFocusRef = useRef55(null);
37545
+ const popupRef = useRef55(null);
37546
+ const popupCleanupRef = useRef55(null);
37210
37547
  const fullscreenSupported = typeof document !== "undefined" && typeof document.documentElement.requestFullscreen === "function";
37211
37548
  const availableTargets = useMemo50(
37212
37549
  () => [
@@ -37533,8 +37870,8 @@ function PresentationModeControl() {
37533
37870
  stop
37534
37871
  } = usePresentationMode();
37535
37872
  const { colorScheme } = useEditorContext();
37536
- const triggerRef = useRef54(null);
37537
- const menuRef = useRef54(null);
37873
+ const triggerRef = useRef55(null);
37874
+ const menuRef = useRef55(null);
37538
37875
  const [open, setOpen] = useState68(false);
37539
37876
  const [anchor, setAnchor] = useState68(null);
37540
37877
  const options = PRESENTATION_OPTIONS.filter((option) => availableTargets.includes(option.target));
@@ -37706,7 +38043,7 @@ import {
37706
38043
  useContext as useContext8,
37707
38044
  useEffect as useEffect58,
37708
38045
  useMemo as useMemo51,
37709
- useRef as useRef55,
38046
+ useRef as useRef56,
37710
38047
  useState as useState69
37711
38048
  } from "react";
37712
38049
  import { jsx as jsx75, jsxs as jsxs60 } from "react/jsx-runtime";
@@ -37724,8 +38061,8 @@ function PrintModeProvider({ rootRef, children }) {
37724
38061
  const { activeTarget: presentationTarget, stop: stopPresentation } = usePresentationMode();
37725
38062
  const [active, setActive] = useState69(false);
37726
38063
  const [slidesPerPage, setSlidesPerPage] = useState69(1);
37727
- const customPrintHandlerRef = useRef55(null);
37728
- const printAncestorsRef = useRef55([]);
38064
+ const customPrintHandlerRef = useRef56(null);
38065
+ const printAncestorsRef = useRef56([]);
37729
38066
  const unmarkPrinting = useCallback50(() => {
37730
38067
  const ownerDocument = rootRef.current?.ownerDocument;
37731
38068
  ownerDocument?.body.classList.remove("squisq-printing");
@@ -37877,7 +38214,7 @@ function PrintPreviewToolbar() {
37877
38214
  }
37878
38215
 
37879
38216
  // src/print/PrintPreview.tsx
37880
- import { useCallback as useCallback51, useEffect as useEffect59, useMemo as useMemo52, useRef as useRef56 } from "react";
38217
+ import { useCallback as useCallback51, useEffect as useEffect59, useMemo as useMemo52, useRef as useRef57 } from "react";
37881
38218
  import {
37882
38219
  BlockRenderer as BlockRenderer4,
37883
38220
  FlashcardFaceView,
@@ -37912,7 +38249,7 @@ function PrintPreview({
37912
38249
  }) {
37913
38250
  const { slidesPerPage, registerPrintHandler } = usePrintMode();
37914
38251
  const mediaProvider = useMediaProvider();
37915
- const documentFrameRef = useRef56(null);
38252
+ const documentFrameRef = useRef57(null);
37916
38253
  const setDocumentFrame = useCallback51((frame) => {
37917
38254
  documentFrameRef.current = frame;
37918
38255
  }, []);
@@ -38113,8 +38450,8 @@ function PreviewPanel({
38113
38450
  activeDashboardTitle,
38114
38451
  activeDashboardStyle
38115
38452
  } = usePreviewSettings();
38116
- const mainSurfaceRef = useRef57(null);
38117
- const popupSurfaceRef = useRef57(null);
38453
+ const mainSurfaceRef = useRef58(null);
38454
+ const popupSurfaceRef = useRef58(null);
38118
38455
  const [playbackState, setPlaybackState] = useState70(null);
38119
38456
  const handlePlaybackStateChange = useCallback52((next) => {
38120
38457
  setPlaybackState(next);
@@ -38424,7 +38761,7 @@ function PreviewPanel({
38424
38761
  }
38425
38762
 
38426
38763
  // src/MediaBin.tsx
38427
- import { useState as useState71, useEffect as useEffect61, useRef as useRef58, useCallback as useCallback53 } from "react";
38764
+ import { useState as useState71, useEffect as useEffect61, useRef as useRef59, useCallback as useCallback53 } from "react";
38428
38765
  import { jsx as jsx78, jsxs as jsxs63 } from "react/jsx-runtime";
38429
38766
  function formatSize(bytes) {
38430
38767
  if (bytes < 1024) return `${bytes} B`;
@@ -38494,7 +38831,7 @@ function MediaBin({
38494
38831
  highlightPath = null
38495
38832
  }) {
38496
38833
  const [entries, setEntries] = useState71([]);
38497
- const listRef = useRef58(null);
38834
+ const listRef = useRef59(null);
38498
38835
  useEffect61(() => {
38499
38836
  if (!highlightPath || !listRef.current) return;
38500
38837
  const item = listRef.current.querySelector(`[data-media-path="${CSS.escape(highlightPath)}"]`);
@@ -38507,9 +38844,9 @@ function MediaBin({
38507
38844
  const [isDropActive, setIsDropActive] = useState71(false);
38508
38845
  const [downloadingPath, setDownloadingPath] = useState71(null);
38509
38846
  const [contextMenu, setContextMenu] = useState71(null);
38510
- const fileInputRef = useRef58(null);
38511
- const contextMenuRef = useRef58(null);
38512
- const dropDepthRef = useRef58(0);
38847
+ const fileInputRef = useRef59(null);
38848
+ const contextMenuRef = useRef59(null);
38849
+ const dropDepthRef = useRef59(0);
38513
38850
  const updateEntries = useCallback53(
38514
38851
  async (provider) => {
38515
38852
  const list = sortMediaEntries(filterVisibleMediaEntries(await provider.listMedia()));
@@ -38994,7 +39331,7 @@ function DropZone({
38994
39331
  }
38995
39332
 
38996
39333
  // src/Tooltip.tsx
38997
- import { useEffect as useEffect62, useLayoutEffect as useLayoutEffect12, useRef as useRef59, useState as useState73 } from "react";
39334
+ import { useEffect as useEffect62, useLayoutEffect as useLayoutEffect12, useRef as useRef60, useState as useState73 } from "react";
38998
39335
  import { createPortal as createPortal17 } from "react-dom";
38999
39336
 
39000
39337
  // src/tooltipPlacement.ts
@@ -39011,10 +39348,10 @@ import { jsx as jsx80 } from "react/jsx-runtime";
39011
39348
  var SHOW_DELAY_MS = 180;
39012
39349
  function TooltipLayer() {
39013
39350
  const [state, setState3] = useState73(null);
39014
- const tooltipRef = useRef59(null);
39015
- const timerRef = useRef59(null);
39016
- const currentTargetRef = useRef59(null);
39017
- const visibleRef = useRef59(false);
39351
+ const tooltipRef = useRef60(null);
39352
+ const timerRef = useRef60(null);
39353
+ const currentTargetRef = useRef60(null);
39354
+ const visibleRef = useRef60(false);
39018
39355
  useLayoutEffect12(() => {
39019
39356
  if (!state) return;
39020
39357
  const node2 = tooltipRef.current;
@@ -39112,7 +39449,7 @@ function TooltipLayer() {
39112
39449
  }
39113
39450
 
39114
39451
  // src/EditorShell.tsx
39115
- import { useEffect as useEffect63, useRef as useRef60, useState as useState74, useCallback as useCallback54, useMemo as useMemo55 } from "react";
39452
+ import { useEffect as useEffect63, useRef as useRef61, useState as useState74, useCallback as useCallback54, useMemo as useMemo55 } from "react";
39116
39453
 
39117
39454
  // src/BlockPreviewPanel.tsx
39118
39455
  import { useMemo as useMemo54 } from "react";
@@ -39597,6 +39934,7 @@ function EditorShell({
39597
39934
  proofingIgnoreStore,
39598
39935
  documentLinkProvider,
39599
39936
  fenceRenderers,
39937
+ onCopyCode,
39600
39938
  linkSchemes,
39601
39939
  allowRecording,
39602
39940
  allowNarrate,
@@ -39740,7 +40078,7 @@ function EditorShellInner({
39740
40078
  outlineWidth,
39741
40079
  themeOverride
39742
40080
  }) {
39743
- const shellRef = useRef60(null);
40081
+ const shellRef = useRef61(null);
39744
40082
  const {
39745
40083
  activeView,
39746
40084
  markdownSource,
@@ -39823,7 +40161,7 @@ function EditorShellInner({
39823
40161
  () => collectMediaReferencesFromMarkdown(markdownSource),
39824
40162
  [markdownSource]
39825
40163
  );
39826
- const imageEditFallbackContainerRef = useRef60(null);
40164
+ const imageEditFallbackContainerRef = useRef61(null);
39827
40165
  if (imageEditFallbackContainerRef.current === null) {
39828
40166
  imageEditFallbackContainerRef.current = new MemoryContentContainer();
39829
40167
  }
@@ -39897,7 +40235,7 @@ ${snippet}` : snippet);
39897
40235
  },
39898
40236
  [activeView, tiptapEditor, monacoEditor, insertAtCursor, markdownSource, setMarkdownSource]
39899
40237
  );
39900
- const docBasenameRef = useRef60("document");
40238
+ const docBasenameRef = useRef61("document");
39901
40239
  useEffect63(() => {
39902
40240
  let cancelled = false;
39903
40241
  docBasenameRef.current = "document";
@@ -40377,8 +40715,8 @@ function ImageEditModal({
40377
40715
  versioningAutoSaveIdleMs,
40378
40716
  shellTheme
40379
40717
  }) {
40380
- const modalRef = useRef60(null);
40381
- const surfaceRef = useRef60(null);
40718
+ const modalRef = useRef61(null);
40719
+ const surfaceRef = useRef61(null);
40382
40720
  useModalDialog({ rootRef: modalRef, dialogRef: surfaceRef, onClose });
40383
40721
  const extension = relativePath.split(/[?#]/, 1)[0]?.split(".").pop()?.toLowerCase();
40384
40722
  const saveFormat = extension === "png" ? "png" : extension === "jpg" || extension === "jpeg" ? "jpeg" : extension === "webp" ? "webp" : null;