@bendyline/squisq-editor-react 2.11.0 → 2.11.2

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";
@@ -27448,10 +27716,9 @@ var CODE_SNIPPET_HEADER_HEIGHT = 34;
27448
27716
  var CODE_SNIPPET_LINE_HEIGHT = 20;
27449
27717
  var CODE_SNIPPET_VERTICAL_PADDING = 20;
27450
27718
  var CODE_SNIPPET_SHELL_BORDER = 2;
27451
- var CODE_SNIPPET_EXTRA_LINES = 1;
27452
27719
  function codeSnippetAutoHeight(source) {
27453
27720
  const sourceLineCount = source.split("\n").length;
27454
- return CODE_SNIPPET_SHELL_BORDER + CODE_SNIPPET_HEADER_HEIGHT + CODE_SNIPPET_VERTICAL_PADDING + (sourceLineCount + CODE_SNIPPET_EXTRA_LINES) * CODE_SNIPPET_LINE_HEIGHT;
27721
+ return CODE_SNIPPET_SHELL_BORDER + CODE_SNIPPET_HEADER_HEIGHT + CODE_SNIPPET_VERTICAL_PADDING + sourceLineCount * CODE_SNIPPET_LINE_HEIGHT;
27455
27722
  }
27456
27723
 
27457
27724
  // src/codeSnippet/CodeSnippetWidget.tsx
@@ -27485,6 +27752,26 @@ function useHostColorScheme(host) {
27485
27752
  }, [host]);
27486
27753
  return scheme;
27487
27754
  }
27755
+ var COPY_LABELS = {
27756
+ idle: "Copy",
27757
+ copied: "Copied",
27758
+ failed: "Copy failed"
27759
+ };
27760
+ var COPY_ICONS = {
27761
+ idle: "fa-regular fa-copy",
27762
+ copied: "fa-solid fa-check",
27763
+ failed: "fa-solid fa-triangle-exclamation"
27764
+ };
27765
+ async function writeSnippetToClipboard(source, language, handler) {
27766
+ if (handler) {
27767
+ await handler(source, language ? { language } : {});
27768
+ return;
27769
+ }
27770
+ if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
27771
+ throw new Error("Clipboard access is unavailable in this host");
27772
+ }
27773
+ await navigator.clipboard.writeText(source);
27774
+ }
27488
27775
  function useEditorEditable(editor) {
27489
27776
  const [editable, setEditable] = useState47(editor.isEditable);
27490
27777
  useEffect37(() => {
@@ -27502,13 +27789,36 @@ function CodeSnippetWidget({
27502
27789
  editor,
27503
27790
  blockId,
27504
27791
  host,
27505
- focusOnMount = false
27792
+ focusOnMount = false,
27793
+ onCopyCode
27506
27794
  }) {
27507
27795
  const data = useCodeSnippetData(editor, blockId);
27508
27796
  const { ready } = useMonacoLoader(data?.monacoLanguage);
27509
27797
  const colorScheme = useHostColorScheme(host);
27510
27798
  const editable = useEditorEditable(editor);
27511
27799
  const [modelInstanceId] = useState47(allocateCodeSnippetModelInstanceId);
27800
+ const [copyStatus, setCopyStatus] = useState47("idle");
27801
+ const copyResetTimer = useRef39();
27802
+ const sourceRef = useRef39("");
27803
+ sourceRef.current = data?.source ?? "";
27804
+ const languageRef = useRef39("");
27805
+ languageRef.current = data?.fenceLanguage ?? "";
27806
+ useEffect37(
27807
+ () => () => {
27808
+ if (copyResetTimer.current !== void 0) clearTimeout(copyResetTimer.current);
27809
+ },
27810
+ []
27811
+ );
27812
+ const handleCopy = useCallback37(async () => {
27813
+ try {
27814
+ await writeSnippetToClipboard(sourceRef.current, languageRef.current, onCopyCode?.());
27815
+ setCopyStatus("copied");
27816
+ } catch {
27817
+ setCopyStatus("failed");
27818
+ }
27819
+ if (copyResetTimer.current !== void 0) clearTimeout(copyResetTimer.current);
27820
+ copyResetTimer.current = setTimeout(() => setCopyStatus("idle"), 1600);
27821
+ }, [onCopyCode]);
27512
27822
  const handleChange = useCallback37(
27513
27823
  (value) => {
27514
27824
  if (!editable) return;
@@ -27534,10 +27844,28 @@ function CodeSnippetWidget({
27534
27844
  "data-language": data.fenceLanguage,
27535
27845
  style: { height: codeSnippetAutoHeight(data.source) },
27536
27846
  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
- ] }) }),
27847
+ /* @__PURE__ */ jsxs42("div", { className: "squisq-code-snippet-header", children: [
27848
+ /* @__PURE__ */ jsxs42("span", { className: "squisq-code-snippet-title", children: [
27849
+ /* @__PURE__ */ jsx53(Icon, { icon: "fa-solid fa-file-code" }),
27850
+ /* @__PURE__ */ jsx53("span", { children: data.label })
27851
+ ] }),
27852
+ /* @__PURE__ */ jsxs42(
27853
+ "button",
27854
+ {
27855
+ type: "button",
27856
+ className: "squisq-code-snippet-copy",
27857
+ "data-copy-state": copyStatus,
27858
+ onClick: () => void handleCopy(),
27859
+ onMouseDown: (event) => event.preventDefault(),
27860
+ title: COPY_LABELS[copyStatus],
27861
+ "aria-label": "Copy " + data.label + " snippet to clipboard",
27862
+ children: [
27863
+ /* @__PURE__ */ jsx53(Icon, { icon: COPY_ICONS[copyStatus] }),
27864
+ /* @__PURE__ */ jsx53("span", { children: COPY_LABELS[copyStatus] })
27865
+ ]
27866
+ }
27867
+ )
27868
+ ] }),
27541
27869
  /* @__PURE__ */ jsx53("div", { className: "squisq-code-snippet-editor", "aria-label": `${data.label} code editor`, children: ready && colorScheme !== null ? /* @__PURE__ */ jsx53(
27542
27870
  Ft,
27543
27871
  {
@@ -27581,7 +27909,7 @@ function findCodeSnippetBlockPos(editor, blockId) {
27581
27909
  const state = CODE_SNIPPET_KEY.getState(editor.state);
27582
27910
  return state?.entries.find((entry) => entry.id === blockId)?.pos ?? null;
27583
27911
  }
27584
- function buildDecorations5(doc, entries, editor, focusBlockId = null, reserved) {
27912
+ function buildDecorations5(doc, entries, editor, focusBlockId = null, reserved, onCopyCode) {
27585
27913
  const decorations = [];
27586
27914
  for (const entry of entries) {
27587
27915
  const node2 = doc.nodeAt(entry.pos);
@@ -27607,7 +27935,8 @@ function buildDecorations5(doc, entries, editor, focusBlockId = null, reserved)
27607
27935
  editor,
27608
27936
  blockId,
27609
27937
  host: view.dom.parentElement ?? view.dom,
27610
- focusOnMount: entry.id === focusBlockId
27938
+ focusOnMount: entry.id === focusBlockId,
27939
+ onCopyCode
27611
27940
  })
27612
27941
  );
27613
27942
  container.__squisqCodeSnippetRoot = { root };
@@ -27656,7 +27985,7 @@ function remapEntries2(tr, previous, doc, reserved) {
27656
27985
  });
27657
27986
  return { entries, seq };
27658
27987
  }
27659
- function applyState4(tr, previous, editor, doc, reserved) {
27988
+ function applyState4(tr, previous, editor, doc, reserved, onCopyCode) {
27660
27989
  if (!tr.docChanged) return previous;
27661
27990
  const { entries, seq } = remapEntries2(tr, previous, doc, reserved);
27662
27991
  const requestedFocusPos = tr.getMeta(CODE_SNIPPET_FOCUS_INSERTED_META);
@@ -27665,7 +27994,7 @@ function applyState4(tr, previous, editor, doc, reserved) {
27665
27994
  entries,
27666
27995
  seq,
27667
27996
  focusBlockId,
27668
- decorations: buildDecorations5(doc, entries, editor, focusBlockId, reserved)
27997
+ decorations: buildDecorations5(doc, entries, editor, focusBlockId, reserved, onCopyCode)
27669
27998
  };
27670
27999
  }
27671
28000
  var CodeSnippetExtension = Extension7.create({
@@ -27677,6 +28006,7 @@ var CodeSnippetExtension = Extension7.create({
27677
28006
  if (this.options.enabled === false) return [];
27678
28007
  const editor = this.editor;
27679
28008
  const reserved = this.options.reservedLanguages && this.options.reservedLanguages.length > 0 ? new Set(this.options.reservedLanguages.map((lang) => codeSnippetFenceLanguageToken(lang))) : void 0;
28009
+ const onCopyCode = this.options.onCopyCode;
27680
28010
  return [
27681
28011
  new Plugin7({
27682
28012
  key: CODE_SNIPPET_KEY,
@@ -27694,10 +28024,10 @@ var CodeSnippetExtension = Extension7.create({
27694
28024
  entries,
27695
28025
  seq,
27696
28026
  focusBlockId: null,
27697
- decorations: buildDecorations5(state.doc, entries, editor, null, reserved)
28027
+ decorations: buildDecorations5(state.doc, entries, editor, null, reserved, onCopyCode)
27698
28028
  };
27699
28029
  },
27700
- apply: (tr, previous, _oldState, newState) => applyState4(tr, previous, editor, newState.doc, reserved)
28030
+ apply: (tr, previous, _oldState, newState) => applyState4(tr, previous, editor, newState.doc, reserved, onCopyCode)
27701
28031
  },
27702
28032
  props: {
27703
28033
  decorations(state) {
@@ -28557,7 +28887,7 @@ async function createXlsxFormulaSession(meta, options = {}) {
28557
28887
  }
28558
28888
 
28559
28889
  // src/dataCard/DataCardWidget.tsx
28560
- import { useCallback as useCallback38, useEffect as useEffect39, useMemo as useMemo36, useRef as useRef39, useState as useState49 } from "react";
28890
+ import { useCallback as useCallback38, useEffect as useEffect39, useMemo as useMemo36, useRef as useRef40, useState as useState49 } from "react";
28561
28891
  import { EMPTY_TABLE_VIEW_STATE } from "@bendyline/squisq/table";
28562
28892
 
28563
28893
  // src/dataCard/DataCardExtension.ts
@@ -28749,7 +29079,7 @@ function DataCardWidget({
28749
29079
  const [saving, setSaving] = useState49(false);
28750
29080
  const [saveNotice, setSaveNotice] = useState49(null);
28751
29081
  const [formulaDirty, setFormulaDirty] = useState49(0);
28752
- const gridRef = useRef39(null);
29082
+ const gridRef = useRef40(null);
28753
29083
  const href = link?.href ?? null;
28754
29084
  const cardPos = link?.pos ?? null;
28755
29085
  useEffect39(() => {
@@ -29012,7 +29342,7 @@ import {
29012
29342
  } from "@bendyline/squisq/doc";
29013
29343
 
29014
29344
  // src/treeview/TreeOutlineWidget.tsx
29015
- import { useCallback as useCallback39, useRef as useRef40, useState as useState50 } from "react";
29345
+ import { useCallback as useCallback39, useRef as useRef41, useState as useState50 } from "react";
29016
29346
 
29017
29347
  // src/treeview/treeViewCommands.ts
29018
29348
  import { parseTree, renderTree } from "@bendyline/squisq/doc";
@@ -29250,7 +29580,7 @@ function dropPositionForPointer(event) {
29250
29580
  function TreeOutlineWidget({ editor, blockId }) {
29251
29581
  const view = useTreeViewData(editor, blockId);
29252
29582
  const [collapsed, setCollapsed] = useState50(() => /* @__PURE__ */ new Set());
29253
- const activeDragRef = useRef40(null);
29583
+ const activeDragRef = useRef41(null);
29254
29584
  const [draggedId, setDraggedId] = useState50(null);
29255
29585
  const [dropTarget, setDropTarget] = useState50(null);
29256
29586
  const dispatch = useCallback39(
@@ -29730,7 +30060,7 @@ function shouldPasteAsTreeFence(text) {
29730
30060
  }
29731
30061
 
29732
30062
  // src/timeline/timelineData.ts
29733
- import { useEffect as useEffect42, useMemo as useMemo39, useRef as useRef42, useState as useState53 } from "react";
30063
+ import { useEffect as useEffect42, useMemo as useMemo39, useRef as useRef43, useState as useState53 } from "react";
29734
30064
 
29735
30065
  // src/timeline/TimelineViewExtension.ts
29736
30066
  import { Extension as Extension12 } from "@tiptap/core";
@@ -29745,7 +30075,7 @@ import {
29745
30075
  } from "@bendyline/squisq/doc";
29746
30076
 
29747
30077
  // src/timeline/TimelineEditorWidget.tsx
29748
- import { useCallback as useCallback40, useEffect as useEffect41, useMemo as useMemo38, useRef as useRef41, useState as useState52 } from "react";
30078
+ import { useCallback as useCallback40, useEffect as useEffect41, useMemo as useMemo38, useRef as useRef42, useState as useState52 } from "react";
29749
30079
  import {
29750
30080
  asciiTimelineToTemplateData
29751
30081
  } from "@bendyline/squisq/doc";
@@ -30234,7 +30564,7 @@ function TimelineEditorWidget({ editor, blockId }) {
30234
30564
  const [editingTrackId, setEditingTrackId] = useState52(null);
30235
30565
  const [hover, setHover] = useState52(null);
30236
30566
  const [dragged, setDragged] = useState52(null);
30237
- const suppressClickEventId = useRef41(null);
30567
+ const suppressClickEventId = useRef42(null);
30238
30568
  const [announcement, setAnnouncement] = useState52("");
30239
30569
  const dispatch = useCallback40(
30240
30570
  (command) => {
@@ -31085,7 +31415,7 @@ var TimelineViewExtension = Extension12.create({
31085
31415
  // src/timeline/timelineData.ts
31086
31416
  function useTimelineData(editor, blockId) {
31087
31417
  const [version, setVersion] = useState53(0);
31088
- const dataCache = useRef42(null);
31418
+ const dataCache = useRef43(null);
31089
31419
  useEffect42(() => {
31090
31420
  const onEditorChange = () => setVersion((value) => value + 1);
31091
31421
  editor.on("transaction", onEditorChange);
@@ -31121,7 +31451,7 @@ function shouldPasteAsTimelineFence(text) {
31121
31451
  }
31122
31452
 
31123
31453
  // src/BlockPropertiesPopover.tsx
31124
- import { useEffect as useEffect43, useId as useId13, useRef as useRef43, useState as useState54 } from "react";
31454
+ import { useEffect as useEffect43, useId as useId13, useRef as useRef44, useState as useState54 } from "react";
31125
31455
  import { createPortal as createPortal12 } from "react-dom";
31126
31456
  import { jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
31127
31457
  var TRANSITION_FLYOUT = ".squisq-transition-flyout";
@@ -31135,7 +31465,7 @@ function BlockPropertiesPopover({
31135
31465
  accentColor,
31136
31466
  onClose
31137
31467
  }) {
31138
- const panelRef = useRef43(null);
31468
+ const panelRef = useRef44(null);
31139
31469
  const panelId = `squisq-block-props-portal-${useId13().replace(/:/g, "")}`;
31140
31470
  const [inner, setInner] = useState54(blockAttrs);
31141
31471
  const [templateInner, setTemplateInner] = useState54(templateParams);
@@ -31305,7 +31635,7 @@ function persistFromWrite(bodyMd, state) {
31305
31635
  }
31306
31636
 
31307
31637
  // src/WysiwygEditor.tsx
31308
- import { useCallback as useCallback41, useEffect as useEffect47, useMemo as useMemo40, useRef as useRef45, useState as useState58 } from "react";
31638
+ import { useCallback as useCallback41, useEffect as useEffect47, useMemo as useMemo40, useRef as useRef46, useState as useState58 } from "react";
31309
31639
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
31310
31640
  import { Selection } from "@tiptap/pm/state";
31311
31641
  import StarterKit2 from "@tiptap/starter-kit";
@@ -31393,7 +31723,7 @@ var InlineIcon = Node2.create({
31393
31723
  });
31394
31724
 
31395
31725
  // src/ImageNodeView.tsx
31396
- import { useEffect as useEffect44, useRef as useRef44, useState as useState55 } from "react";
31726
+ import { useEffect as useEffect44, useRef as useRef45, useState as useState55 } from "react";
31397
31727
  import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
31398
31728
  import Image from "@tiptap/extension-image";
31399
31729
 
@@ -31415,7 +31745,7 @@ function ImageComponent({ node: node2, selected, editor, updateAttributes }) {
31415
31745
  const { mediaProvider, imageDisplayMode, openImageEdit, mediaRevision } = useEditorContext();
31416
31746
  const [resolvedSrc, setResolvedSrc] = useState55(src);
31417
31747
  const [hovered, setHovered] = useState55(false);
31418
- const imgRef = useRef44(null);
31748
+ const imgRef = useRef45(null);
31419
31749
  const [previewWidth, setPreviewWidth] = useState55(null);
31420
31750
  const isThumbnail = imageDisplayMode === "thumbnail";
31421
31751
  const isEditable = editor?.isEditable ?? true;
@@ -32322,6 +32652,7 @@ function WysiwygEditor({
32322
32652
  mediaProvider,
32323
32653
  mentionProvider,
32324
32654
  fenceRenderers,
32655
+ onCopyCode,
32325
32656
  blockTagVisibility,
32326
32657
  themeInheritance,
32327
32658
  colorScheme,
@@ -32334,10 +32665,10 @@ function WysiwygEditor({
32334
32665
  } = useEditorContext();
32335
32666
  const wrapPolicyEnabled = preserveSourceWrapping && layoutMode === "document";
32336
32667
  const previewSettings = usePreviewSettingsOptional();
32337
- const setEditorSourceRef = useRef45(setEditorSource);
32668
+ const setEditorSourceRef = useRef46(setEditorSource);
32338
32669
  setEditorSourceRef.current = setEditorSource;
32339
32670
  const activeTheme = previewSettings?.activeTheme;
32340
- const mermaidThemeStoreRef = useRef45(null);
32671
+ const mermaidThemeStoreRef = useRef46(null);
32341
32672
  if (mermaidThemeStoreRef.current === null) {
32342
32673
  mermaidThemeStoreRef.current = createMermaidThemeStore(activeTheme ?? DEFAULT_THEME4);
32343
32674
  }
@@ -32361,40 +32692,44 @@ function WysiwygEditor({
32361
32692
  },
32362
32693
  [docTemplates, onDocTemplatesChange]
32363
32694
  );
32364
- const mentionProviderRef = useRef45(mentionProvider);
32695
+ const mentionProviderRef = useRef46(mentionProvider);
32365
32696
  useEffect47(() => {
32366
32697
  mentionProviderRef.current = mentionProvider;
32367
32698
  }, [mentionProvider]);
32368
- const fenceRenderersRef = useRef45(fenceRenderers);
32699
+ const fenceRenderersRef = useRef46(fenceRenderers);
32369
32700
  useEffect47(() => {
32370
32701
  fenceRenderersRef.current = fenceRenderers;
32371
32702
  }, [fenceRenderers]);
32372
- const activeThemeRef = useRef45(activeTheme);
32703
+ const onCopyCodeRef = useRef46(onCopyCode);
32704
+ useEffect47(() => {
32705
+ onCopyCodeRef.current = onCopyCode;
32706
+ }, [onCopyCode]);
32707
+ const activeThemeRef = useRef46(activeTheme);
32373
32708
  useEffect47(() => {
32374
32709
  activeThemeRef.current = activeTheme;
32375
32710
  }, [activeTheme]);
32376
32711
  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);
32712
+ const isExternalUpdate = useRef46(false);
32713
+ const lastSourceRef = useRef46(editorSource);
32714
+ const pendingLocalSourcesRef = useRef46([]);
32715
+ const mediaProviderRef = useRef46(mediaProvider);
32716
+ const mediaRevisionRef = useRef46(mediaRevision);
32382
32717
  useEffect47(() => {
32383
32718
  mediaRevisionRef.current = mediaRevision;
32384
32719
  }, [mediaRevision]);
32385
- const onOpenFilesPanelRef = useRef45(onOpenFilesPanel);
32720
+ const onOpenFilesPanelRef = useRef46(onOpenFilesPanel);
32386
32721
  useEffect47(() => {
32387
32722
  onOpenFilesPanelRef.current = onOpenFilesPanel;
32388
32723
  }, [onOpenFilesPanel]);
32389
- const calcEngineFactoryRef = useRef45(calcEngineFactory);
32724
+ const calcEngineFactoryRef = useRef46(calcEngineFactory);
32390
32725
  useEffect47(() => {
32391
32726
  calcEngineFactoryRef.current = calcEngineFactory;
32392
32727
  }, [calcEngineFactory]);
32393
- const workspaceContainerRef = useRef45(workspaceContainer);
32728
+ const workspaceContainerRef = useRef46(workspaceContainer);
32394
32729
  useEffect47(() => {
32395
32730
  workspaceContainerRef.current = workspaceContainer;
32396
32731
  }, [workspaceContainer]);
32397
- const bumpMediaRevisionRef = useRef45(bumpMediaRevision);
32732
+ const bumpMediaRevisionRef = useRef46(bumpMediaRevision);
32398
32733
  useEffect47(() => {
32399
32734
  bumpMediaRevisionRef.current = bumpMediaRevision;
32400
32735
  }, [bumpMediaRevision]);
@@ -32420,9 +32755,9 @@ function WysiwygEditor({
32420
32755
  cancelled = true;
32421
32756
  };
32422
32757
  }, [mediaProvider, mediaRevision]);
32423
- const frontmatterRef = useRef45(stripFrontmatter(editorSource).frontmatter);
32424
- const wrapStateRef = useRef45(null);
32425
- const initialDisplayBodyRef = useRef45(void 0);
32758
+ const frontmatterRef = useRef46(stripFrontmatter(editorSource).frontmatter);
32759
+ const wrapStateRef = useRef46(null);
32760
+ const initialDisplayBodyRef = useRef46(void 0);
32426
32761
  if (initialDisplayBodyRef.current === void 0) {
32427
32762
  const body = stripFrontmatter(editorSource).body;
32428
32763
  if (wrapPolicyEnabled) {
@@ -32433,7 +32768,7 @@ function WysiwygEditor({
32433
32768
  initialDisplayBodyRef.current = body;
32434
32769
  }
32435
32770
  }
32436
- const submitOnEnterRef = useRef45(submitOnEnter);
32771
+ const submitOnEnterRef = useRef46(submitOnEnter);
32437
32772
  useEffect47(() => {
32438
32773
  submitOnEnterRef.current = submitOnEnter;
32439
32774
  }, [submitOnEnter]);
@@ -32454,7 +32789,8 @@ function WysiwygEditor({
32454
32789
  AsciiDiagramExtension.configure({ textChannel: sceneTextChannel }),
32455
32790
  MermaidDiagramExtension.configure({ themeStore: mermaidThemeStore }),
32456
32791
  CodeSnippetExtension.configure({
32457
- reservedLanguages: fenceRendererLangs(fenceRenderers ?? void 0)
32792
+ reservedLanguages: fenceRendererLangs(fenceRenderers ?? void 0),
32793
+ onCopyCode: () => onCopyCodeRef.current
32458
32794
  }),
32459
32795
  HostFenceExtension.configure({
32460
32796
  renderers: () => fenceRenderersRef.current ?? void 0,
@@ -32653,7 +32989,7 @@ function WysiwygEditor({
32653
32989
  useEffect47(() => {
32654
32990
  if (editor) editor.setEditable(!readOnly);
32655
32991
  }, [editor, readOnly]);
32656
- const containerRef = useRef45(null);
32992
+ const containerRef = useRef46(null);
32657
32993
  const [badgeMenu, setBadgeMenu] = useState58(null);
32658
32994
  const [propsMenu, setPropsMenu] = useState58(null);
32659
32995
  const closeBadgeMenu = useCallback41(() => {
@@ -32975,7 +33311,7 @@ function moveSelectionToDropPoint(view, event) {
32975
33311
  }
32976
33312
 
32977
33313
  // src/InlinePreviewGutter.tsx
32978
- import { useLayoutEffect as useLayoutEffect9, useMemo as useMemo42, useRef as useRef46, useState as useState60 } from "react";
33314
+ import { useLayoutEffect as useLayoutEffect9, useMemo as useMemo42, useRef as useRef47, useState as useState60 } from "react";
32979
33315
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS5 } from "@bendyline/squisq/schemas";
32980
33316
  import {
32981
33317
  flattenBlocks as flattenBlocks4,
@@ -33351,7 +33687,7 @@ function InlinePreviewGutter({
33351
33687
  mediaProvider = null
33352
33688
  }) {
33353
33689
  const { doc } = useEditorContext();
33354
- const gutterRef = useRef46(null);
33690
+ const gutterRef = useRef47(null);
33355
33691
  const { entries: headingEntries, scrollToBlock } = useHeadingLayout(gutterRef);
33356
33692
  const previewSettings = usePreviewSettingsOptional();
33357
33693
  const activeTheme = previewSettings?.activeTheme ?? DEFAULT_THEME5;
@@ -33604,7 +33940,7 @@ import {
33604
33940
  useCallback as useCallback43,
33605
33941
  useEffect as useEffect49,
33606
33942
  useMemo as useMemo43,
33607
- useRef as useRef47,
33943
+ useRef as useRef48,
33608
33944
  useState as useState61
33609
33945
  } from "react";
33610
33946
  import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate2 } from "@bendyline/squisq/doc";
@@ -33724,18 +34060,18 @@ function OutlinePanel({ width, className, readOnly = false }) {
33724
34060
  monacoEditor,
33725
34061
  tiptapEditor
33726
34062
  } = useEditorContext();
33727
- const paneRef = useRef47(null);
34063
+ const paneRef = useRef48(null);
33728
34064
  const cursorActiveId = useActiveOutlineBlockId();
33729
- const activeDragRef = useRef47(null);
34065
+ const activeDragRef = useRef48(null);
33730
34066
  const [draggedBlockId, setDraggedBlockId] = useState61(null);
33731
34067
  const [dropTarget, setDropTarget] = useState61(null);
33732
34068
  const nextOutlineBlocks = doc?.blocks ?? EMPTY_BLOCKS;
33733
- const outlineBlocksRef = useRef47(nextOutlineBlocks);
34069
+ const outlineBlocksRef = useRef48(nextOutlineBlocks);
33734
34070
  if (!sameOutlineStructure(outlineBlocksRef.current, nextOutlineBlocks)) {
33735
34071
  outlineBlocksRef.current = nextOutlineBlocks;
33736
34072
  }
33737
34073
  const outlineBlocks = outlineBlocksRef.current;
33738
- const interactionRef = useRef47({
34074
+ const interactionRef = useRef48({
33739
34075
  doc,
33740
34076
  markdownSource,
33741
34077
  setMarkdownSource,
@@ -34058,7 +34394,7 @@ function OutlineNode({
34058
34394
  function useActiveOutlineBlockId() {
34059
34395
  const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
34060
34396
  const flatBlocks = useMemo43(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
34061
- const flatBlocksRef = useRef47(flatBlocks);
34397
+ const flatBlocksRef = useRef48(flatBlocks);
34062
34398
  flatBlocksRef.current = flatBlocks;
34063
34399
  const headingLocations = flatBlocks.map((block) => `${block.id}:${block.sourceHeading?.position?.start.line ?? ""}`).join("\0");
34064
34400
  const [activeId, setActiveId] = useState61(null);
@@ -34174,7 +34510,7 @@ function bumpHeadingLevelInSource(source, line, delta) {
34174
34510
  }
34175
34511
 
34176
34512
  // src/codeContext/CodeContextZones.tsx
34177
- import { useCallback as useCallback45, useEffect as useEffect51, useMemo as useMemo45, useRef as useRef49, useState as useState62 } from "react";
34513
+ import { useCallback as useCallback45, useEffect as useEffect51, useMemo as useMemo45, useRef as useRef50, useState as useState62 } from "react";
34178
34514
  import { createPortal as createPortal13 } from "react-dom";
34179
34515
 
34180
34516
  // src/codeContext/diffContextSections.ts
@@ -34298,7 +34634,7 @@ function setOrdinal(zone, ordinal) {
34298
34634
  // src/codeContext/CodeContextSectionView.tsx
34299
34635
  import { parseMarkdown as parseMarkdown8 } from "@bendyline/squisq/markdown";
34300
34636
  import { MarkdownRenderer } from "@bendyline/squisq-react";
34301
- import { useCallback as useCallback44, useEffect as useEffect50, useMemo as useMemo44, useRef as useRef48 } from "react";
34637
+ import { useCallback as useCallback44, useEffect as useEffect50, useMemo as useMemo44, useRef as useRef49 } from "react";
34302
34638
  import { jsx as jsx65, jsxs as jsxs52 } from "react/jsx-runtime";
34303
34639
  function CodeContextSectionView({
34304
34640
  section,
@@ -34309,7 +34645,7 @@ function CodeContextSectionView({
34309
34645
  onRevealLine,
34310
34646
  onMeasure
34311
34647
  }) {
34312
- const rootRef = useRef48(null);
34648
+ const rootRef = useRef49(null);
34313
34649
  const stripNodes = useMemo44(
34314
34650
  () => parseMarkdown8(section.summaryMarkdown).children,
34315
34651
  [section.summaryMarkdown]
@@ -34393,7 +34729,7 @@ function CodeContextZones({ options }) {
34393
34729
  const [manager, setManager] = useState62(null);
34394
34730
  const [, setZonesVersion] = useState62(0);
34395
34731
  const [expandedById, setExpandedById] = useState62({});
34396
- const seenIds = useRef49(/* @__PURE__ */ new Set());
34732
+ const seenIds = useRef50(/* @__PURE__ */ new Set());
34397
34733
  useEffect51(() => {
34398
34734
  if (!monacoEditor) return;
34399
34735
  const mgr = new CodeContextZoneManager(monacoEditor);
@@ -34853,7 +35189,7 @@ function placeClipInBlock(source, fromLine, targetHeadingLine, spec, startAt) {
34853
35189
  }
34854
35190
 
34855
35191
  // src/TimelineTrack.tsx
34856
- import { useCallback as useCallback47, useEffect as useEffect54, useMemo as useMemo46, useRef as useRef52, useState as useState65 } from "react";
35192
+ import { useCallback as useCallback47, useEffect as useEffect54, useMemo as useMemo46, useRef as useRef53, useState as useState65 } from "react";
34857
35193
  import {
34858
35194
  resolveMediaSchedule as resolveMediaSchedule2,
34859
35195
  getDocPlaybackDuration,
@@ -34978,7 +35314,7 @@ function collectTimelinePlaybackSchedule(doc, scheduled) {
34978
35314
  }
34979
35315
 
34980
35316
  // src/useTimelineClock.ts
34981
- import { useCallback as useCallback46, useEffect as useEffect52, useRef as useRef50, useState as useState63 } from "react";
35317
+ import { useCallback as useCallback46, useEffect as useEffect52, useRef as useRef51, useState as useState63 } from "react";
34982
35318
  function advanceTime(prev, dt, total) {
34983
35319
  if (total <= 0) return 0;
34984
35320
  return Math.min(total, Math.max(0, prev + dt));
@@ -35000,11 +35336,11 @@ function playTimelineMediaAt(root, time) {
35000
35336
  function useTimelineClock(total) {
35001
35337
  const [currentTime, setCurrentTime] = useState63(0);
35002
35338
  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);
35339
+ const rafRef = useRef51(null);
35340
+ const lastRef = useRef51(0);
35341
+ const currentTimeRef = useRef51(0);
35342
+ const isPlayingRef = useRef51(false);
35343
+ const mediaHostRef = useRef51(null);
35008
35344
  currentTimeRef.current = currentTime;
35009
35345
  isPlayingRef.current = isPlaying;
35010
35346
  useEffect52(() => {
@@ -35072,7 +35408,7 @@ function timelineMediaLabel(src, kind) {
35072
35408
  }
35073
35409
 
35074
35410
  // src/TimelineItemMenu.tsx
35075
- import { useEffect as useEffect53, useLayoutEffect as useLayoutEffect10, useRef as useRef51, useState as useState64 } from "react";
35411
+ import { useEffect as useEffect53, useLayoutEffect as useLayoutEffect10, useRef as useRef52, useState as useState64 } from "react";
35076
35412
  import { createPortal as createPortal14 } from "react-dom";
35077
35413
  import { Fragment as Fragment20, jsx as jsx68, jsxs as jsxs54 } from "react/jsx-runtime";
35078
35414
  function TimelineItemMenu({
@@ -35086,7 +35422,7 @@ function TimelineItemMenu({
35086
35422
  onVideoPatch,
35087
35423
  onClose
35088
35424
  }) {
35089
- const panelRef = useRef51(null);
35425
+ const panelRef = useRef52(null);
35090
35426
  const [style, setStyle] = useState64(() => menuStyle(anchor));
35091
35427
  useLayoutEffect10(() => {
35092
35428
  const panel = panelRef.current;
@@ -35515,7 +35851,7 @@ function TimelineTrack({
35515
35851
  const [drag, setDrag] = useState65(null);
35516
35852
  const [itemMenu, setItemMenu] = useState65(null);
35517
35853
  const [pxPerSecond, setPxPerSecond] = useState65(DEFAULT_PX_PER_SECOND);
35518
- const scrollRef = useRef52(null);
35854
+ const scrollRef = useRef53(null);
35519
35855
  const blocks = useMemo46(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
35520
35856
  const previewSettings = usePreviewSettingsOptional();
35521
35857
  const previewTheme = previewSettings?.activeTheme ?? DEFAULT_THEME6;
@@ -35585,7 +35921,7 @@ function TimelineTrack({
35585
35921
  },
35586
35922
  [blocks]
35587
35923
  );
35588
- const followedBlockRef = useRef52(null);
35924
+ const followedBlockRef = useRef53(null);
35589
35925
  useEffect54(() => {
35590
35926
  if (!isPlaying) {
35591
35927
  followedBlockRef.current = null;
@@ -35655,9 +35991,9 @@ function TimelineTrack({
35655
35991
  ro.observe(el);
35656
35992
  return () => ro.disconnect();
35657
35993
  }, []);
35658
- const scaleRef = useRef52(pxPerSecond);
35994
+ const scaleRef = useRef53(pxPerSecond);
35659
35995
  scaleRef.current = pxPerSecond;
35660
- const dragRef = useRef52(null);
35996
+ const dragRef = useRef53(null);
35661
35997
  dragRef.current = drag;
35662
35998
  const isDragging = drag != null && !drag.committed;
35663
35999
  useEffect54(() => {
@@ -36613,7 +36949,7 @@ function TimelineToolbar({
36613
36949
  }
36614
36950
 
36615
36951
  // src/PlainHtmlPreview.tsx
36616
- import { useCallback as useCallback48, useEffect as useEffect56, useMemo as useMemo49, useRef as useRef53, useState as useState67 } from "react";
36952
+ import { useCallback as useCallback48, useEffect as useEffect56, useMemo as useMemo49, useRef as useRef54, useState as useState67 } from "react";
36617
36953
  import { parseMarkdown as parseMarkdown9 } from "@bendyline/squisq/markdown";
36618
36954
 
36619
36955
  // src/utils/collectInlineFontAwesomeCss.ts
@@ -36683,9 +37019,9 @@ function PlainHtmlPreview({
36683
37019
  showCodeCopyButton = false,
36684
37020
  onCopyCode
36685
37021
  }) {
36686
- const iframeRef = useRef53(null);
36687
- const removeFrameLinkHandlerRef = useRef53(() => void 0);
36688
- const removeFrameCodeCopyControlsRef = useRef53(() => void 0);
37022
+ const iframeRef = useRef54(null);
37023
+ const removeFrameLinkHandlerRef = useRef54(() => void 0);
37024
+ const removeFrameCodeCopyControlsRef = useRef54(() => void 0);
36689
37025
  const setIframeRef = useCallback48(
36690
37026
  (frame) => {
36691
37027
  iframeRef.current = frame;
@@ -36944,7 +37280,7 @@ function collectImageRefs(doc) {
36944
37280
  }
36945
37281
 
36946
37282
  // src/PreviewPanel.tsx
36947
- import { useState as useState70, useEffect as useEffect60, useMemo as useMemo53, useCallback as useCallback52, useRef as useRef57 } from "react";
37283
+ import { useState as useState70, useEffect as useEffect60, useMemo as useMemo53, useCallback as useCallback52, useRef as useRef58 } from "react";
36948
37284
  import { createPortal as createPortal16 } from "react-dom";
36949
37285
  import {
36950
37286
  DashboardView,
@@ -37093,7 +37429,7 @@ import {
37093
37429
  useId as useId14,
37094
37430
  useLayoutEffect as useLayoutEffect11,
37095
37431
  useMemo as useMemo50,
37096
- useRef as useRef54,
37432
+ useRef as useRef55,
37097
37433
  useState as useState68
37098
37434
  } from "react";
37099
37435
  import { createPortal as createPortal15 } from "react-dom";
@@ -37201,12 +37537,12 @@ function PresentationModeProvider({
37201
37537
  const [popupRoot, setPopupRoot] = useState68(null);
37202
37538
  const [error, setError] = useState68(null);
37203
37539
  const [fullscreenExitStyle, setFullscreenExitStyle] = useState68(null);
37204
- const activeTargetRef = useRef54(activeTarget);
37540
+ const activeTargetRef = useRef55(activeTarget);
37205
37541
  activeTargetRef.current = activeTarget;
37206
- const previousActiveTargetRef = useRef54(null);
37207
- const returnFocusRef = useRef54(null);
37208
- const popupRef = useRef54(null);
37209
- const popupCleanupRef = useRef54(null);
37542
+ const previousActiveTargetRef = useRef55(null);
37543
+ const returnFocusRef = useRef55(null);
37544
+ const popupRef = useRef55(null);
37545
+ const popupCleanupRef = useRef55(null);
37210
37546
  const fullscreenSupported = typeof document !== "undefined" && typeof document.documentElement.requestFullscreen === "function";
37211
37547
  const availableTargets = useMemo50(
37212
37548
  () => [
@@ -37533,8 +37869,8 @@ function PresentationModeControl() {
37533
37869
  stop
37534
37870
  } = usePresentationMode();
37535
37871
  const { colorScheme } = useEditorContext();
37536
- const triggerRef = useRef54(null);
37537
- const menuRef = useRef54(null);
37872
+ const triggerRef = useRef55(null);
37873
+ const menuRef = useRef55(null);
37538
37874
  const [open, setOpen] = useState68(false);
37539
37875
  const [anchor, setAnchor] = useState68(null);
37540
37876
  const options = PRESENTATION_OPTIONS.filter((option) => availableTargets.includes(option.target));
@@ -37706,7 +38042,7 @@ import {
37706
38042
  useContext as useContext8,
37707
38043
  useEffect as useEffect58,
37708
38044
  useMemo as useMemo51,
37709
- useRef as useRef55,
38045
+ useRef as useRef56,
37710
38046
  useState as useState69
37711
38047
  } from "react";
37712
38048
  import { jsx as jsx75, jsxs as jsxs60 } from "react/jsx-runtime";
@@ -37724,8 +38060,8 @@ function PrintModeProvider({ rootRef, children }) {
37724
38060
  const { activeTarget: presentationTarget, stop: stopPresentation } = usePresentationMode();
37725
38061
  const [active, setActive] = useState69(false);
37726
38062
  const [slidesPerPage, setSlidesPerPage] = useState69(1);
37727
- const customPrintHandlerRef = useRef55(null);
37728
- const printAncestorsRef = useRef55([]);
38063
+ const customPrintHandlerRef = useRef56(null);
38064
+ const printAncestorsRef = useRef56([]);
37729
38065
  const unmarkPrinting = useCallback50(() => {
37730
38066
  const ownerDocument = rootRef.current?.ownerDocument;
37731
38067
  ownerDocument?.body.classList.remove("squisq-printing");
@@ -37877,7 +38213,7 @@ function PrintPreviewToolbar() {
37877
38213
  }
37878
38214
 
37879
38215
  // src/print/PrintPreview.tsx
37880
- import { useCallback as useCallback51, useEffect as useEffect59, useMemo as useMemo52, useRef as useRef56 } from "react";
38216
+ import { useCallback as useCallback51, useEffect as useEffect59, useMemo as useMemo52, useRef as useRef57 } from "react";
37881
38217
  import {
37882
38218
  BlockRenderer as BlockRenderer4,
37883
38219
  FlashcardFaceView,
@@ -37912,7 +38248,7 @@ function PrintPreview({
37912
38248
  }) {
37913
38249
  const { slidesPerPage, registerPrintHandler } = usePrintMode();
37914
38250
  const mediaProvider = useMediaProvider();
37915
- const documentFrameRef = useRef56(null);
38251
+ const documentFrameRef = useRef57(null);
37916
38252
  const setDocumentFrame = useCallback51((frame) => {
37917
38253
  documentFrameRef.current = frame;
37918
38254
  }, []);
@@ -38113,8 +38449,8 @@ function PreviewPanel({
38113
38449
  activeDashboardTitle,
38114
38450
  activeDashboardStyle
38115
38451
  } = usePreviewSettings();
38116
- const mainSurfaceRef = useRef57(null);
38117
- const popupSurfaceRef = useRef57(null);
38452
+ const mainSurfaceRef = useRef58(null);
38453
+ const popupSurfaceRef = useRef58(null);
38118
38454
  const [playbackState, setPlaybackState] = useState70(null);
38119
38455
  const handlePlaybackStateChange = useCallback52((next) => {
38120
38456
  setPlaybackState(next);
@@ -38424,7 +38760,7 @@ function PreviewPanel({
38424
38760
  }
38425
38761
 
38426
38762
  // src/MediaBin.tsx
38427
- import { useState as useState71, useEffect as useEffect61, useRef as useRef58, useCallback as useCallback53 } from "react";
38763
+ import { useState as useState71, useEffect as useEffect61, useRef as useRef59, useCallback as useCallback53 } from "react";
38428
38764
  import { jsx as jsx78, jsxs as jsxs63 } from "react/jsx-runtime";
38429
38765
  function formatSize(bytes) {
38430
38766
  if (bytes < 1024) return `${bytes} B`;
@@ -38494,7 +38830,7 @@ function MediaBin({
38494
38830
  highlightPath = null
38495
38831
  }) {
38496
38832
  const [entries, setEntries] = useState71([]);
38497
- const listRef = useRef58(null);
38833
+ const listRef = useRef59(null);
38498
38834
  useEffect61(() => {
38499
38835
  if (!highlightPath || !listRef.current) return;
38500
38836
  const item = listRef.current.querySelector(`[data-media-path="${CSS.escape(highlightPath)}"]`);
@@ -38507,9 +38843,9 @@ function MediaBin({
38507
38843
  const [isDropActive, setIsDropActive] = useState71(false);
38508
38844
  const [downloadingPath, setDownloadingPath] = useState71(null);
38509
38845
  const [contextMenu, setContextMenu] = useState71(null);
38510
- const fileInputRef = useRef58(null);
38511
- const contextMenuRef = useRef58(null);
38512
- const dropDepthRef = useRef58(0);
38846
+ const fileInputRef = useRef59(null);
38847
+ const contextMenuRef = useRef59(null);
38848
+ const dropDepthRef = useRef59(0);
38513
38849
  const updateEntries = useCallback53(
38514
38850
  async (provider) => {
38515
38851
  const list = sortMediaEntries(filterVisibleMediaEntries(await provider.listMedia()));
@@ -38994,7 +39330,7 @@ function DropZone({
38994
39330
  }
38995
39331
 
38996
39332
  // src/Tooltip.tsx
38997
- import { useEffect as useEffect62, useLayoutEffect as useLayoutEffect12, useRef as useRef59, useState as useState73 } from "react";
39333
+ import { useEffect as useEffect62, useLayoutEffect as useLayoutEffect12, useRef as useRef60, useState as useState73 } from "react";
38998
39334
  import { createPortal as createPortal17 } from "react-dom";
38999
39335
 
39000
39336
  // src/tooltipPlacement.ts
@@ -39011,10 +39347,10 @@ import { jsx as jsx80 } from "react/jsx-runtime";
39011
39347
  var SHOW_DELAY_MS = 180;
39012
39348
  function TooltipLayer() {
39013
39349
  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);
39350
+ const tooltipRef = useRef60(null);
39351
+ const timerRef = useRef60(null);
39352
+ const currentTargetRef = useRef60(null);
39353
+ const visibleRef = useRef60(false);
39018
39354
  useLayoutEffect12(() => {
39019
39355
  if (!state) return;
39020
39356
  const node2 = tooltipRef.current;
@@ -39112,7 +39448,7 @@ function TooltipLayer() {
39112
39448
  }
39113
39449
 
39114
39450
  // src/EditorShell.tsx
39115
- import { useEffect as useEffect63, useRef as useRef60, useState as useState74, useCallback as useCallback54, useMemo as useMemo55 } from "react";
39451
+ import { useEffect as useEffect63, useRef as useRef61, useState as useState74, useCallback as useCallback54, useMemo as useMemo55 } from "react";
39116
39452
 
39117
39453
  // src/BlockPreviewPanel.tsx
39118
39454
  import { useMemo as useMemo54 } from "react";
@@ -39597,6 +39933,7 @@ function EditorShell({
39597
39933
  proofingIgnoreStore,
39598
39934
  documentLinkProvider,
39599
39935
  fenceRenderers,
39936
+ onCopyCode,
39600
39937
  linkSchemes,
39601
39938
  allowRecording,
39602
39939
  allowNarrate,
@@ -39740,7 +40077,7 @@ function EditorShellInner({
39740
40077
  outlineWidth,
39741
40078
  themeOverride
39742
40079
  }) {
39743
- const shellRef = useRef60(null);
40080
+ const shellRef = useRef61(null);
39744
40081
  const {
39745
40082
  activeView,
39746
40083
  markdownSource,
@@ -39823,7 +40160,7 @@ function EditorShellInner({
39823
40160
  () => collectMediaReferencesFromMarkdown(markdownSource),
39824
40161
  [markdownSource]
39825
40162
  );
39826
- const imageEditFallbackContainerRef = useRef60(null);
40163
+ const imageEditFallbackContainerRef = useRef61(null);
39827
40164
  if (imageEditFallbackContainerRef.current === null) {
39828
40165
  imageEditFallbackContainerRef.current = new MemoryContentContainer();
39829
40166
  }
@@ -39897,7 +40234,7 @@ ${snippet}` : snippet);
39897
40234
  },
39898
40235
  [activeView, tiptapEditor, monacoEditor, insertAtCursor, markdownSource, setMarkdownSource]
39899
40236
  );
39900
- const docBasenameRef = useRef60("document");
40237
+ const docBasenameRef = useRef61("document");
39901
40238
  useEffect63(() => {
39902
40239
  let cancelled = false;
39903
40240
  docBasenameRef.current = "document";
@@ -40377,8 +40714,8 @@ function ImageEditModal({
40377
40714
  versioningAutoSaveIdleMs,
40378
40715
  shellTheme
40379
40716
  }) {
40380
- const modalRef = useRef60(null);
40381
- const surfaceRef = useRef60(null);
40717
+ const modalRef = useRef61(null);
40718
+ const surfaceRef = useRef61(null);
40382
40719
  useModalDialog({ rootRef: modalRef, dialogRef: surfaceRef, onClose });
40383
40720
  const extension = relativePath.split(/[?#]/, 1)[0]?.split(".").pop()?.toLowerCase();
40384
40721
  const saveFormat = extension === "png" ? "png" : extension === "jpg" || extension === "jpeg" ? "jpeg" : extension === "webp" ? "webp" : null;