@bendyline/squisq-editor-react 2.6.0 → 2.7.0

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.
@@ -378,6 +378,7 @@ function EditorProvider({
378
378
  imageDisplayMode = "inline",
379
379
  mentionProvider = null,
380
380
  documentLinkProvider = null,
381
+ fenceRenderers = null,
381
382
  linkSchemes,
382
383
  allowRecording = true,
383
384
  allowNarrate = true,
@@ -865,6 +866,7 @@ function EditorProvider({
865
866
  imageDisplayMode,
866
867
  mentionProvider,
867
868
  documentLinkProvider,
869
+ fenceRenderers,
868
870
  linkSchemes,
869
871
  fileName,
870
872
  setMarkdownSource,
@@ -926,6 +928,7 @@ function EditorProvider({
926
928
  imageDisplayMode,
927
929
  mentionProvider,
928
930
  documentLinkProvider,
931
+ fenceRenderers,
929
932
  linkSchemes,
930
933
  fileName,
931
934
  setMarkdownSource,
@@ -25015,19 +25018,21 @@ function CodeSnippetWidget({
25015
25018
 
25016
25019
  // src/codeSnippet/CodeSnippetExtension.ts
25017
25020
  var CODE_SNIPPET_KEY = new PluginKey6("squisq-code-snippet");
25018
- function isCodeSnippetNode(node2) {
25021
+ function isCodeSnippetNode(node2, reserved) {
25019
25022
  const language = node2.attrs.language;
25020
- return node2.type.name === "codeBlock" && isCodeSnippetFenceLanguage(typeof language === "string" ? language : null);
25023
+ const lang = typeof language === "string" ? language : null;
25024
+ if (node2.type.name !== "codeBlock" || !isCodeSnippetFenceLanguage(lang)) return false;
25025
+ return !reserved || !reserved.has(codeSnippetFenceLanguageToken(lang));
25021
25026
  }
25022
25027
  function findCodeSnippetBlockPos(editor, blockId) {
25023
25028
  const state = CODE_SNIPPET_KEY.getState(editor.state);
25024
25029
  return state?.entries.find((entry) => entry.id === blockId)?.pos ?? null;
25025
25030
  }
25026
- function buildDecorations5(doc, entries, editor, focusBlockId = null) {
25031
+ function buildDecorations5(doc, entries, editor, focusBlockId = null, reserved) {
25027
25032
  const decorations = [];
25028
25033
  for (const entry of entries) {
25029
25034
  const node2 = doc.nodeAt(entry.pos);
25030
- if (!node2 || !isCodeSnippetNode(node2)) continue;
25035
+ if (!node2 || !isCodeSnippetNode(node2, reserved)) continue;
25031
25036
  decorations.push(
25032
25037
  Decoration6.node(entry.pos, entry.pos + node2.nodeSize, {
25033
25038
  class: "squisq-code-snippet-fence-hidden"
@@ -25069,7 +25074,7 @@ function buildDecorations5(doc, entries, editor, focusBlockId = null) {
25069
25074
  }
25070
25075
  return DecorationSet6.create(doc, decorations);
25071
25076
  }
25072
- function remapEntries2(tr, previous, doc) {
25077
+ function remapEntries2(tr, previous, doc, reserved) {
25073
25078
  const mapped = /* @__PURE__ */ new Map();
25074
25079
  const claimed = /* @__PURE__ */ new Set();
25075
25080
  for (const entry of previous.entries) {
@@ -25092,22 +25097,22 @@ function remapEntries2(tr, previous, doc) {
25092
25097
  const entries = [];
25093
25098
  doc.descendants((node2, pos) => {
25094
25099
  if (node2.type.name !== "codeBlock") return;
25095
- if (!isCodeSnippetNode(node2)) return false;
25100
+ if (!isCodeSnippetNode(node2, reserved)) return false;
25096
25101
  entries.push({ id: mapped.get(pos) ?? `code-snippet-${++seq}`, pos });
25097
25102
  return false;
25098
25103
  });
25099
25104
  return { entries, seq };
25100
25105
  }
25101
- function applyState4(tr, previous, editor, doc) {
25106
+ function applyState4(tr, previous, editor, doc, reserved) {
25102
25107
  if (!tr.docChanged) return previous;
25103
- const { entries, seq } = remapEntries2(tr, previous, doc);
25108
+ const { entries, seq } = remapEntries2(tr, previous, doc, reserved);
25104
25109
  const requestedFocusPos = tr.getMeta(CODE_SNIPPET_FOCUS_INSERTED_META);
25105
25110
  const focusBlockId = typeof requestedFocusPos === "number" ? entries.find((entry) => entry.pos === requestedFocusPos)?.id ?? null : null;
25106
25111
  return {
25107
25112
  entries,
25108
25113
  seq,
25109
25114
  focusBlockId,
25110
- decorations: buildDecorations5(doc, entries, editor, focusBlockId)
25115
+ decorations: buildDecorations5(doc, entries, editor, focusBlockId, reserved)
25111
25116
  };
25112
25117
  }
25113
25118
  var CodeSnippetExtension = Extension6.create({
@@ -25118,6 +25123,7 @@ var CodeSnippetExtension = Extension6.create({
25118
25123
  addProseMirrorPlugins() {
25119
25124
  if (this.options.enabled === false) return [];
25120
25125
  const editor = this.editor;
25126
+ const reserved = this.options.reservedLanguages && this.options.reservedLanguages.length > 0 ? new Set(this.options.reservedLanguages.map((lang) => codeSnippetFenceLanguageToken(lang))) : void 0;
25121
25127
  return [
25122
25128
  new Plugin6({
25123
25129
  key: CODE_SNIPPET_KEY,
@@ -25127,7 +25133,7 @@ var CodeSnippetExtension = Extension6.create({
25127
25133
  const entries = [];
25128
25134
  state.doc.descendants((node2, pos) => {
25129
25135
  if (node2.type.name !== "codeBlock") return;
25130
- if (!isCodeSnippetNode(node2)) return false;
25136
+ if (!isCodeSnippetNode(node2, reserved)) return false;
25131
25137
  entries.push({ id: `code-snippet-${++seq}`, pos });
25132
25138
  return false;
25133
25139
  });
@@ -25135,10 +25141,10 @@ var CodeSnippetExtension = Extension6.create({
25135
25141
  entries,
25136
25142
  seq,
25137
25143
  focusBlockId: null,
25138
- decorations: buildDecorations5(state.doc, entries, editor)
25144
+ decorations: buildDecorations5(state.doc, entries, editor, null, reserved)
25139
25145
  };
25140
25146
  },
25141
- apply: (tr, previous, _oldState, newState) => applyState4(tr, previous, editor, newState.doc)
25147
+ apply: (tr, previous, _oldState, newState) => applyState4(tr, previous, editor, newState.doc, reserved)
25142
25148
  },
25143
25149
  props: {
25144
25150
  decorations(state) {
@@ -25164,15 +25170,188 @@ function replaceCodeSnippetText(editor, blockId, nextText) {
25164
25170
  return true;
25165
25171
  }
25166
25172
 
25167
- // src/treeview/treeViewData.ts
25168
- import { useEffect as useEffect33, useMemo as useMemo32, useState as useState43 } from "react";
25169
-
25170
- // src/treeview/TreeViewExtension.ts
25173
+ // src/fenceWidgets/HostFenceExtension.tsx
25171
25174
  import { Extension as Extension7 } from "@tiptap/core";
25172
25175
  import { Plugin as Plugin7, PluginKey as PluginKey7 } from "@tiptap/pm/state";
25173
25176
  import { Decoration as Decoration7, DecorationSet as DecorationSet7 } from "@tiptap/pm/view";
25174
25177
  import { createRoot as createRoot5 } from "react-dom/client";
25175
- import { createElement as createElement11 } from "react";
25178
+ import { Component, createElement as createElement11, useEffect as useEffect33, useMemo as useMemo32, useState as useState42 } from "react";
25179
+ import { jsx as jsx50 } from "react/jsx-runtime";
25180
+ var HOST_FENCE_KEY = new PluginKey7("squisq-host-fence");
25181
+ function fenceLangToken(node2) {
25182
+ const lang = node2.attrs.language;
25183
+ if (typeof lang !== "string") return "";
25184
+ return lang.trim().split(/\s+/, 1)[0]?.toLowerCase() ?? "";
25185
+ }
25186
+ function findHostFenceBlockPos(editor, blockId) {
25187
+ return HOST_FENCE_KEY.getState(editor.state)?.entries.find((e2) => e2.id === blockId)?.pos ?? null;
25188
+ }
25189
+ function replaceHostFenceText(editor, blockId, next) {
25190
+ const pos = findHostFenceBlockPos(editor, blockId);
25191
+ if (pos === null) return false;
25192
+ return replaceAsciiFenceText(editor, pos, next);
25193
+ }
25194
+ var HostFenceErrorBoundary = class extends Component {
25195
+ constructor() {
25196
+ super(...arguments);
25197
+ this.state = { failed: false };
25198
+ }
25199
+ static getDerivedStateFromError() {
25200
+ return { failed: true };
25201
+ }
25202
+ render() {
25203
+ return this.state.failed ? this.props.fallback : this.props.children;
25204
+ }
25205
+ };
25206
+ function HostFenceWidget({
25207
+ editor,
25208
+ blockId,
25209
+ getRenderers,
25210
+ getTheme
25211
+ }) {
25212
+ const [version, setVersion] = useState42(0);
25213
+ useEffect33(() => {
25214
+ const onUpdate = () => setVersion((v2) => v2 + 1);
25215
+ editor.on("transaction", onUpdate);
25216
+ return () => {
25217
+ editor.off("transaction", onUpdate);
25218
+ };
25219
+ }, [editor]);
25220
+ const current = useMemo32(() => {
25221
+ const pos = findHostFenceBlockPos(editor, blockId);
25222
+ if (pos === null) return null;
25223
+ const node2 = editor.state.doc.nodeAt(pos);
25224
+ if (!node2 || node2.type.name !== "codeBlock") return null;
25225
+ return { lang: fenceLangToken(node2), value: node2.textContent };
25226
+ }, [editor, blockId, version]);
25227
+ if (!current) return null;
25228
+ const renderer = getRenderers()?.[current.lang];
25229
+ const rawFallback = /* @__PURE__ */ jsx50("pre", { className: "squisq-md-code-block", children: /* @__PURE__ */ jsx50("code", { children: current.value }) });
25230
+ if (!renderer) return rawFallback;
25231
+ const theme = getTheme();
25232
+ return /* @__PURE__ */ jsx50(HostFenceErrorBoundary, { fallback: rawFallback, children: renderer({
25233
+ lang: current.lang,
25234
+ value: current.value,
25235
+ ...theme ? { theme } : {},
25236
+ mode: "edit",
25237
+ replaceValue: (next) => {
25238
+ replaceHostFenceText(editor, blockId, next);
25239
+ }
25240
+ }) });
25241
+ }
25242
+ function buildDecorations6(doc, entries, editor, options) {
25243
+ const decos = [];
25244
+ for (const entry of entries) {
25245
+ const node2 = doc.nodeAt(entry.pos);
25246
+ if (!node2 || node2.type.name !== "codeBlock") continue;
25247
+ decos.push(
25248
+ Decoration7.node(entry.pos, entry.pos + node2.nodeSize, {
25249
+ class: "squisq-host-fence-hidden"
25250
+ })
25251
+ );
25252
+ const blockId = entry.id;
25253
+ decos.push(
25254
+ Decoration7.widget(
25255
+ entry.pos + node2.nodeSize,
25256
+ () => {
25257
+ const container = document.createElement("div");
25258
+ container.className = "squisq-host-fence-widget-host";
25259
+ container.contentEditable = "false";
25260
+ containFenceWidgetEvents(container);
25261
+ const root = createRoot5(container);
25262
+ root.render(
25263
+ createElement11(HostFenceWidget, {
25264
+ editor,
25265
+ blockId,
25266
+ getRenderers: () => options.renderers?.(),
25267
+ getTheme: () => options.theme?.()
25268
+ })
25269
+ );
25270
+ container.__squisqHostFenceRoot = { root };
25271
+ return container;
25272
+ },
25273
+ {
25274
+ destroy: (dom) => {
25275
+ const ref = dom.__squisqHostFenceRoot;
25276
+ if (ref) setTimeout(() => ref.root.unmount(), 0);
25277
+ },
25278
+ side: 1,
25279
+ ignoreSelection: true,
25280
+ key: `squisq-host-fence-${entry.id}`
25281
+ }
25282
+ )
25283
+ );
25284
+ }
25285
+ return DecorationSet7.create(doc, decos);
25286
+ }
25287
+ function claims(node2, options) {
25288
+ if (node2.type.name !== "codeBlock") return false;
25289
+ const lang = fenceLangToken(node2);
25290
+ if (!lang) return false;
25291
+ return Boolean(options.renderers?.()?.[lang]);
25292
+ }
25293
+ function applyState5(tr, prev, editor, doc, options) {
25294
+ if (!tr.docChanged) return prev;
25295
+ const mapped = mapFenceEntries(tr, prev.entries, doc);
25296
+ let seq = prev.seq;
25297
+ const entries = [];
25298
+ doc.descendants((node2, pos) => {
25299
+ if (node2.type.name !== "codeBlock") return;
25300
+ if (!claims(node2, options)) return false;
25301
+ entries.push({ id: mapped.get(pos) ?? `host-fence-${++seq}`, pos });
25302
+ return false;
25303
+ });
25304
+ return { entries, seq, decorations: buildDecorations6(doc, entries, editor, options) };
25305
+ }
25306
+ var HostFenceExtension = Extension7.create({
25307
+ name: "squisqHostFence",
25308
+ addOptions() {
25309
+ return { enabled: true };
25310
+ },
25311
+ addProseMirrorPlugins() {
25312
+ const editor = this.editor;
25313
+ const options = this.options;
25314
+ if (options.enabled === false || !options.renderers) return [];
25315
+ return [
25316
+ new Plugin7({
25317
+ key: HOST_FENCE_KEY,
25318
+ state: {
25319
+ init: (_config, state) => {
25320
+ let seq = 0;
25321
+ const entries = [];
25322
+ state.doc.descendants((node2, pos) => {
25323
+ if (node2.type.name !== "codeBlock") return;
25324
+ if (!claims(node2, options)) return false;
25325
+ entries.push({ id: `host-fence-${++seq}`, pos });
25326
+ return false;
25327
+ });
25328
+ return {
25329
+ entries,
25330
+ seq,
25331
+ decorations: buildDecorations6(state.doc, entries, editor, options)
25332
+ };
25333
+ },
25334
+ apply: (tr, prev, _oldState, newState) => applyState5(tr, prev, editor, newState.doc, options)
25335
+ },
25336
+ props: {
25337
+ decorations(state) {
25338
+ return this.getState(state)?.decorations ?? DecorationSet7.empty;
25339
+ }
25340
+ }
25341
+ })
25342
+ ];
25343
+ }
25344
+ });
25345
+
25346
+ // src/treeview/treeViewData.ts
25347
+ import { useEffect as useEffect34, useMemo as useMemo33, useState as useState44 } from "react";
25348
+
25349
+ // src/treeview/TreeViewExtension.ts
25350
+ import { Extension as Extension8 } from "@tiptap/core";
25351
+ import { Plugin as Plugin8, PluginKey as PluginKey8 } from "@tiptap/pm/state";
25352
+ import { Decoration as Decoration8, DecorationSet as DecorationSet8 } from "@tiptap/pm/view";
25353
+ import { createRoot as createRoot6 } from "react-dom/client";
25354
+ import { createElement as createElement12 } from "react";
25176
25355
  import {
25177
25356
  detectTree,
25178
25357
  isEligibleTreeFenceLang,
@@ -25182,7 +25361,7 @@ import {
25182
25361
  } from "@bendyline/squisq/doc";
25183
25362
 
25184
25363
  // src/treeview/TreeOutlineWidget.tsx
25185
- import { useCallback as useCallback36, useRef as useRef35, useState as useState42 } from "react";
25364
+ import { useCallback as useCallback36, useRef as useRef35, useState as useState43 } from "react";
25186
25365
 
25187
25366
  // src/treeview/treeViewCommands.ts
25188
25367
  import { parseTree, renderTree } from "@bendyline/squisq/doc";
@@ -25392,7 +25571,7 @@ function applyTreeCommand(editor, blockId, cmd) {
25392
25571
  }
25393
25572
 
25394
25573
  // src/treeview/TreeOutlineWidget.tsx
25395
- import { jsx as jsx50, jsxs as jsxs39 } from "react/jsx-runtime";
25574
+ import { jsx as jsx51, jsxs as jsxs39 } from "react/jsx-runtime";
25396
25575
  var TREE_DRAG_MIME = "application/x-squisq-tree-node";
25397
25576
  function findNode(nodes, id) {
25398
25577
  for (const node2 of nodes) {
@@ -25419,10 +25598,10 @@ function dropPositionForPointer(event) {
25419
25598
  }
25420
25599
  function TreeOutlineWidget({ editor, blockId }) {
25421
25600
  const view = useTreeViewData(editor, blockId);
25422
- const [collapsed, setCollapsed] = useState42(() => /* @__PURE__ */ new Set());
25601
+ const [collapsed, setCollapsed] = useState43(() => /* @__PURE__ */ new Set());
25423
25602
  const activeDragRef = useRef35(null);
25424
- const [draggedId, setDraggedId] = useState42(null);
25425
- const [dropTarget, setDropTarget] = useState42(null);
25603
+ const [draggedId, setDraggedId] = useState43(null);
25604
+ const [dropTarget, setDropTarget] = useState43(null);
25426
25605
  const dispatch = useCallback36(
25427
25606
  (cmd) => applyTreeCommand(editor, blockId, cmd),
25428
25607
  [editor, blockId]
@@ -25504,7 +25683,7 @@ function TreeOutlineWidget({ editor, blockId }) {
25504
25683
  disabled: !firstRootId,
25505
25684
  onClick: () => firstRootId ? dispatch({ kind: "addItem", targetId: firstRootId, position: "siblingAfter" }) : void 0,
25506
25685
  children: [
25507
- /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-plus" }),
25686
+ /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-plus" }),
25508
25687
  " Item"
25509
25688
  ]
25510
25689
  }
@@ -25523,13 +25702,13 @@ function TreeOutlineWidget({ editor, blockId }) {
25523
25702
  isDir: true
25524
25703
  }) : void 0,
25525
25704
  children: [
25526
- /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-folder-plus" }),
25705
+ /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-folder-plus" }),
25527
25706
  " Folder"
25528
25707
  ]
25529
25708
  }
25530
25709
  )
25531
25710
  ] }),
25532
- /* @__PURE__ */ jsx50("ul", { className: "squisq-tree-rows", role: "tree", children: roots.map((node2) => /* @__PURE__ */ jsx50(
25711
+ /* @__PURE__ */ jsx51("ul", { className: "squisq-tree-rows", role: "tree", children: roots.map((node2) => /* @__PURE__ */ jsx51(
25533
25712
  TreeRowView,
25534
25713
  {
25535
25714
  node: node2,
@@ -25569,7 +25748,7 @@ function TreeRowView({
25569
25748
  const hasChildren = node2.children.length > 0;
25570
25749
  const isCollapsed = collapsed.has(node2.id);
25571
25750
  const isDir = node2.isDir || hasChildren;
25572
- const [draft, setDraft] = useState42(node2.label);
25751
+ const [draft, setDraft] = useState43(node2.label);
25573
25752
  const dropPosition = dropTarget?.id === node2.id ? dropTarget.position : null;
25574
25753
  const itemClassName = [
25575
25754
  "squisq-tree-item",
@@ -25589,27 +25768,27 @@ function TreeRowView({
25589
25768
  onDragOver: (event) => onDragOver(event, node2.id),
25590
25769
  onDrop: (event) => onDrop(event, node2.id),
25591
25770
  children: [
25592
- hasChildren ? /* @__PURE__ */ jsx50(
25771
+ hasChildren ? /* @__PURE__ */ jsx51(
25593
25772
  "button",
25594
25773
  {
25595
25774
  type: "button",
25596
25775
  className: "squisq-tree-chevron",
25597
25776
  "aria-label": isCollapsed ? "Expand" : "Collapse",
25598
25777
  onClick: () => toggleCollapse(node2.id),
25599
- children: /* @__PURE__ */ jsx50(Icon, { icon: `fa-solid ${isCollapsed ? "fa-chevron-right" : "fa-chevron-down"}` })
25778
+ children: /* @__PURE__ */ jsx51(Icon, { icon: `fa-solid ${isCollapsed ? "fa-chevron-right" : "fa-chevron-down"}` })
25600
25779
  }
25601
- ) : /* @__PURE__ */ jsx50("span", { className: "squisq-tree-chevron squisq-tree-chevron--empty" }),
25602
- /* @__PURE__ */ jsx50(
25780
+ ) : /* @__PURE__ */ jsx51("span", { className: "squisq-tree-chevron squisq-tree-chevron--empty" }),
25781
+ /* @__PURE__ */ jsx51(
25603
25782
  "button",
25604
25783
  {
25605
25784
  type: "button",
25606
25785
  className: "squisq-tree-icon",
25607
25786
  title: isDir ? "Make a file" : "Make a folder",
25608
25787
  onClick: () => dispatch({ kind: "toggleDir", id: node2.id }),
25609
- children: /* @__PURE__ */ jsx50(Icon, { icon: `fa-solid ${isDir ? "fa-folder" : "fa-file"}` })
25788
+ children: /* @__PURE__ */ jsx51(Icon, { icon: `fa-solid ${isDir ? "fa-folder" : "fa-file"}` })
25610
25789
  }
25611
25790
  ),
25612
- /* @__PURE__ */ jsx50(
25791
+ /* @__PURE__ */ jsx51(
25613
25792
  "input",
25614
25793
  {
25615
25794
  className: "squisq-tree-label",
@@ -25633,7 +25812,7 @@ function TreeRowView({
25633
25812
  }
25634
25813
  ),
25635
25814
  /* @__PURE__ */ jsxs39("span", { className: "squisq-tree-controls", children: [
25636
- /* @__PURE__ */ jsx50(
25815
+ /* @__PURE__ */ jsx51(
25637
25816
  "span",
25638
25817
  {
25639
25818
  className: "squisq-tree-drag-handle",
@@ -25642,69 +25821,69 @@ function TreeRowView({
25642
25821
  title: `Drag ${node2.label} to move`,
25643
25822
  onDragStart: (event) => onDragStart(event, node2.id),
25644
25823
  onDragEnd,
25645
- children: /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-grip-vertical" })
25824
+ children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-grip-vertical" })
25646
25825
  }
25647
25826
  ),
25648
- /* @__PURE__ */ jsx50(
25827
+ /* @__PURE__ */ jsx51(
25649
25828
  "button",
25650
25829
  {
25651
25830
  type: "button",
25652
25831
  title: "Add child",
25653
25832
  onClick: () => dispatch({ kind: "addItem", targetId: node2.id, position: "child" }),
25654
- children: /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-plus" })
25833
+ children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-plus" })
25655
25834
  }
25656
25835
  ),
25657
- /* @__PURE__ */ jsx50(
25836
+ /* @__PURE__ */ jsx51(
25658
25837
  "button",
25659
25838
  {
25660
25839
  type: "button",
25661
25840
  title: "Outdent",
25662
25841
  onClick: () => dispatch({ kind: "outdentItem", id: node2.id }),
25663
- children: /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-outdent" })
25842
+ children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-outdent" })
25664
25843
  }
25665
25844
  ),
25666
- /* @__PURE__ */ jsx50(
25845
+ /* @__PURE__ */ jsx51(
25667
25846
  "button",
25668
25847
  {
25669
25848
  type: "button",
25670
25849
  title: "Indent",
25671
25850
  onClick: () => dispatch({ kind: "indentItem", id: node2.id }),
25672
- children: /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-indent" })
25851
+ children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-indent" })
25673
25852
  }
25674
25853
  ),
25675
- /* @__PURE__ */ jsx50(
25854
+ /* @__PURE__ */ jsx51(
25676
25855
  "button",
25677
25856
  {
25678
25857
  type: "button",
25679
25858
  title: "Move up",
25680
25859
  onClick: () => dispatch({ kind: "moveItemUp", id: node2.id }),
25681
- children: /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-arrow-up" })
25860
+ children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-arrow-up" })
25682
25861
  }
25683
25862
  ),
25684
- /* @__PURE__ */ jsx50(
25863
+ /* @__PURE__ */ jsx51(
25685
25864
  "button",
25686
25865
  {
25687
25866
  type: "button",
25688
25867
  title: "Move down",
25689
25868
  onClick: () => dispatch({ kind: "moveItemDown", id: node2.id }),
25690
- children: /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-arrow-down" })
25869
+ children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-arrow-down" })
25691
25870
  }
25692
25871
  ),
25693
- /* @__PURE__ */ jsx50(
25872
+ /* @__PURE__ */ jsx51(
25694
25873
  "button",
25695
25874
  {
25696
25875
  type: "button",
25697
25876
  title: "Delete",
25698
25877
  className: "squisq-tree-delete",
25699
25878
  onClick: () => dispatch({ kind: "removeItem", id: node2.id }),
25700
- children: /* @__PURE__ */ jsx50(Icon, { icon: "fa-solid fa-trash" })
25879
+ children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-trash" })
25701
25880
  }
25702
25881
  )
25703
25882
  ] })
25704
25883
  ]
25705
25884
  }
25706
25885
  ),
25707
- hasChildren && !isCollapsed ? /* @__PURE__ */ jsx50("ul", { className: "squisq-tree-rows", role: "group", children: node2.children.map((child) => /* @__PURE__ */ jsx50(
25886
+ hasChildren && !isCollapsed ? /* @__PURE__ */ jsx51("ul", { className: "squisq-tree-rows", role: "group", children: node2.children.map((child) => /* @__PURE__ */ jsx51(
25708
25887
  TreeRowView,
25709
25888
  {
25710
25889
  node: child,
@@ -25725,7 +25904,7 @@ function TreeRowView({
25725
25904
  }
25726
25905
 
25727
25906
  // src/treeview/TreeViewExtension.ts
25728
- var TREEVIEW_KEY = new PluginKey7("squisq-treeview");
25907
+ var TREEVIEW_KEY = new PluginKey8("squisq-treeview");
25729
25908
  var detectCache2 = /* @__PURE__ */ new WeakMap();
25730
25909
  var parseCache2 = /* @__PURE__ */ new WeakMap();
25731
25910
  function fenceLangOf3(node2) {
@@ -25771,27 +25950,27 @@ function parseTreeForNode(node2) {
25771
25950
  function findTreeBlockPos(editor, blockId) {
25772
25951
  return TREEVIEW_KEY.getState(editor.state)?.entries.find((e2) => e2.id === blockId)?.pos ?? null;
25773
25952
  }
25774
- function buildDecorations6(doc, entries, editor) {
25953
+ function buildDecorations7(doc, entries, editor) {
25775
25954
  const decos = [];
25776
25955
  for (const entry of entries) {
25777
25956
  const node2 = doc.nodeAt(entry.pos);
25778
25957
  if (!node2 || node2.type.name !== "codeBlock") continue;
25779
25958
  decos.push(
25780
- Decoration7.node(entry.pos, entry.pos + node2.nodeSize, { class: "squisq-tree-fence-hidden" })
25959
+ Decoration8.node(entry.pos, entry.pos + node2.nodeSize, { class: "squisq-tree-fence-hidden" })
25781
25960
  );
25782
25961
  const blockId = entry.id;
25783
25962
  const fallbackPos = entry.pos;
25784
25963
  decos.push(
25785
- Decoration7.widget(
25964
+ Decoration8.widget(
25786
25965
  entry.pos + node2.nodeSize,
25787
25966
  (view) => {
25788
25967
  const container = document.createElement("div");
25789
25968
  container.className = "squisq-tree-widget-host";
25790
25969
  container.contentEditable = "false";
25791
25970
  containFenceWidgetEvents(container);
25792
- const root = createRoot5(container);
25971
+ const root = createRoot6(container);
25793
25972
  root.render(
25794
- createElement11(TreeOutlineWidget, {
25973
+ createElement12(TreeOutlineWidget, {
25795
25974
  editor,
25796
25975
  blockId,
25797
25976
  fallbackPos,
@@ -25815,9 +25994,9 @@ function buildDecorations6(doc, entries, editor) {
25815
25994
  )
25816
25995
  );
25817
25996
  }
25818
- return DecorationSet7.create(doc, decos);
25997
+ return DecorationSet8.create(doc, decos);
25819
25998
  }
25820
- function applyState5(tr, prev, editor, doc) {
25999
+ function applyState6(tr, prev, editor, doc) {
25821
26000
  if (!tr.docChanged) return prev;
25822
26001
  const mapped = mapFenceEntries(tr, prev.entries, doc);
25823
26002
  let seq = prev.seq;
@@ -25830,9 +26009,9 @@ function applyState5(tr, prev, editor, doc) {
25830
26009
  entries.push({ id: knownId ?? `tree-${++seq}`, pos });
25831
26010
  return false;
25832
26011
  });
25833
- return { entries, seq, decorations: buildDecorations6(doc, entries, editor) };
26012
+ return { entries, seq, decorations: buildDecorations7(doc, entries, editor) };
25834
26013
  }
25835
- var TreeViewExtension = Extension7.create({
26014
+ var TreeViewExtension = Extension8.create({
25836
26015
  name: "squisqTreeView",
25837
26016
  addOptions() {
25838
26017
  return { enabled: true };
@@ -25841,7 +26020,7 @@ var TreeViewExtension = Extension7.create({
25841
26020
  const editor = this.editor;
25842
26021
  if (this.options.enabled === false) return [];
25843
26022
  return [
25844
- new Plugin7({
26023
+ new Plugin8({
25845
26024
  key: TREEVIEW_KEY,
25846
26025
  state: {
25847
26026
  init: (_config, state) => {
@@ -25856,14 +26035,14 @@ var TreeViewExtension = Extension7.create({
25856
26035
  return {
25857
26036
  entries,
25858
26037
  seq,
25859
- decorations: buildDecorations6(state.doc, entries, editor)
26038
+ decorations: buildDecorations7(state.doc, entries, editor)
25860
26039
  };
25861
26040
  },
25862
- apply: (tr, prev, _oldState, newState) => applyState5(tr, prev, editor, newState.doc)
26041
+ apply: (tr, prev, _oldState, newState) => applyState6(tr, prev, editor, newState.doc)
25863
26042
  },
25864
26043
  props: {
25865
26044
  decorations(state) {
25866
- return this.getState(state)?.decorations ?? DecorationSet7.empty;
26045
+ return this.getState(state)?.decorations ?? DecorationSet8.empty;
25867
26046
  }
25868
26047
  }
25869
26048
  })
@@ -25873,15 +26052,15 @@ var TreeViewExtension = Extension7.create({
25873
26052
 
25874
26053
  // src/treeview/treeViewData.ts
25875
26054
  function useTreeViewData(editor, blockId) {
25876
- const [version, setVersion] = useState43(0);
25877
- useEffect33(() => {
26055
+ const [version, setVersion] = useState44(0);
26056
+ useEffect34(() => {
25878
26057
  const onUpdate = () => setVersion((v2) => v2 + 1);
25879
26058
  editor.on("transaction", onUpdate);
25880
26059
  return () => {
25881
26060
  editor.off("transaction", onUpdate);
25882
26061
  };
25883
26062
  }, [editor]);
25884
- return useMemo32(() => {
26063
+ return useMemo33(() => {
25885
26064
  const pos = findTreeBlockPos(editor, blockId);
25886
26065
  if (pos === null) return null;
25887
26066
  const node2 = editor.state.doc.nodeAt(pos);
@@ -25900,14 +26079,14 @@ function shouldPasteAsTreeFence(text) {
25900
26079
  }
25901
26080
 
25902
26081
  // src/timeline/timelineData.ts
25903
- import { useEffect as useEffect35, useMemo as useMemo34, useRef as useRef37, useState as useState45 } from "react";
26082
+ import { useEffect as useEffect36, useMemo as useMemo35, useRef as useRef37, useState as useState46 } from "react";
25904
26083
 
25905
26084
  // src/timeline/TimelineViewExtension.ts
25906
- import { Extension as Extension8 } from "@tiptap/core";
25907
- import { Plugin as Plugin8, PluginKey as PluginKey8 } from "@tiptap/pm/state";
25908
- import { Decoration as Decoration8, DecorationSet as DecorationSet8 } from "@tiptap/pm/view";
25909
- import { createElement as createElement12 } from "react";
25910
- import { createRoot as createRoot6 } from "react-dom/client";
26085
+ import { Extension as Extension9 } from "@tiptap/core";
26086
+ import { Plugin as Plugin9, PluginKey as PluginKey9 } from "@tiptap/pm/state";
26087
+ import { Decoration as Decoration9, DecorationSet as DecorationSet9 } from "@tiptap/pm/view";
26088
+ import { createElement as createElement13 } from "react";
26089
+ import { createRoot as createRoot7 } from "react-dom/client";
25911
26090
  import {
25912
26091
  detectAsciiTimeline,
25913
26092
  isEligibleAsciiTimelineFenceLang,
@@ -25915,7 +26094,7 @@ import {
25915
26094
  } from "@bendyline/squisq/doc";
25916
26095
 
25917
26096
  // src/timeline/TimelineEditorWidget.tsx
25918
- import { useCallback as useCallback37, useEffect as useEffect34, useMemo as useMemo33, useRef as useRef36, useState as useState44 } from "react";
26097
+ import { useCallback as useCallback37, useEffect as useEffect35, useMemo as useMemo34, useRef as useRef36, useState as useState45 } from "react";
25919
26098
  import {
25920
26099
  asciiTimelineToTemplateData
25921
26100
  } from "@bendyline/squisq/doc";
@@ -26395,17 +26574,17 @@ function applyTimelineCommand(editor, blockId, command) {
26395
26574
  }
26396
26575
 
26397
26576
  // src/timeline/TimelineEditorWidget.tsx
26398
- import { Fragment as Fragment15, jsx as jsx51, jsxs as jsxs40 } from "react/jsx-runtime";
26577
+ import { Fragment as Fragment15, jsx as jsx52, jsxs as jsxs40 } from "react/jsx-runtime";
26399
26578
  var clamp01 = (value) => Math.max(0, Math.min(1, value));
26400
26579
  function TimelineEditorWidget({ editor, blockId }) {
26401
26580
  const view = useTimelineData(editor, blockId);
26402
- const [selectedEventId, setSelectedEventId] = useState44(null);
26403
- const [addingTrackId, setAddingTrackId] = useState44(null);
26404
- const [editingTrackId, setEditingTrackId] = useState44(null);
26405
- const [hover, setHover] = useState44(null);
26406
- const [dragged, setDragged] = useState44(null);
26581
+ const [selectedEventId, setSelectedEventId] = useState45(null);
26582
+ const [addingTrackId, setAddingTrackId] = useState45(null);
26583
+ const [editingTrackId, setEditingTrackId] = useState45(null);
26584
+ const [hover, setHover] = useState45(null);
26585
+ const [dragged, setDragged] = useState45(null);
26407
26586
  const suppressClickEventId = useRef36(null);
26408
- const [announcement, setAnnouncement] = useState44("");
26587
+ const [announcement, setAnnouncement] = useState45("");
26409
26588
  const dispatch = useCallback37(
26410
26589
  (command) => {
26411
26590
  const result = applyTimelineCommand(editor, blockId, command);
@@ -26419,7 +26598,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26419
26598
  );
26420
26599
  const sourceText2 = view?.text;
26421
26600
  const sourceTimeline = view?.timeline;
26422
- const sourceSafe = useMemo33(
26601
+ const sourceSafe = useMemo34(
26423
26602
  () => sourceText2 && sourceTimeline ? isTimelineSourceSafeForSemanticEdit(sourceText2, sourceTimeline) : false,
26424
26603
  // `useTimelineData` publishes on every editor transaction so read-only
26425
26604
  // changes are observed. Unrelated transactions retain both primitive/model
@@ -26429,7 +26608,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26429
26608
  );
26430
26609
  const editorEditable = editor.isEditable;
26431
26610
  const editable = editorEditable && sourceSafe;
26432
- const positioned = useMemo33(() => {
26611
+ const positioned = useMemo34(() => {
26433
26612
  if (!view) return [];
26434
26613
  const normalized = asciiTimelineToTemplateData(view.timeline).tracks;
26435
26614
  return view.timeline.tracks.flatMap((track, trackIndex) => {
@@ -26444,17 +26623,17 @@ function TimelineEditorWidget({ editor, blockId }) {
26444
26623
  );
26445
26624
  });
26446
26625
  }, [view]);
26447
- const displayedPositioned = useMemo33(
26626
+ const displayedPositioned = useMemo34(
26448
26627
  () => dragged ? positioned.map(
26449
26628
  (point) => point.event.id === dragged.eventId ? { ...point, position: dragged.position } : point
26450
26629
  ) : positioned,
26451
26630
  [dragged, positioned]
26452
26631
  );
26453
- const positionById = useMemo33(
26632
+ const positionById = useMemo34(
26454
26633
  () => new Map(displayedPositioned.map((point) => [point.event.id, point.position])),
26455
26634
  [displayedPositioned]
26456
26635
  );
26457
- const selected = useMemo33(() => {
26636
+ const selected = useMemo34(() => {
26458
26637
  if (!view || !selectedEventId) return null;
26459
26638
  for (const track of view.timeline.tracks) {
26460
26639
  const event = track.events.find((candidate) => candidate.id === selectedEventId);
@@ -26468,7 +26647,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26468
26647
  }
26469
26648
  return null;
26470
26649
  }, [selectedEventId, view]);
26471
- useEffect34(() => {
26650
+ useEffect35(() => {
26472
26651
  if (!view) return;
26473
26652
  const ids = new Set(
26474
26653
  view.timeline.tracks.flatMap((track) => track.events.map((event) => event.id))
@@ -26476,13 +26655,13 @@ function TimelineEditorWidget({ editor, blockId }) {
26476
26655
  if (selectedEventId && ids.has(selectedEventId)) return;
26477
26656
  setSelectedEventId(view.timeline.tracks[0]?.events[0]?.id ?? null);
26478
26657
  }, [selectedEventId, view]);
26479
- useEffect34(() => {
26658
+ useEffect35(() => {
26480
26659
  if (editable) return;
26481
26660
  setAddingTrackId(null);
26482
26661
  setEditingTrackId(null);
26483
26662
  setHover(null);
26484
26663
  }, [editable]);
26485
- useEffect34(() => {
26664
+ useEffect35(() => {
26486
26665
  if (!editingTrackId || view?.timeline.tracks.some((track) => track.id === editingTrackId)) {
26487
26666
  return;
26488
26667
  }
@@ -26549,13 +26728,13 @@ function TimelineEditorWidget({ editor, blockId }) {
26549
26728
  children: [
26550
26729
  /* @__PURE__ */ jsxs40("header", { className: "squisq-ascii-timeline-header", children: [
26551
26730
  /* @__PURE__ */ jsxs40("span", { children: [
26552
- /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-timeline" }),
26731
+ /* @__PURE__ */ jsx52(Icon, { icon: "fa-solid fa-timeline" }),
26553
26732
  " Timeline"
26554
26733
  ] }),
26555
26734
  /* @__PURE__ */ jsxs40("div", { className: "squisq-ascii-timeline-header-actions", children: [
26556
- editable && addingTrackId ? /* @__PURE__ */ jsx51("small", { children: "Click the line to add a point \xB7 Esc to cancel" }) : editable ? /* @__PURE__ */ jsx51("small", { children: "Use + to add a point \xB7 Drag dots to move" }) : editorEditable ? /* @__PURE__ */ jsx51("small", { children: "Source repair needed" }) : /* @__PURE__ */ jsx51("small", { children: "Read only" }),
26735
+ editable && addingTrackId ? /* @__PURE__ */ jsx52("small", { children: "Click the line to add a point \xB7 Esc to cancel" }) : editable ? /* @__PURE__ */ jsx52("small", { children: "Use + to add a point \xB7 Drag dots to move" }) : editorEditable ? /* @__PURE__ */ jsx52("small", { children: "Source repair needed" }) : /* @__PURE__ */ jsx52("small", { children: "Read only" }),
26557
26736
  editable ? /* @__PURE__ */ jsxs40("button", { type: "button", onClick: addTrack, children: [
26558
- /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-plus" }),
26737
+ /* @__PURE__ */ jsx52(Icon, { icon: "fa-solid fa-plus" }),
26559
26738
  " Add line"
26560
26739
  ] }) : null
26561
26740
  ] })
@@ -26566,7 +26745,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26566
26745
  className: "squisq-ascii-timeline-canvas",
26567
26746
  style: { "--squisq-ascii-timeline-track-count": view.timeline.tracks.length },
26568
26747
  children: [
26569
- view.timeline.links.length > 0 ? /* @__PURE__ */ jsx51(
26748
+ view.timeline.links.length > 0 ? /* @__PURE__ */ jsx52(
26570
26749
  "svg",
26571
26750
  {
26572
26751
  className: "squisq-ascii-timeline-branches",
@@ -26583,7 +26762,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26583
26762
  const ty = target.trackIndex * 96 + 48;
26584
26763
  const sameTrack = source.trackIndex === target.trackIndex;
26585
26764
  const controlY = sameTrack ? sy + (source.event.side === "below" ? -30 : 30) : (sy + ty) / 2;
26586
- return /* @__PURE__ */ jsx51(
26765
+ return /* @__PURE__ */ jsx52(
26587
26766
  "path",
26588
26767
  {
26589
26768
  d: `M ${sx} ${sy} C ${sx} ${controlY}, ${tx} ${controlY}, ${tx} ${ty}`,
@@ -26602,7 +26781,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26602
26781
  const addingPoint = editable && addingTrackId === track.id;
26603
26782
  return /* @__PURE__ */ jsxs40("div", { className: "squisq-ascii-timeline-track", children: [
26604
26783
  /* @__PURE__ */ jsxs40("div", { className: "squisq-ascii-timeline-track-label", children: [
26605
- /* @__PURE__ */ jsx51(
26784
+ /* @__PURE__ */ jsx52(
26606
26785
  InlineTrackLabel,
26607
26786
  {
26608
26787
  trackId: track.id,
@@ -26619,7 +26798,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26619
26798
  }
26620
26799
  ),
26621
26800
  editable ? /* @__PURE__ */ jsxs40(Fragment15, { children: [
26622
- /* @__PURE__ */ jsx51(
26801
+ /* @__PURE__ */ jsx52(
26623
26802
  "button",
26624
26803
  {
26625
26804
  type: "button",
@@ -26628,10 +26807,10 @@ function TimelineEditorWidget({ editor, blockId }) {
26628
26807
  disabled: view.timeline.tracks.length <= 1,
26629
26808
  title: view.timeline.tracks.length > 1 ? `Delete ${trackLabel} line and all of its points` : "A timeline needs one line",
26630
26809
  onClick: () => deleteTrack(track.id, trackLabel),
26631
- children: /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-trash" })
26810
+ children: /* @__PURE__ */ jsx52(Icon, { icon: "fa-solid fa-trash" })
26632
26811
  }
26633
26812
  ),
26634
- /* @__PURE__ */ jsx51(
26813
+ /* @__PURE__ */ jsx52(
26635
26814
  "button",
26636
26815
  {
26637
26816
  type: "button",
@@ -26676,8 +26855,8 @@ function TimelineEditorWidget({ editor, blockId }) {
26676
26855
  addEvent(track.id, (event.clientX - rect.left) / rect.width);
26677
26856
  },
26678
26857
  children: [
26679
- /* @__PURE__ */ jsx51("span", { className: "squisq-ascii-timeline-rail-line", "aria-hidden": "true" }),
26680
- addingPoint && hover?.trackId === track.id && !dragged ? /* @__PURE__ */ jsx51(
26858
+ /* @__PURE__ */ jsx52("span", { className: "squisq-ascii-timeline-rail-line", "aria-hidden": "true" }),
26859
+ addingPoint && hover?.trackId === track.id && !dragged ? /* @__PURE__ */ jsx52(
26681
26860
  "span",
26682
26861
  {
26683
26862
  className: "squisq-ascii-timeline-add-ghost",
@@ -26686,7 +26865,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26686
26865
  children: "+"
26687
26866
  }
26688
26867
  ) : null,
26689
- addingPoint && !dragged ? gaps.map((position) => /* @__PURE__ */ jsx51(
26868
+ addingPoint && !dragged ? gaps.map((position) => /* @__PURE__ */ jsx52(
26690
26869
  "button",
26691
26870
  {
26692
26871
  type: "button",
@@ -26713,21 +26892,21 @@ function TimelineEditorWidget({ editor, blockId }) {
26713
26892
  className: `squisq-ascii-timeline-point squisq-ascii-timeline-point--${side}${draggedPoint ? " squisq-ascii-timeline-point--dragging" : ""}`,
26714
26893
  style: { left: `${position * 100}%` },
26715
26894
  children: [
26716
- event.callout !== false ? /* @__PURE__ */ jsx51(
26895
+ event.callout !== false ? /* @__PURE__ */ jsx52(
26717
26896
  "span",
26718
26897
  {
26719
26898
  className: `squisq-ascii-timeline-callout squisq-ascii-timeline-callout--${side}`,
26720
26899
  children: event.label
26721
26900
  }
26722
26901
  ) : null,
26723
- event.callout !== false && event.description ? /* @__PURE__ */ jsx51(
26902
+ event.callout !== false && event.description ? /* @__PURE__ */ jsx52(
26724
26903
  "span",
26725
26904
  {
26726
26905
  className: `squisq-ascii-timeline-description squisq-ascii-timeline-description--${descriptionSide}`,
26727
26906
  children: event.description
26728
26907
  }
26729
26908
  ) : null,
26730
- /* @__PURE__ */ jsx51(
26909
+ /* @__PURE__ */ jsx52(
26731
26910
  "button",
26732
26911
  {
26733
26912
  type: "button",
@@ -26837,7 +27016,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26837
27016
  event.id
26838
27017
  );
26839
27018
  }),
26840
- track.endLabel ? /* @__PURE__ */ jsx51("span", { className: "squisq-ascii-timeline-end-label", children: track.endLabel }) : null
27019
+ track.endLabel ? /* @__PURE__ */ jsx52("span", { className: "squisq-ascii-timeline-end-label", children: track.endLabel }) : null
26841
27020
  ]
26842
27021
  }
26843
27022
  )
@@ -26846,13 +27025,13 @@ function TimelineEditorWidget({ editor, blockId }) {
26846
27025
  ]
26847
27026
  }
26848
27027
  ),
26849
- view.timeline.links.length > 0 ? /* @__PURE__ */ jsx51("ul", { className: "squisq-ascii-timeline-link-list", "aria-label": "Timeline branches", children: view.timeline.links.map((link, index2) => /* @__PURE__ */ jsxs40("li", { children: [
27028
+ view.timeline.links.length > 0 ? /* @__PURE__ */ jsx52("ul", { className: "squisq-ascii-timeline-link-list", "aria-label": "Timeline branches", children: view.timeline.links.map((link, index2) => /* @__PURE__ */ jsxs40("li", { children: [
26850
27029
  link.source,
26851
27030
  " \u2192 ",
26852
27031
  link.target,
26853
27032
  link.label ? `: ${link.label}` : ""
26854
27033
  ] }, `${link.source}-${link.target}-${index2}`)) }) : null,
26855
- selected ? /* @__PURE__ */ jsx51(
27034
+ selected ? /* @__PURE__ */ jsx52(
26856
27035
  EventInspector,
26857
27036
  {
26858
27037
  selected,
@@ -26874,7 +27053,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26874
27053
  "Visual editing paused: this timeline contains source the canvas cannot safely rewrite. Repair it in Source view first.",
26875
27054
  view.warnings.length > 0 ? ` (${view.warnings.length} parser note${view.warnings.length === 1 ? "" : "s"})` : ""
26876
27055
  ] }) : null,
26877
- /* @__PURE__ */ jsx51("div", { className: "squisq-sr-only", "aria-live": "polite", children: announcement })
27056
+ /* @__PURE__ */ jsx52("div", { className: "squisq-sr-only", "aria-live": "polite", children: announcement })
26878
27057
  ]
26879
27058
  }
26880
27059
  );
@@ -26888,8 +27067,8 @@ function InlineTrackLabel({
26888
27067
  onStart,
26889
27068
  onFinish
26890
27069
  }) {
26891
- const [draft, setDraft] = useState44(label);
26892
- useEffect34(() => {
27070
+ const [draft, setDraft] = useState45(label);
27071
+ useEffect35(() => {
26893
27072
  if (editing) setDraft(label);
26894
27073
  }, [editing, label]);
26895
27074
  const commitLabel = () => {
@@ -26902,8 +27081,8 @@ function InlineTrackLabel({
26902
27081
  }
26903
27082
  onFinish();
26904
27083
  };
26905
- if (!editable) return /* @__PURE__ */ jsx51("span", { className: "squisq-ascii-timeline-track-name", children: label });
26906
- return editing ? /* @__PURE__ */ jsx51(
27084
+ if (!editable) return /* @__PURE__ */ jsx52("span", { className: "squisq-ascii-timeline-track-name", children: label });
27085
+ return editing ? /* @__PURE__ */ jsx52(
26907
27086
  "input",
26908
27087
  {
26909
27088
  className: "squisq-ascii-timeline-track-name-input",
@@ -26926,7 +27105,7 @@ function InlineTrackLabel({
26926
27105
  }
26927
27106
  }
26928
27107
  }
26929
- ) : /* @__PURE__ */ jsx51(
27108
+ ) : /* @__PURE__ */ jsx52(
26930
27109
  "button",
26931
27110
  {
26932
27111
  type: "button",
@@ -26946,10 +27125,10 @@ function EventInspector({
26946
27125
  onDelete
26947
27126
  }) {
26948
27127
  const { event } = selected;
26949
- const [label, setLabel] = useState44(event.label);
26950
- const [description, setDescription] = useState44(event.description ?? "");
26951
- useEffect34(() => setLabel(event.label), [event.label]);
26952
- useEffect34(() => setDescription(event.description ?? ""), [event.description]);
27128
+ const [label, setLabel] = useState45(event.label);
27129
+ const [description, setDescription] = useState45(event.description ?? "");
27130
+ useEffect35(() => setLabel(event.label), [event.label]);
27131
+ useEffect35(() => setDescription(event.description ?? ""), [event.description]);
26953
27132
  const update = (patch) => dispatch(patch);
26954
27133
  const commitLabel = () => {
26955
27134
  const next = label.trim();
@@ -26976,11 +27155,11 @@ function EventInspector({
26976
27155
  return /* @__PURE__ */ jsxs40("fieldset", { className: "squisq-ascii-timeline-inspector", disabled: !editable, children: [
26977
27156
  /* @__PURE__ */ jsxs40("legend", { children: [
26978
27157
  "Edit point ",
26979
- /* @__PURE__ */ jsx51("span", { children: selected.trackLabel })
27158
+ /* @__PURE__ */ jsx52("span", { children: selected.trackLabel })
26980
27159
  ] }),
26981
27160
  /* @__PURE__ */ jsxs40("label", { children: [
26982
- /* @__PURE__ */ jsx51("span", { children: "Label" }),
26983
- /* @__PURE__ */ jsx51(
27161
+ /* @__PURE__ */ jsx52("span", { children: "Label" }),
27162
+ /* @__PURE__ */ jsx52(
26984
27163
  "input",
26985
27164
  {
26986
27165
  value: label,
@@ -27000,8 +27179,8 @@ function EventInspector({
27000
27179
  )
27001
27180
  ] }),
27002
27181
  /* @__PURE__ */ jsxs40("label", { className: "squisq-ascii-timeline-inspector-description", children: [
27003
- /* @__PURE__ */ jsx51("span", { children: "Callout text" }),
27004
- /* @__PURE__ */ jsx51(
27182
+ /* @__PURE__ */ jsx52("span", { children: "Callout text" }),
27183
+ /* @__PURE__ */ jsx52(
27005
27184
  "textarea",
27006
27185
  {
27007
27186
  rows: 2,
@@ -27022,7 +27201,7 @@ function EventInspector({
27022
27201
  )
27023
27202
  ] }),
27024
27203
  /* @__PURE__ */ jsxs40("label", { children: [
27025
- /* @__PURE__ */ jsx51("span", { children: "Label side" }),
27204
+ /* @__PURE__ */ jsx52("span", { children: "Label side" }),
27026
27205
  /* @__PURE__ */ jsxs40(
27027
27206
  "select",
27028
27207
  {
@@ -27033,14 +27212,14 @@ function EventInspector({
27033
27212
  patch: { side: event_.target.value }
27034
27213
  }),
27035
27214
  children: [
27036
- /* @__PURE__ */ jsx51("option", { value: "above", children: "Above" }),
27037
- /* @__PURE__ */ jsx51("option", { value: "below", children: "Below" })
27215
+ /* @__PURE__ */ jsx52("option", { value: "above", children: "Above" }),
27216
+ /* @__PURE__ */ jsx52("option", { value: "below", children: "Below" })
27038
27217
  ]
27039
27218
  }
27040
27219
  )
27041
27220
  ] }),
27042
27221
  /* @__PURE__ */ jsxs40("label", { children: [
27043
- /* @__PURE__ */ jsx51("span", { children: "Marker" }),
27222
+ /* @__PURE__ */ jsx52("span", { children: "Marker" }),
27044
27223
  /* @__PURE__ */ jsxs40(
27045
27224
  "select",
27046
27225
  {
@@ -27051,15 +27230,15 @@ function EventInspector({
27051
27230
  patch: { marker: event_.target.value }
27052
27231
  }),
27053
27232
  children: [
27054
- /* @__PURE__ */ jsx51("option", { value: "filled", children: "Filled dot" }),
27055
- /* @__PURE__ */ jsx51("option", { value: "hollow", children: "Hollow dot" }),
27056
- /* @__PURE__ */ jsx51("option", { value: "diamond", children: "Diamond" })
27233
+ /* @__PURE__ */ jsx52("option", { value: "filled", children: "Filled dot" }),
27234
+ /* @__PURE__ */ jsx52("option", { value: "hollow", children: "Hollow dot" }),
27235
+ /* @__PURE__ */ jsx52("option", { value: "diamond", children: "Diamond" })
27057
27236
  ]
27058
27237
  }
27059
27238
  )
27060
27239
  ] }),
27061
27240
  /* @__PURE__ */ jsxs40("label", { className: "squisq-ascii-timeline-checkbox", children: [
27062
- /* @__PURE__ */ jsx51(
27241
+ /* @__PURE__ */ jsx52(
27063
27242
  "input",
27064
27243
  {
27065
27244
  type: "checkbox",
@@ -27071,7 +27250,7 @@ function EventInspector({
27071
27250
  })
27072
27251
  }
27073
27252
  ),
27074
- /* @__PURE__ */ jsx51("span", { children: "Show callout" })
27253
+ /* @__PURE__ */ jsx52("span", { children: "Show callout" })
27075
27254
  ] }),
27076
27255
  /* @__PURE__ */ jsxs40(
27077
27256
  "button",
@@ -27082,7 +27261,7 @@ function EventInspector({
27082
27261
  title: canDelete ? "Delete point" : "A timeline needs at least one point",
27083
27262
  onClick: onDelete,
27084
27263
  children: [
27085
- /* @__PURE__ */ jsx51(Icon, { icon: "fa-solid fa-trash" }),
27264
+ /* @__PURE__ */ jsx52(Icon, { icon: "fa-solid fa-trash" }),
27086
27265
  " Delete point"
27087
27266
  ]
27088
27267
  }
@@ -27116,7 +27295,7 @@ function navigateTrackPoints(event) {
27116
27295
  }
27117
27296
 
27118
27297
  // src/timeline/TimelineViewExtension.ts
27119
- var TIMELINE_VIEW_KEY = new PluginKey8("squisq-timeline-view");
27298
+ var TIMELINE_VIEW_KEY = new PluginKey9("squisq-timeline-view");
27120
27299
  var detectCache3 = /* @__PURE__ */ new WeakMap();
27121
27300
  var parseCache3 = /* @__PURE__ */ new WeakMap();
27122
27301
  function fenceLangOf4(node2) {
@@ -27161,26 +27340,26 @@ function parseTimelineForNode(node2) {
27161
27340
  function findTimelineBlockPos(editor, blockId) {
27162
27341
  return TIMELINE_VIEW_KEY.getState(editor.state)?.entries.find((entry) => entry.id === blockId)?.pos ?? null;
27163
27342
  }
27164
- function buildDecorations7(doc, entries, editor) {
27343
+ function buildDecorations8(doc, entries, editor) {
27165
27344
  const decorations = [];
27166
27345
  for (const entry of entries) {
27167
27346
  const node2 = doc.nodeAt(entry.pos);
27168
27347
  if (!node2 || node2.type.name !== "codeBlock") continue;
27169
27348
  decorations.push(
27170
- Decoration8.node(entry.pos, entry.pos + node2.nodeSize, {
27349
+ Decoration9.node(entry.pos, entry.pos + node2.nodeSize, {
27171
27350
  class: "squisq-ascii-timeline-fence-hidden"
27172
27351
  })
27173
27352
  );
27174
27353
  decorations.push(
27175
- Decoration8.widget(
27354
+ Decoration9.widget(
27176
27355
  entry.pos + node2.nodeSize,
27177
27356
  () => {
27178
27357
  const container = document.createElement("div");
27179
27358
  container.className = "squisq-ascii-timeline-widget-host";
27180
27359
  container.contentEditable = "false";
27181
27360
  containFenceWidgetEvents(container);
27182
- const root = createRoot6(container);
27183
- root.render(createElement12(TimelineEditorWidget, { editor, blockId: entry.id }));
27361
+ const root = createRoot7(container);
27362
+ root.render(createElement13(TimelineEditorWidget, { editor, blockId: entry.id }));
27184
27363
  container.__squisqTimelineRoot = root;
27185
27364
  return container;
27186
27365
  },
@@ -27196,9 +27375,9 @@ function buildDecorations7(doc, entries, editor) {
27196
27375
  )
27197
27376
  );
27198
27377
  }
27199
- return DecorationSet8.create(doc, decorations);
27378
+ return DecorationSet9.create(doc, decorations);
27200
27379
  }
27201
- function applyState6(tr, previous, editor, doc) {
27380
+ function applyState7(tr, previous, editor, doc) {
27202
27381
  if (!tr.docChanged) return previous;
27203
27382
  const mapped = mapFenceEntries(tr, previous.entries, doc);
27204
27383
  let seq = previous.seq;
@@ -27211,9 +27390,9 @@ function applyState6(tr, previous, editor, doc) {
27211
27390
  entries.push({ id: knownId ?? `timeline-${++seq}`, pos });
27212
27391
  return false;
27213
27392
  });
27214
- return { entries, seq, decorations: buildDecorations7(doc, entries, editor) };
27393
+ return { entries, seq, decorations: buildDecorations8(doc, entries, editor) };
27215
27394
  }
27216
- var TimelineViewExtension = Extension8.create({
27395
+ var TimelineViewExtension = Extension9.create({
27217
27396
  name: "squisqTimelineView",
27218
27397
  addOptions() {
27219
27398
  return { enabled: true };
@@ -27222,7 +27401,7 @@ var TimelineViewExtension = Extension8.create({
27222
27401
  const editor = this.editor;
27223
27402
  if (this.options.enabled === false) return [];
27224
27403
  return [
27225
- new Plugin8({
27404
+ new Plugin9({
27226
27405
  key: TIMELINE_VIEW_KEY,
27227
27406
  state: {
27228
27407
  init: (_config, state) => {
@@ -27237,14 +27416,14 @@ var TimelineViewExtension = Extension8.create({
27237
27416
  return {
27238
27417
  entries,
27239
27418
  seq,
27240
- decorations: buildDecorations7(state.doc, entries, editor)
27419
+ decorations: buildDecorations8(state.doc, entries, editor)
27241
27420
  };
27242
27421
  },
27243
- apply: (tr, previous, _oldState, newState) => applyState6(tr, previous, editor, newState.doc)
27422
+ apply: (tr, previous, _oldState, newState) => applyState7(tr, previous, editor, newState.doc)
27244
27423
  },
27245
27424
  props: {
27246
27425
  decorations(state) {
27247
- return this.getState(state)?.decorations ?? DecorationSet8.empty;
27426
+ return this.getState(state)?.decorations ?? DecorationSet9.empty;
27248
27427
  }
27249
27428
  }
27250
27429
  })
@@ -27254,9 +27433,9 @@ var TimelineViewExtension = Extension8.create({
27254
27433
 
27255
27434
  // src/timeline/timelineData.ts
27256
27435
  function useTimelineData(editor, blockId) {
27257
- const [version, setVersion] = useState45(0);
27436
+ const [version, setVersion] = useState46(0);
27258
27437
  const dataCache = useRef37(null);
27259
- useEffect35(() => {
27438
+ useEffect36(() => {
27260
27439
  const onEditorChange = () => setVersion((value) => value + 1);
27261
27440
  editor.on("transaction", onEditorChange);
27262
27441
  editor.on("update", onEditorChange);
@@ -27265,7 +27444,7 @@ function useTimelineData(editor, blockId) {
27265
27444
  editor.off("update", onEditorChange);
27266
27445
  };
27267
27446
  }, [editor]);
27268
- return useMemo34(() => {
27447
+ return useMemo35(() => {
27269
27448
  const pos = findTimelineBlockPos(editor, blockId);
27270
27449
  if (pos === null) return null;
27271
27450
  const node2 = editor.state.doc.nodeAt(pos);
@@ -27291,9 +27470,9 @@ function shouldPasteAsTimelineFence(text) {
27291
27470
  }
27292
27471
 
27293
27472
  // src/BlockPropertiesPopover.tsx
27294
- import { useEffect as useEffect36, useId as useId13, useRef as useRef38, useState as useState46 } from "react";
27473
+ import { useEffect as useEffect37, useId as useId13, useRef as useRef38, useState as useState47 } from "react";
27295
27474
  import { createPortal as createPortal9 } from "react-dom";
27296
- import { jsx as jsx52, jsxs as jsxs41 } from "react/jsx-runtime";
27475
+ import { jsx as jsx53, jsxs as jsxs41 } from "react/jsx-runtime";
27297
27476
  var TRANSITION_FLYOUT = ".squisq-transition-flyout";
27298
27477
  function BlockPropertiesPopover({
27299
27478
  anchorRect,
@@ -27307,13 +27486,13 @@ function BlockPropertiesPopover({
27307
27486
  }) {
27308
27487
  const panelRef = useRef38(null);
27309
27488
  const panelId = `squisq-block-props-portal-${useId13().replace(/:/g, "")}`;
27310
- const [inner, setInner] = useState46(blockAttrs);
27311
- const [templateInner, setTemplateInner] = useState46(templateParams);
27312
- const [style, setStyle] = useState46(() => computeStyle(anchorRect));
27313
- useEffect36(() => {
27489
+ const [inner, setInner] = useState47(blockAttrs);
27490
+ const [templateInner, setTemplateInner] = useState47(templateParams);
27491
+ const [style, setStyle] = useState47(() => computeStyle(anchorRect));
27492
+ useEffect37(() => {
27314
27493
  requestAnimationFrame(() => setStyle(computeStyle(anchorRect, panelRef.current)));
27315
27494
  }, [anchorRect]);
27316
- useEffect36(() => {
27495
+ useEffect37(() => {
27317
27496
  const onKey = (e2) => {
27318
27497
  if (e2.key === "Escape") onClose();
27319
27498
  };
@@ -27359,8 +27538,8 @@ function BlockPropertiesPopover({
27359
27538
  style: { ...style, ...blockAccentStyle2(accentColor) },
27360
27539
  children: [
27361
27540
  /* @__PURE__ */ jsxs41("div", { className: "squisq-block-props-row", children: [
27362
- /* @__PURE__ */ jsx52("span", { className: "squisq-block-props-label", children: "Transition" }),
27363
- /* @__PURE__ */ jsx52(
27541
+ /* @__PURE__ */ jsx53("span", { className: "squisq-block-props-label", children: "Transition" }),
27542
+ /* @__PURE__ */ jsx53(
27364
27543
  TransitionPicker,
27365
27544
  {
27366
27545
  value: transition,
@@ -27371,8 +27550,8 @@ function BlockPropertiesPopover({
27371
27550
  )
27372
27551
  ] }),
27373
27552
  /* @__PURE__ */ jsxs41("div", { className: "squisq-block-props-row", children: [
27374
- /* @__PURE__ */ jsx52("span", { className: "squisq-block-props-label", children: "Duration" }),
27375
- /* @__PURE__ */ jsx52(
27553
+ /* @__PURE__ */ jsx53("span", { className: "squisq-block-props-label", children: "Duration" }),
27554
+ /* @__PURE__ */ jsx53(
27376
27555
  NumberField,
27377
27556
  {
27378
27557
  value: duration,
@@ -27384,8 +27563,8 @@ function BlockPropertiesPopover({
27384
27563
  )
27385
27564
  ] }),
27386
27565
  /* @__PURE__ */ jsxs41("div", { className: "squisq-block-props-row", children: [
27387
- /* @__PURE__ */ jsx52("span", { className: "squisq-block-props-label", children: "Start time" }),
27388
- /* @__PURE__ */ jsx52(
27566
+ /* @__PURE__ */ jsx53("span", { className: "squisq-block-props-label", children: "Start time" }),
27567
+ /* @__PURE__ */ jsx53(
27389
27568
  NumberField,
27390
27569
  {
27391
27570
  value: startTime,
@@ -27413,7 +27592,7 @@ function NumberField({
27413
27592
  onChange
27414
27593
  }) {
27415
27594
  return /* @__PURE__ */ jsxs41("div", { className: "squisq-block-props-numfield", children: [
27416
- /* @__PURE__ */ jsx52(
27595
+ /* @__PURE__ */ jsx53(
27417
27596
  "input",
27418
27597
  {
27419
27598
  type: "number",
@@ -27426,7 +27605,7 @@ function NumberField({
27426
27605
  "aria-label": ariaLabel
27427
27606
  }
27428
27607
  ),
27429
- /* @__PURE__ */ jsx52("span", { className: "squisq-block-props-unit", children: unit })
27608
+ /* @__PURE__ */ jsx53("span", { className: "squisq-block-props-unit", children: unit })
27430
27609
  ] });
27431
27610
  }
27432
27611
  function computeStyle(rect, element) {
@@ -27475,7 +27654,7 @@ function persistFromWrite(bodyMd, state) {
27475
27654
  }
27476
27655
 
27477
27656
  // src/WysiwygEditor.tsx
27478
- import { useCallback as useCallback38, useEffect as useEffect40, useMemo as useMemo35, useRef as useRef40, useState as useState50 } from "react";
27657
+ import { useCallback as useCallback38, useEffect as useEffect41, useMemo as useMemo36, useRef as useRef40, useState as useState51 } from "react";
27479
27658
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
27480
27659
  import { Selection } from "@tiptap/pm/state";
27481
27660
  import StarterKit2 from "@tiptap/starter-kit";
@@ -27509,13 +27688,16 @@ function createMermaidThemeStore(initialTheme) {
27509
27688
  };
27510
27689
  }
27511
27690
 
27691
+ // src/WysiwygEditor.tsx
27692
+ import { fenceRendererLangs } from "@bendyline/squisq/fence";
27693
+
27512
27694
  // src/blockTagActivity.ts
27513
- import { Extension as Extension9 } from "@tiptap/core";
27514
- import { Plugin as Plugin9, PluginKey as PluginKey9 } from "@tiptap/pm/state";
27515
- import { Decoration as Decoration9, DecorationSet as DecorationSet9 } from "@tiptap/pm/view";
27695
+ import { Extension as Extension10 } from "@tiptap/core";
27696
+ import { Plugin as Plugin10, PluginKey as PluginKey10 } from "@tiptap/pm/state";
27697
+ import { Decoration as Decoration10, DecorationSet as DecorationSet10 } from "@tiptap/pm/view";
27516
27698
  var BLOCK_TAG_SELECTED_CLASS = "squisq-block-tags--selected";
27517
27699
  var BLOCK_TAG_HOVERED_CLASS = "squisq-block-tags--hovered";
27518
- var BLOCK_TAG_ACTIVITY_KEY = new PluginKey9(
27700
+ var BLOCK_TAG_ACTIVITY_KEY = new PluginKey10(
27519
27701
  "squisq-block-tag-activity"
27520
27702
  );
27521
27703
  function isHeadingElement(element) {
@@ -27565,7 +27747,7 @@ function validHeadingPosition(doc, position) {
27565
27747
  if (position === null) return null;
27566
27748
  return doc.nodeAt(position)?.type.name === "heading" ? position : null;
27567
27749
  }
27568
- function buildDecorations8(doc, selectedPosition, hoveredPosition) {
27750
+ function buildDecorations9(doc, selectedPosition, hoveredPosition) {
27569
27751
  const classesByPosition = /* @__PURE__ */ new Map();
27570
27752
  if (selectedPosition !== null) {
27571
27753
  classesByPosition.set(selectedPosition, [BLOCK_TAG_SELECTED_CLASS]);
@@ -27580,10 +27762,10 @@ function buildDecorations8(doc, selectedPosition, hoveredPosition) {
27580
27762
  const node2 = doc.nodeAt(position);
27581
27763
  if (!node2 || node2.type.name !== "heading") continue;
27582
27764
  decorations.push(
27583
- Decoration9.node(position, position + node2.nodeSize, { class: classes.join(" ") })
27765
+ Decoration10.node(position, position + node2.nodeSize, { class: classes.join(" ") })
27584
27766
  );
27585
27767
  }
27586
- return decorations.length > 0 ? DecorationSet9.create(doc, decorations) : DecorationSet9.empty;
27768
+ return decorations.length > 0 ? DecorationSet10.create(doc, decorations) : DecorationSet10.empty;
27587
27769
  }
27588
27770
  function createPluginState(doc, selectionFrom, hoveredPosition) {
27589
27771
  const selectedPosition = findOwningHeadingPosition(doc, selectionFrom);
@@ -27591,7 +27773,7 @@ function createPluginState(doc, selectionFrom, hoveredPosition) {
27591
27773
  return {
27592
27774
  selectedPosition,
27593
27775
  hoveredPosition: validHoveredPosition,
27594
- decorations: buildDecorations8(doc, selectedPosition, validHoveredPosition)
27776
+ decorations: buildDecorations9(doc, selectedPosition, validHoveredPosition)
27595
27777
  };
27596
27778
  }
27597
27779
  function nextHoveredPosition(transaction, previousPosition, doc) {
@@ -27618,11 +27800,11 @@ function setHoveredPosition(view, hoveredPosition) {
27618
27800
  view.state.tr.setMeta(BLOCK_TAG_ACTIVITY_KEY, { hoveredPosition }).setMeta("addToHistory", false)
27619
27801
  );
27620
27802
  }
27621
- var BlockTagActivityExtension = Extension9.create({
27803
+ var BlockTagActivityExtension = Extension10.create({
27622
27804
  name: "squisqBlockTagActivity",
27623
27805
  addProseMirrorPlugins() {
27624
27806
  return [
27625
- new Plugin9({
27807
+ new Plugin10({
27626
27808
  key: BLOCK_TAG_ACTIVITY_KEY,
27627
27809
  state: {
27628
27810
  init: (_config, state) => createPluginState(state.doc, state.selection.from, null),
@@ -27634,7 +27816,7 @@ var BlockTagActivityExtension = Extension9.create({
27634
27816
  },
27635
27817
  props: {
27636
27818
  decorations(state) {
27637
- return this.getState(state)?.decorations ?? DecorationSet9.empty;
27819
+ return this.getState(state)?.decorations ?? DecorationSet10.empty;
27638
27820
  },
27639
27821
  handleDOMEvents: {
27640
27822
  mouseover(view, event) {
@@ -27708,7 +27890,7 @@ var InlineIcon = Node2.create({
27708
27890
  });
27709
27891
 
27710
27892
  // src/ImageNodeView.tsx
27711
- import { useEffect as useEffect37, useRef as useRef39, useState as useState47 } from "react";
27893
+ import { useEffect as useEffect38, useRef as useRef39, useState as useState48 } from "react";
27712
27894
  import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
27713
27895
  import Image from "@tiptap/extension-image";
27714
27896
 
@@ -27724,20 +27906,20 @@ function normalizeMalformedAssetUrl(src) {
27724
27906
  }
27725
27907
 
27726
27908
  // src/ImageNodeView.tsx
27727
- import { Fragment as Fragment16, jsx as jsx53, jsxs as jsxs42 } from "react/jsx-runtime";
27909
+ import { Fragment as Fragment16, jsx as jsx54, jsxs as jsxs42 } from "react/jsx-runtime";
27728
27910
  function ImageComponent({ node: node2, selected, editor, updateAttributes }) {
27729
27911
  const { src, alt, title, width } = node2.attrs;
27730
27912
  const { mediaProvider, imageDisplayMode, openImageEdit, mediaRevision } = useEditorContext();
27731
- const [resolvedSrc, setResolvedSrc] = useState47(src);
27732
- const [hovered, setHovered] = useState47(false);
27913
+ const [resolvedSrc, setResolvedSrc] = useState48(src);
27914
+ const [hovered, setHovered] = useState48(false);
27733
27915
  const imgRef = useRef39(null);
27734
- const [previewWidth, setPreviewWidth] = useState47(null);
27916
+ const [previewWidth, setPreviewWidth] = useState48(null);
27735
27917
  const isThumbnail = imageDisplayMode === "thumbnail";
27736
27918
  const isEditable = editor?.isEditable ?? true;
27737
27919
  const normalizedRelativePath = normalizeMalformedAssetUrl(src);
27738
27920
  const isRelative = src && !src.startsWith("blob:") && !src.startsWith("http") && !src.startsWith("data:") && !src.startsWith("/");
27739
27921
  const resolveAs = normalizedRelativePath ?? (isRelative ? src : null);
27740
- useEffect37(() => {
27922
+ useEffect38(() => {
27741
27923
  if (!mediaProvider || !resolveAs) {
27742
27924
  setResolvedSrc(src);
27743
27925
  return;
@@ -27818,7 +28000,7 @@ function ImageComponent({ node: node2, selected, editor, updateAttributes }) {
27818
28000
  onMouseEnter: () => setHovered(true),
27819
28001
  onMouseLeave: () => setHovered(false),
27820
28002
  children: [
27821
- /* @__PURE__ */ jsx53(
28003
+ /* @__PURE__ */ jsx54(
27822
28004
  "img",
27823
28005
  {
27824
28006
  ref: imgRef,
@@ -27847,13 +28029,13 @@ function ImageComponent({ node: node2, selected, editor, updateAttributes }) {
27847
28029
  title: "Edit image",
27848
28030
  "aria-label": `Edit image ${alt || src}`,
27849
28031
  children: [
27850
- /* @__PURE__ */ jsx53("span", { "aria-hidden": "true", style: { fontSize: "0.95em", lineHeight: 1 }, children: "\u270E" }),
27851
- /* @__PURE__ */ jsx53("span", { children: "Edit" })
28032
+ /* @__PURE__ */ jsx54("span", { "aria-hidden": "true", style: { fontSize: "0.95em", lineHeight: 1 }, children: "\u270E" }),
28033
+ /* @__PURE__ */ jsx54("span", { children: "Edit" })
27852
28034
  ]
27853
28035
  }
27854
28036
  ),
27855
28037
  showResize && /* @__PURE__ */ jsxs42(Fragment16, { children: [
27856
- /* @__PURE__ */ jsx53(
28038
+ /* @__PURE__ */ jsx54(
27857
28039
  "span",
27858
28040
  {
27859
28041
  className: "squisq-image-resize-handle",
@@ -27916,15 +28098,15 @@ var ImageWithMediaProvider = Image.extend({
27916
28098
  // src/tiptap/TiptapVideo.tsx
27917
28099
  import { Node as Node3, mergeAttributes as mergeAttributes2 } from "@tiptap/core";
27918
28100
  import { NodeViewWrapper as NodeViewWrapper2, ReactNodeViewRenderer as ReactNodeViewRenderer2 } from "@tiptap/react";
27919
- import { useEffect as useEffect39, useState as useState49 } from "react";
28101
+ import { useEffect as useEffect40, useState as useState50 } from "react";
27920
28102
 
27921
28103
  // src/tiptap/useResolvedMediaSrc.ts
27922
- import { useEffect as useEffect38, useState as useState48 } from "react";
28104
+ import { useEffect as useEffect39, useState as useState49 } from "react";
27923
28105
  function useResolvedMediaSrc(src) {
27924
28106
  const { mediaProvider, mediaRevision } = useEditorContext();
27925
- const [resolved, setResolved] = useState48(src);
28107
+ const [resolved, setResolved] = useState49(src);
27926
28108
  const isRelative = !!src && !src.startsWith("blob:") && !src.startsWith("http:") && !src.startsWith("https:") && !src.startsWith("data:") && !src.startsWith("/");
27927
- useEffect38(() => {
28109
+ useEffect39(() => {
27928
28110
  if (!mediaProvider || !isRelative) {
27929
28111
  setResolved(src);
27930
28112
  return;
@@ -27946,7 +28128,7 @@ function useResolvedMediaSrc(src) {
27946
28128
  }
27947
28129
 
27948
28130
  // src/tiptap/TiptapVideo.tsx
27949
- import { jsx as jsx54, jsxs as jsxs43 } from "react/jsx-runtime";
28131
+ import { jsx as jsx55, jsxs as jsxs43 } from "react/jsx-runtime";
27950
28132
  var PLACEMENT_OPTIONS = [
27951
28133
  { value: "content", label: "In layout", title: "Participate in the block content layout" },
27952
28134
  {
@@ -27975,9 +28157,9 @@ function VideoNodeView({ node: node2, updateAttributes, selected }) {
27975
28157
  const placement = normalizeVideoPlacement(rawPlacement);
27976
28158
  const lockToBlock = normalizeLockToBlock(rawLockToBlock);
27977
28159
  const resolvedSrc = useResolvedMediaSrc(src ?? "");
27978
- const [audioOnly, setAudioOnly] = useState49(false);
28160
+ const [audioOnly, setAudioOnly] = useState50(false);
27979
28161
  const resolvedPoster = useResolvedMediaSrc(poster ?? "");
27980
- useEffect39(() => {
28162
+ useEffect40(() => {
27981
28163
  setAudioOnly(false);
27982
28164
  }, [resolvedSrc]);
27983
28165
  const handleLoadedMetadata = (event) => {
@@ -27999,8 +28181,8 @@ function VideoNodeView({ node: node2, updateAttributes, selected }) {
27999
28181
  "aria-label": "Video placement",
28000
28182
  contentEditable: false,
28001
28183
  children: [
28002
- /* @__PURE__ */ jsx54("span", { className: "squisq-video-placement-label", children: "Video" }),
28003
- PLACEMENT_OPTIONS.map((option) => /* @__PURE__ */ jsx54(
28184
+ /* @__PURE__ */ jsx55("span", { className: "squisq-video-placement-label", children: "Video" }),
28185
+ PLACEMENT_OPTIONS.map((option) => /* @__PURE__ */ jsx55(
28004
28186
  "button",
28005
28187
  {
28006
28188
  type: "button",
@@ -28013,7 +28195,7 @@ function VideoNodeView({ node: node2, updateAttributes, selected }) {
28013
28195
  },
28014
28196
  option.value
28015
28197
  )),
28016
- placement !== "content" && /* @__PURE__ */ jsx54(
28198
+ placement !== "content" && /* @__PURE__ */ jsx55(
28017
28199
  "button",
28018
28200
  {
28019
28201
  type: "button",
@@ -28029,7 +28211,7 @@ function VideoNodeView({ node: node2, updateAttributes, selected }) {
28029
28211
  ]
28030
28212
  }
28031
28213
  ),
28032
- audioOnly ? /* @__PURE__ */ jsx54(
28214
+ audioOnly ? /* @__PURE__ */ jsx55(
28033
28215
  "audio",
28034
28216
  {
28035
28217
  "data-drag-handle": true,
@@ -28038,7 +28220,7 @@ function VideoNodeView({ node: node2, updateAttributes, selected }) {
28038
28220
  controls,
28039
28221
  preload: "metadata"
28040
28222
  }
28041
- ) : /* @__PURE__ */ jsx54(
28223
+ ) : /* @__PURE__ */ jsx55(
28042
28224
  "video",
28043
28225
  {
28044
28226
  "data-drag-handle": true,
@@ -28157,11 +28339,11 @@ var TiptapVideo = Node3.create({
28157
28339
  // src/tiptap/TiptapAudio.tsx
28158
28340
  import { Node as Node4, mergeAttributes as mergeAttributes3 } from "@tiptap/core";
28159
28341
  import { NodeViewWrapper as NodeViewWrapper3, ReactNodeViewRenderer as ReactNodeViewRenderer3 } from "@tiptap/react";
28160
- import { jsx as jsx55 } from "react/jsx-runtime";
28342
+ import { jsx as jsx56 } from "react/jsx-runtime";
28161
28343
  function AudioNodeView({ node: node2 }) {
28162
28344
  const { src, controls } = node2.attrs;
28163
28345
  const resolvedSrc = useResolvedMediaSrc(src ?? "");
28164
- return /* @__PURE__ */ jsx55(NodeViewWrapper3, { as: "span", className: "squisq-inline-audio-player", "data-drag-handle": true, draggable: true, children: /* @__PURE__ */ jsx55("audio", { src: resolvedSrc || void 0, controls, preload: "metadata" }) });
28346
+ return /* @__PURE__ */ jsx56(NodeViewWrapper3, { as: "span", className: "squisq-inline-audio-player", "data-drag-handle": true, draggable: true, children: /* @__PURE__ */ jsx56("audio", { src: resolvedSrc || void 0, controls, preload: "metadata" }) });
28165
28347
  }
28166
28348
  var TiptapAudio = Node4.create({
28167
28349
  name: "audio",
@@ -28222,7 +28404,7 @@ import { profileBlockContents as profileBlockContents2, recommendTemplatesForBlo
28222
28404
 
28223
28405
  // src/MentionExtension.tsx
28224
28406
  import Mention from "@tiptap/extension-mention";
28225
- import { PluginKey as PluginKey10 } from "@tiptap/pm/state";
28407
+ import { PluginKey as PluginKey11 } from "@tiptap/pm/state";
28226
28408
  var FALLBACK_KIND = "mention";
28227
28409
  function buildMentionExtension(getProvider) {
28228
28410
  return Mention.configure({
@@ -28278,7 +28460,7 @@ function buildMentionExtension(getProvider) {
28278
28460
  char: "@",
28279
28461
  // Custom plugin key so the mention suggestion doesn't collide
28280
28462
  // with any future `:` or `/` popovers.
28281
- pluginKey: new PluginKey10("mentionSuggestion"),
28463
+ pluginKey: new PluginKey11("mentionSuggestion"),
28282
28464
  command: ({
28283
28465
  editor,
28284
28466
  range,
@@ -28585,7 +28767,7 @@ function safeFontFamily(value) {
28585
28767
 
28586
28768
  // src/WysiwygEditor.tsx
28587
28769
  import { useEditor as useEditor3 } from "@tiptap/react";
28588
- import { jsx as jsx56, jsxs as jsxs44 } from "react/jsx-runtime";
28770
+ import { jsx as jsx57, jsxs as jsxs44 } from "react/jsx-runtime";
28589
28771
  var LinkWithTitle = Link2.extend({
28590
28772
  addAttributes() {
28591
28773
  return {
@@ -28625,6 +28807,7 @@ function WysiwygEditor({
28625
28807
  setTiptapEditor,
28626
28808
  mediaProvider,
28627
28809
  mentionProvider,
28810
+ fenceRenderers,
28628
28811
  blockTagVisibility,
28629
28812
  themeInheritance,
28630
28813
  colorScheme,
@@ -28643,11 +28826,11 @@ function WysiwygEditor({
28643
28826
  mermaidThemeStoreRef.current = createMermaidThemeStore(activeTheme ?? DEFAULT_THEME4);
28644
28827
  }
28645
28828
  const mermaidThemeStore = mermaidThemeStoreRef.current;
28646
- useEffect40(() => {
28829
+ useEffect41(() => {
28647
28830
  mermaidThemeStore.setTheme(activeTheme ?? DEFAULT_THEME4);
28648
28831
  }, [activeTheme, mermaidThemeStore]);
28649
28832
  const { docTemplates, onDocTemplatesChange } = useDocCustomTemplates();
28650
- const [designerState, setDesignerState] = useState50(
28833
+ const [designerState, setDesignerState] = useState51(
28651
28834
  null
28652
28835
  );
28653
28836
  const handleDesignerSave = useCallback38(
@@ -28663,15 +28846,23 @@ function WysiwygEditor({
28663
28846
  [docTemplates, onDocTemplatesChange]
28664
28847
  );
28665
28848
  const mentionProviderRef = useRef40(mentionProvider);
28666
- useEffect40(() => {
28849
+ useEffect41(() => {
28667
28850
  mentionProviderRef.current = mentionProvider;
28668
28851
  }, [mentionProvider]);
28669
- const resolvedPlaceholder = useMemo35(() => placeholder ?? pickEmptyPrompt(), [placeholder]);
28852
+ const fenceRenderersRef = useRef40(fenceRenderers);
28853
+ useEffect41(() => {
28854
+ fenceRenderersRef.current = fenceRenderers;
28855
+ }, [fenceRenderers]);
28856
+ const activeThemeRef = useRef40(activeTheme);
28857
+ useEffect41(() => {
28858
+ activeThemeRef.current = activeTheme;
28859
+ }, [activeTheme]);
28860
+ const resolvedPlaceholder = useMemo36(() => placeholder ?? pickEmptyPrompt(), [placeholder]);
28670
28861
  const isExternalUpdate = useRef40(false);
28671
28862
  const lastSourceRef = useRef40(editorSource);
28672
28863
  const pendingLocalSourcesRef = useRef40([]);
28673
28864
  const mediaProviderRef = useRef40(mediaProvider);
28674
- useEffect40(() => {
28865
+ useEffect41(() => {
28675
28866
  mediaProviderRef.current = mediaProvider;
28676
28867
  }, [mediaProvider]);
28677
28868
  const frontmatterRef = useRef40(stripFrontmatter(editorSource).frontmatter);
@@ -28688,7 +28879,7 @@ function WysiwygEditor({
28688
28879
  }
28689
28880
  }
28690
28881
  const submitOnEnterRef = useRef40(submitOnEnter);
28691
- useEffect40(() => {
28882
+ useEffect41(() => {
28692
28883
  submitOnEnterRef.current = submitOnEnter;
28693
28884
  }, [submitOnEnter]);
28694
28885
  const editor = useEditor2({
@@ -28705,7 +28896,13 @@ function WysiwygEditor({
28705
28896
  BlockTagActivityExtension,
28706
28897
  AsciiDiagramExtension.configure({ textChannel: sceneTextChannel }),
28707
28898
  MermaidDiagramExtension.configure({ themeStore: mermaidThemeStore }),
28708
- CodeSnippetExtension,
28899
+ CodeSnippetExtension.configure({
28900
+ reservedLanguages: fenceRendererLangs(fenceRenderers ?? void 0)
28901
+ }),
28902
+ HostFenceExtension.configure({
28903
+ renderers: () => fenceRenderersRef.current ?? void 0,
28904
+ theme: () => activeThemeRef.current ?? void 0
28905
+ }),
28709
28906
  RepairableDiagramExtension.configure({ onRepair: applyRepairCommand }),
28710
28907
  TimelineViewExtension,
28711
28908
  TreeViewExtension,
@@ -28870,25 +29067,25 @@ function WysiwygEditor({
28870
29067
  }
28871
29068
  }
28872
29069
  });
28873
- useEffect40(() => {
29070
+ useEffect41(() => {
28874
29071
  if (editor) {
28875
29072
  setTiptapEditor(editor);
28876
29073
  }
28877
29074
  return () => setTiptapEditor(null);
28878
29075
  }, [editor, setTiptapEditor]);
28879
- useEffect40(() => {
29076
+ useEffect41(() => {
28880
29077
  if (editor) editor.setEditable(!readOnly);
28881
29078
  }, [editor, readOnly]);
28882
29079
  const containerRef = useRef40(null);
28883
- const [badgeMenu, setBadgeMenu] = useState50(null);
28884
- const [propsMenu, setPropsMenu] = useState50(null);
29080
+ const [badgeMenu, setBadgeMenu] = useState51(null);
29081
+ const [propsMenu, setPropsMenu] = useState51(null);
28885
29082
  const closeBadgeMenu = useCallback38(() => {
28886
29083
  setBadgeMenu(null);
28887
29084
  requestAnimationFrame(() => {
28888
29085
  if (editor && !editor.isDestroyed) editor.commands.focus();
28889
29086
  });
28890
29087
  }, [editor]);
28891
- useEffect40(() => {
29088
+ useEffect41(() => {
28892
29089
  if (!editor) return;
28893
29090
  const root = containerRef.current;
28894
29091
  if (!root) return;
@@ -28944,7 +29141,7 @@ function WysiwygEditor({
28944
29141
  root.addEventListener("mousedown", onClick);
28945
29142
  return () => root.removeEventListener("mousedown", onClick);
28946
29143
  }, [editor]);
28947
- useEffect40(() => {
29144
+ useEffect41(() => {
28948
29145
  if (!editor) return;
28949
29146
  const pendingIndex = pendingLocalSourcesRef.current.lastIndexOf(editorSource);
28950
29147
  if (pendingIndex >= 0) {
@@ -28976,7 +29173,7 @@ function WysiwygEditor({
28976
29173
  lastSourceRef.current = editorSource;
28977
29174
  isExternalUpdate.current = false;
28978
29175
  }, [editorSource, editor, wrapPolicyEnabled]);
28979
- const badgePreviewSource = useMemo35(() => {
29176
+ const badgePreviewSource = useMemo36(() => {
28980
29177
  if (!badgeMenu) return void 0;
28981
29178
  try {
28982
29179
  const previewDoc = markdownToDoc2(parseMarkdown6(editorSource), { autoTemplates: false });
@@ -29001,7 +29198,7 @@ function WysiwygEditor({
29001
29198
  previewSettings?.activeTheme,
29002
29199
  previewSettings?.activeViewport
29003
29200
  ]);
29004
- const themeStyle = useMemo35(() => {
29201
+ const themeStyle = useMemo36(() => {
29005
29202
  if (!activeTheme) return {};
29006
29203
  const out = {
29007
29204
  "--squisq-block-props-accent": activeTheme.colors.primary
@@ -29027,7 +29224,7 @@ function WysiwygEditor({
29027
29224
  }
29028
29225
  return out;
29029
29226
  }, [activeTheme, themeInheritance]);
29030
- return /* @__PURE__ */ jsx56(CustomTemplateProvider, { docTemplates, onDocTemplatesChange, children: /* @__PURE__ */ jsxs44(
29227
+ return /* @__PURE__ */ jsx57(CustomTemplateProvider, { docTemplates, onDocTemplatesChange, children: /* @__PURE__ */ jsxs44(
29031
29228
  "div",
29032
29229
  {
29033
29230
  className: `squisq-wysiwyg-container${className ? ` ${className}` : ""}`,
@@ -29043,8 +29240,8 @@ function WysiwygEditor({
29043
29240
  "data-theme-inheritance": themeInheritance,
29044
29241
  ref: containerRef,
29045
29242
  children: [
29046
- /* @__PURE__ */ jsx56(EditorContent2, { editor, style: { height: "100%" } }),
29047
- badgeMenu && /* @__PURE__ */ jsx56(
29243
+ /* @__PURE__ */ jsx57(EditorContent2, { editor, style: { height: "100%" } }),
29244
+ badgeMenu && /* @__PURE__ */ jsx57(
29048
29245
  TemplateBadgePopover,
29049
29246
  {
29050
29247
  anchorRect: badgeMenu.rect,
@@ -29072,7 +29269,7 @@ function WysiwygEditor({
29072
29269
  onClose: closeBadgeMenu
29073
29270
  }
29074
29271
  ),
29075
- propsMenu && /* @__PURE__ */ jsx56(
29272
+ propsMenu && /* @__PURE__ */ jsx57(
29076
29273
  BlockPropertiesPopover,
29077
29274
  {
29078
29275
  anchorRect: propsMenu.rect,
@@ -29104,7 +29301,7 @@ function WysiwygEditor({
29104
29301
  onClose: () => setPropsMenu(null)
29105
29302
  }
29106
29303
  ),
29107
- designerState && /* @__PURE__ */ jsx56(
29304
+ designerState && /* @__PURE__ */ jsx57(
29108
29305
  TemplateDesigner,
29109
29306
  {
29110
29307
  initial: designerState.initial,
@@ -29201,7 +29398,7 @@ function moveSelectionToDropPoint(view, event) {
29201
29398
  }
29202
29399
 
29203
29400
  // src/InlinePreviewGutter.tsx
29204
- import { useLayoutEffect as useLayoutEffect8, useMemo as useMemo37, useRef as useRef41, useState as useState52 } from "react";
29401
+ import { useLayoutEffect as useLayoutEffect8, useMemo as useMemo38, useRef as useRef41, useState as useState53 } from "react";
29205
29402
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS4 } from "@bendyline/squisq/schemas";
29206
29403
  import {
29207
29404
  flattenBlocks as flattenBlocks4,
@@ -29213,14 +29410,14 @@ import { extractPlainText as extractPlainText3, getChildren } from "@bendyline/s
29213
29410
  import { BlockRenderer as BlockRenderer3, MediaContext as MediaContext4 } from "@bendyline/squisq-react";
29214
29411
 
29215
29412
  // src/useHeadingLayout.ts
29216
- import { useCallback as useCallback39, useEffect as useEffect41, useMemo as useMemo36, useState as useState51 } from "react";
29413
+ import { useCallback as useCallback39, useEffect as useEffect42, useMemo as useMemo37, useState as useState52 } from "react";
29217
29414
  import { flattenBlocks as flattenBlocks3, hasTemplate } from "@bendyline/squisq/doc";
29218
29415
  function useHeadingLayout(refInsideWrapper) {
29219
29416
  const { doc, activeView, monacoEditor, tiptapEditor } = useEditorContext();
29220
- const flatBlocks = useMemo36(() => doc ? flattenBlocks3(doc.blocks) : [], [doc]);
29221
- const [entries, setEntries] = useState51([]);
29222
- const [pageEdges, setPageEdges] = useState51(null);
29223
- useEffect41(() => {
29417
+ const flatBlocks = useMemo37(() => doc ? flattenBlocks3(doc.blocks) : [], [doc]);
29418
+ const [entries, setEntries] = useState52([]);
29419
+ const [pageEdges, setPageEdges] = useState52(null);
29420
+ useEffect42(() => {
29224
29421
  if (activeView !== "wysiwyg") return;
29225
29422
  const node2 = refInsideWrapper.current;
29226
29423
  if (!node2) return;
@@ -29288,7 +29485,7 @@ function useHeadingLayout(refInsideWrapper) {
29288
29485
  window.removeEventListener("resize", recompute);
29289
29486
  };
29290
29487
  }, [activeView, flatBlocks, refInsideWrapper]);
29291
- useEffect41(() => {
29488
+ useEffect42(() => {
29292
29489
  if (activeView !== "raw") return;
29293
29490
  if (!monacoEditor) return;
29294
29491
  const node2 = refInsideWrapper.current;
@@ -29349,7 +29546,7 @@ function useHeadingLayout(refInsideWrapper) {
29349
29546
  window.removeEventListener("resize", recompute);
29350
29547
  };
29351
29548
  }, [activeView, monacoEditor, flatBlocks, refInsideWrapper]);
29352
- useEffect41(() => {
29549
+ useEffect42(() => {
29353
29550
  setEntries([]);
29354
29551
  setPageEdges(null);
29355
29552
  }, [activeView]);
@@ -29411,7 +29608,7 @@ function sameEntries(a, b) {
29411
29608
  }
29412
29609
 
29413
29610
  // src/InlinePreviewGutter.tsx
29414
- import { Fragment as Fragment17, jsx as jsx57, jsxs as jsxs45 } from "react/jsx-runtime";
29611
+ import { Fragment as Fragment17, jsx as jsx58, jsxs as jsxs45 } from "react/jsx-runtime";
29415
29612
  function isAnnotated(block) {
29416
29613
  const annotation = block.sourceHeading?.templateAnnotation;
29417
29614
  if (!annotation) return false;
@@ -29581,7 +29778,7 @@ function InlinePreviewGutter({
29581
29778
  const { entries: headingEntries, scrollToBlock } = useHeadingLayout(gutterRef);
29582
29779
  const previewSettings = usePreviewSettingsOptional();
29583
29780
  const activeTheme = previewSettings?.activeTheme ?? DEFAULT_THEME5;
29584
- const items = useMemo37(() => {
29781
+ const items = useMemo38(() => {
29585
29782
  if (!doc || !doc.blocks.length) return [];
29586
29783
  const flat = flattenBlocks4(doc.blocks);
29587
29784
  const totalBlocks = flat.length;
@@ -29638,12 +29835,12 @@ function InlinePreviewGutter({
29638
29835
  });
29639
29836
  return result;
29640
29837
  }, [doc, viewport, activeTheme]);
29641
- const connectorTops = useMemo37(() => {
29838
+ const connectorTops = useMemo38(() => {
29642
29839
  const m = /* @__PURE__ */ new Map();
29643
29840
  headingEntries.forEach((e2) => m.set(e2.block.id, e2.top));
29644
29841
  return m;
29645
29842
  }, [headingEntries]);
29646
- const [positions, setPositions] = useState52(/* @__PURE__ */ new Map());
29843
+ const [positions, setPositions] = useState53(/* @__PURE__ */ new Map());
29647
29844
  useLayoutEffect8(() => {
29648
29845
  if (items.length === 0) {
29649
29846
  setPositions((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
@@ -29698,7 +29895,7 @@ function InlinePreviewGutter({
29698
29895
  "data-testid": "inline-preview-gutter",
29699
29896
  "aria-label": "Block previews",
29700
29897
  children: [
29701
- headingEntries.length > 0 && /* @__PURE__ */ jsx57(
29898
+ headingEntries.length > 0 && /* @__PURE__ */ jsx58(
29702
29899
  "div",
29703
29900
  {
29704
29901
  className: "squisq-inline-preview-connectors",
@@ -29715,7 +29912,7 @@ function InlinePreviewGutter({
29715
29912
  children: headingEntries.map((ex, i) => {
29716
29913
  const EXTENT_GAP = 6;
29717
29914
  const height = Math.max(2, ex.bottom - ex.top - EXTENT_GAP);
29718
- return /* @__PURE__ */ jsx57(
29915
+ return /* @__PURE__ */ jsx58(
29719
29916
  "div",
29720
29917
  {
29721
29918
  className: `squisq-inline-preview-extent${ex.annotated ? "" : " squisq-inline-preview-extent--untagged"}`,
@@ -29731,7 +29928,7 @@ function InlinePreviewGutter({
29731
29928
  })
29732
29929
  }
29733
29930
  ),
29734
- items.length > 0 && /* @__PURE__ */ jsx57(
29931
+ items.length > 0 && /* @__PURE__ */ jsx58(
29735
29932
  "svg",
29736
29933
  {
29737
29934
  className: "squisq-inline-preview-connector-svg",
@@ -29754,7 +29951,7 @@ function InlinePreviewGutter({
29754
29951
  const x2 = connectorWidth + CARD_LEFT_INSET;
29755
29952
  const y2 = cardTop + CARD_LABEL_OFFSET;
29756
29953
  return /* @__PURE__ */ jsxs45("g", { children: [
29757
- /* @__PURE__ */ jsx57(
29954
+ /* @__PURE__ */ jsx58(
29758
29955
  "line",
29759
29956
  {
29760
29957
  x1,
@@ -29766,13 +29963,13 @@ function InlinePreviewGutter({
29766
29963
  strokeLinecap: "round"
29767
29964
  }
29768
29965
  ),
29769
- /* @__PURE__ */ jsx57("circle", { cx: x1, cy: y1, r: "4", fill: "#6366f1", stroke: "#ffffff", strokeWidth: "2" }),
29770
- /* @__PURE__ */ jsx57("circle", { cx: x2, cy: y2, r: "4", fill: "#6366f1", stroke: "#ffffff", strokeWidth: "2" })
29966
+ /* @__PURE__ */ jsx58("circle", { cx: x1, cy: y1, r: "4", fill: "#6366f1", stroke: "#ffffff", strokeWidth: "2" }),
29967
+ /* @__PURE__ */ jsx58("circle", { cx: x2, cy: y2, r: "4", fill: "#6366f1", stroke: "#ffffff", strokeWidth: "2" })
29771
29968
  ] }, item.id);
29772
29969
  })
29773
29970
  }
29774
29971
  ),
29775
- /* @__PURE__ */ jsx57(MediaContext4.Provider, { value: mediaProvider ?? null, children: items.map((item) => {
29972
+ /* @__PURE__ */ jsx58(MediaContext4.Provider, { value: mediaProvider ?? null, children: items.map((item) => {
29776
29973
  const top = positions.get(item.id);
29777
29974
  const hidden = top == null;
29778
29975
  return /* @__PURE__ */ jsxs45(
@@ -29790,20 +29987,20 @@ function InlinePreviewGutter({
29790
29987
  onClick: () => scrollToBlock(item.block),
29791
29988
  children: [
29792
29989
  /* @__PURE__ */ jsxs45("div", { className: "squisq-inline-preview-card-label", children: [
29793
- /* @__PURE__ */ jsx57("span", { className: "squisq-inline-preview-card-template", children: templateLabel(item.template) }),
29990
+ /* @__PURE__ */ jsx58("span", { className: "squisq-inline-preview-card-template", children: templateLabel(item.template) }),
29794
29991
  item.headingText && /* @__PURE__ */ jsxs45(Fragment17, { children: [
29795
- /* @__PURE__ */ jsx57("span", { className: "squisq-inline-preview-card-sep", children: "\u2014" }),
29796
- /* @__PURE__ */ jsx57("span", { className: "squisq-inline-preview-card-title", children: item.headingText })
29992
+ /* @__PURE__ */ jsx58("span", { className: "squisq-inline-preview-card-sep", children: "\u2014" }),
29993
+ /* @__PURE__ */ jsx58("span", { className: "squisq-inline-preview-card-title", children: item.headingText })
29797
29994
  ] })
29798
29995
  ] }),
29799
- /* @__PURE__ */ jsx57(
29996
+ /* @__PURE__ */ jsx58(
29800
29997
  "div",
29801
29998
  {
29802
29999
  className: "squisq-inline-preview-card-svg",
29803
30000
  style: {
29804
30001
  aspectRatio: `${viewport.width} / ${viewport.height}`
29805
30002
  },
29806
- children: /* @__PURE__ */ jsx57(
30003
+ children: /* @__PURE__ */ jsx58(
29807
30004
  BlockRenderer3,
29808
30005
  {
29809
30006
  block: item.block,
@@ -30159,10 +30356,10 @@ function buildPreviewDoc(doc, options) {
30159
30356
  // src/OutlinePanel.tsx
30160
30357
  import {
30161
30358
  useCallback as useCallback40,
30162
- useEffect as useEffect42,
30163
- useMemo as useMemo38,
30359
+ useEffect as useEffect43,
30360
+ useMemo as useMemo39,
30164
30361
  useRef as useRef42,
30165
- useState as useState53
30362
+ useState as useState54
30166
30363
  } from "react";
30167
30364
  import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate3 } from "@bendyline/squisq/doc";
30168
30365
  import { extractPlainText as extractPlainText5 } from "@bendyline/squisq/markdown";
@@ -30264,7 +30461,7 @@ function splitTrailingLineGap(value) {
30264
30461
  }
30265
30462
 
30266
30463
  // src/OutlinePanel.tsx
30267
- import { jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
30464
+ import { jsx as jsx59, jsxs as jsxs46 } from "react/jsx-runtime";
30268
30465
  var OUTLINE_RESPONSIVE_WIDTH = "clamp(260px, 30vw, 460px)";
30269
30466
  var OUTLINE_DRAG_MIME = "application/x-squisq-outline-section";
30270
30467
  function OutlinePanel({ width, className, readOnly = false }) {
@@ -30281,9 +30478,9 @@ function OutlinePanel({ width, className, readOnly = false }) {
30281
30478
  const { scrollToBlock } = useHeadingLayout(paneRef);
30282
30479
  const cursorActiveId = useActiveOutlineBlockId();
30283
30480
  const activeDragRef = useRef42(null);
30284
- const [draggedBlockId, setDraggedBlockId] = useState53(null);
30285
- const [dropTarget, setDropTarget] = useState53(null);
30286
- const blockModeActiveId = useMemo38(() => {
30481
+ const [draggedBlockId, setDraggedBlockId] = useState54(null);
30482
+ const [dropTarget, setDropTarget] = useState54(null);
30483
+ const blockModeActiveId = useMemo39(() => {
30287
30484
  if (layoutMode !== "block" || activeBlockStartLine == null || !doc) return null;
30288
30485
  const match = flattenBlocks5(doc.blocks).find(
30289
30486
  (b) => b.sourceHeading?.position?.start.line === activeBlockStartLine
@@ -30382,7 +30579,7 @@ function OutlinePanel({ width, className, readOnly = false }) {
30382
30579
  overflow: "auto",
30383
30580
  ...accentColor ? { ["--squisq-outline-accent"]: accentColor } : {}
30384
30581
  };
30385
- return /* @__PURE__ */ jsx58(
30582
+ return /* @__PURE__ */ jsx59(
30386
30583
  "aside",
30387
30584
  {
30388
30585
  ref: paneRef,
@@ -30390,7 +30587,7 @@ function OutlinePanel({ width, className, readOnly = false }) {
30390
30587
  style: paneStyle,
30391
30588
  "data-testid": "outline-panel",
30392
30589
  "aria-label": "Document outline",
30393
- children: isEmpty2 ? /* @__PURE__ */ jsx58("div", { className: "squisq-outline-empty", children: /* @__PURE__ */ jsx58("p", { children: "Add a heading to populate the outline." }) }) : /* @__PURE__ */ jsx58("ul", { className: "squisq-outline-tree", role: "tree", children: doc.blocks.map((b) => /* @__PURE__ */ jsx58(
30590
+ children: isEmpty2 ? /* @__PURE__ */ jsx59("div", { className: "squisq-outline-empty", children: /* @__PURE__ */ jsx59("p", { children: "Add a heading to populate the outline." }) }) : /* @__PURE__ */ jsx59("ul", { className: "squisq-outline-tree", role: "tree", children: doc.blocks.map((b) => /* @__PURE__ */ jsx59(
30394
30591
  OutlineNode,
30395
30592
  {
30396
30593
  block: b,
@@ -30464,21 +30661,21 @@ function OutlineNode({
30464
30661
  onDragEnd,
30465
30662
  title: text || "(empty heading)",
30466
30663
  children: [
30467
- canDrag && /* @__PURE__ */ jsx58("span", { className: "squisq-outline-drag-handle", "aria-hidden": "true", children: /* @__PURE__ */ jsxs46("svg", { width: "8", height: "12", viewBox: "0 0 8 12", children: [
30468
- /* @__PURE__ */ jsx58("circle", { cx: "2", cy: "2", r: "1", fill: "currentColor" }),
30469
- /* @__PURE__ */ jsx58("circle", { cx: "6", cy: "2", r: "1", fill: "currentColor" }),
30470
- /* @__PURE__ */ jsx58("circle", { cx: "2", cy: "6", r: "1", fill: "currentColor" }),
30471
- /* @__PURE__ */ jsx58("circle", { cx: "6", cy: "6", r: "1", fill: "currentColor" }),
30472
- /* @__PURE__ */ jsx58("circle", { cx: "2", cy: "10", r: "1", fill: "currentColor" }),
30473
- /* @__PURE__ */ jsx58("circle", { cx: "6", cy: "10", r: "1", fill: "currentColor" })
30664
+ canDrag && /* @__PURE__ */ jsx59("span", { className: "squisq-outline-drag-handle", "aria-hidden": "true", children: /* @__PURE__ */ jsxs46("svg", { width: "8", height: "12", viewBox: "0 0 8 12", children: [
30665
+ /* @__PURE__ */ jsx59("circle", { cx: "2", cy: "2", r: "1", fill: "currentColor" }),
30666
+ /* @__PURE__ */ jsx59("circle", { cx: "6", cy: "2", r: "1", fill: "currentColor" }),
30667
+ /* @__PURE__ */ jsx59("circle", { cx: "2", cy: "6", r: "1", fill: "currentColor" }),
30668
+ /* @__PURE__ */ jsx59("circle", { cx: "6", cy: "6", r: "1", fill: "currentColor" }),
30669
+ /* @__PURE__ */ jsx59("circle", { cx: "2", cy: "10", r: "1", fill: "currentColor" }),
30670
+ /* @__PURE__ */ jsx59("circle", { cx: "6", cy: "10", r: "1", fill: "currentColor" })
30474
30671
  ] }) }),
30475
- /* @__PURE__ */ jsx58("span", { className: "squisq-outline-row-text", children: text || "(untitled)" }),
30476
- showChip && /* @__PURE__ */ jsx58("span", { className: "squisq-outline-template-chip", children: templateLabel(tplName) })
30672
+ /* @__PURE__ */ jsx59("span", { className: "squisq-outline-row-text", children: text || "(untitled)" }),
30673
+ showChip && /* @__PURE__ */ jsx59("span", { className: "squisq-outline-template-chip", children: templateLabel(tplName) })
30477
30674
  ]
30478
30675
  }
30479
30676
  ),
30480
30677
  heading && /* @__PURE__ */ jsxs46("span", { className: "squisq-outline-row-actions", children: [
30481
- /* @__PURE__ */ jsx58(
30678
+ /* @__PURE__ */ jsx59(
30482
30679
  "button",
30483
30680
  {
30484
30681
  type: "button",
@@ -30487,7 +30684,7 @@ function OutlineNode({
30487
30684
  title: "Promote heading",
30488
30685
  disabled: mutationsDisabled || !canPromote,
30489
30686
  onClick: () => onChangeLevel(block, -1),
30490
- children: /* @__PURE__ */ jsx58("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx58(
30687
+ children: /* @__PURE__ */ jsx59("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx59(
30491
30688
  "path",
30492
30689
  {
30493
30690
  d: "M6.5 2.5 L3 5 L6.5 7.5",
@@ -30500,7 +30697,7 @@ function OutlineNode({
30500
30697
  ) })
30501
30698
  }
30502
30699
  ),
30503
- /* @__PURE__ */ jsx58(
30700
+ /* @__PURE__ */ jsx59(
30504
30701
  "button",
30505
30702
  {
30506
30703
  type: "button",
@@ -30509,7 +30706,7 @@ function OutlineNode({
30509
30706
  title: "Demote heading",
30510
30707
  disabled: mutationsDisabled || !canDemote,
30511
30708
  onClick: () => onChangeLevel(block, 1),
30512
- children: /* @__PURE__ */ jsx58("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx58(
30709
+ children: /* @__PURE__ */ jsx59("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx59(
30513
30710
  "path",
30514
30711
  {
30515
30712
  d: "M3.5 2.5 L7 5 L3.5 7.5",
@@ -30526,7 +30723,7 @@ function OutlineNode({
30526
30723
  ]
30527
30724
  }
30528
30725
  ),
30529
- block.children && block.children.length > 0 && /* @__PURE__ */ jsx58("ul", { className: "squisq-outline-tree", children: block.children.map((child) => /* @__PURE__ */ jsx58(
30726
+ block.children && block.children.length > 0 && /* @__PURE__ */ jsx59("ul", { className: "squisq-outline-tree", children: block.children.map((child) => /* @__PURE__ */ jsx59(
30530
30727
  OutlineNode,
30531
30728
  {
30532
30729
  block: child,
@@ -30548,12 +30745,12 @@ function OutlineNode({
30548
30745
  }
30549
30746
  function useActiveOutlineBlockId() {
30550
30747
  const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
30551
- const flatBlocks = useMemo38(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
30552
- const [activeId, setActiveId] = useState53(null);
30553
- useEffect42(() => {
30748
+ const flatBlocks = useMemo39(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
30749
+ const [activeId, setActiveId] = useState54(null);
30750
+ useEffect43(() => {
30554
30751
  setActiveId(null);
30555
30752
  }, [activeView]);
30556
- useEffect42(() => {
30753
+ useEffect43(() => {
30557
30754
  if (activeView !== "wysiwyg" || !tiptapEditor) return;
30558
30755
  const update = () => {
30559
30756
  const { from } = tiptapEditor.state.selection;
@@ -30575,7 +30772,7 @@ function useActiveOutlineBlockId() {
30575
30772
  tiptapEditor.off("update", update);
30576
30773
  };
30577
30774
  }, [activeView, tiptapEditor, flatBlocks]);
30578
- useEffect42(() => {
30775
+ useEffect43(() => {
30579
30776
  if (activeView !== "raw" || !monacoEditor) return;
30580
30777
  const update = () => {
30581
30778
  const line = monacoEditor.getPosition()?.lineNumber;
@@ -30626,7 +30823,7 @@ function bumpHeadingLevelInSource(source, line, delta) {
30626
30823
  }
30627
30824
 
30628
30825
  // src/codeContext/CodeContextZones.tsx
30629
- import { useCallback as useCallback42, useEffect as useEffect44, useMemo as useMemo40, useRef as useRef44, useState as useState54 } from "react";
30826
+ import { useCallback as useCallback42, useEffect as useEffect45, useMemo as useMemo41, useRef as useRef44, useState as useState55 } from "react";
30630
30827
  import { createPortal as createPortal10 } from "react-dom";
30631
30828
 
30632
30829
  // src/codeContext/diffContextSections.ts
@@ -30750,8 +30947,8 @@ function setOrdinal(zone, ordinal) {
30750
30947
  // src/codeContext/CodeContextSectionView.tsx
30751
30948
  import { parseMarkdown as parseMarkdown8 } from "@bendyline/squisq/markdown";
30752
30949
  import { MarkdownRenderer } from "@bendyline/squisq-react";
30753
- import { useCallback as useCallback41, useEffect as useEffect43, useMemo as useMemo39, useRef as useRef43 } from "react";
30754
- import { jsx as jsx59, jsxs as jsxs47 } from "react/jsx-runtime";
30950
+ import { useCallback as useCallback41, useEffect as useEffect44, useMemo as useMemo40, useRef as useRef43 } from "react";
30951
+ import { jsx as jsx60, jsxs as jsxs47 } from "react/jsx-runtime";
30755
30952
  function CodeContextSectionView({
30756
30953
  section,
30757
30954
  expanded,
@@ -30762,15 +30959,15 @@ function CodeContextSectionView({
30762
30959
  onMeasure
30763
30960
  }) {
30764
30961
  const rootRef = useRef43(null);
30765
- const stripNodes = useMemo39(
30962
+ const stripNodes = useMemo40(
30766
30963
  () => parseMarkdown8(section.summaryMarkdown).children,
30767
30964
  [section.summaryMarkdown]
30768
30965
  );
30769
- const bodyNodes = useMemo39(
30966
+ const bodyNodes = useMemo40(
30770
30967
  () => expanded && section.markdown ? parseMarkdown8(section.markdown).children : null,
30771
30968
  [expanded, section.markdown]
30772
30969
  );
30773
- useEffect43(() => {
30970
+ useEffect44(() => {
30774
30971
  const el = rootRef.current;
30775
30972
  if (!el || typeof ResizeObserver === "undefined") return;
30776
30973
  const report = () => {
@@ -30826,12 +31023,12 @@ function CodeContextSectionView({
30826
31023
  "aria-expanded": expanded,
30827
31024
  onClick: () => onToggle(section.id),
30828
31025
  children: [
30829
- /* @__PURE__ */ jsx59("span", { className: "squisq-ccx-chevron", "aria-hidden": "true", children: expanded ? "\u25BE" : "\u25B8" }),
30830
- /* @__PURE__ */ jsx59("span", { className: "squisq-ccx-strip-text", children: /* @__PURE__ */ jsx59(MarkdownRenderer, { nodes: stripNodes, ...linkSchemes ? { linkSchemes } : {} }) })
31026
+ /* @__PURE__ */ jsx60("span", { className: "squisq-ccx-chevron", "aria-hidden": "true", children: expanded ? "\u25BE" : "\u25B8" }),
31027
+ /* @__PURE__ */ jsx60("span", { className: "squisq-ccx-strip-text", children: /* @__PURE__ */ jsx60(MarkdownRenderer, { nodes: stripNodes, ...linkSchemes ? { linkSchemes } : {} }) })
30831
31028
  ]
30832
31029
  }
30833
31030
  ),
30834
- expanded && (bodyNodes ? /* @__PURE__ */ jsx59("div", { className: "squisq-ccx-body", children: /* @__PURE__ */ jsx59(MarkdownRenderer, { nodes: bodyNodes, ...linkSchemes ? { linkSchemes } : {} }) }) : /* @__PURE__ */ jsx59("div", { className: "squisq-ccx-body squisq-ccx-body--loading", children: "Loading\u2026" }))
31031
+ expanded && (bodyNodes ? /* @__PURE__ */ jsx60("div", { className: "squisq-ccx-body", children: /* @__PURE__ */ jsx60(MarkdownRenderer, { nodes: bodyNodes, ...linkSchemes ? { linkSchemes } : {} }) }) : /* @__PURE__ */ jsx60("div", { className: "squisq-ccx-body squisq-ccx-body--loading", children: "Loading\u2026" }))
30835
31032
  ]
30836
31033
  }
30837
31034
  )
@@ -30839,14 +31036,14 @@ function CodeContextSectionView({
30839
31036
  }
30840
31037
 
30841
31038
  // src/codeContext/CodeContextZones.tsx
30842
- import { Fragment as Fragment18, jsx as jsx60 } from "react/jsx-runtime";
31039
+ import { Fragment as Fragment18, jsx as jsx61 } from "react/jsx-runtime";
30843
31040
  function CodeContextZones({ options }) {
30844
31041
  const { monacoEditor } = useEditorContext();
30845
- const [manager, setManager] = useState54(null);
30846
- const [, setZonesVersion] = useState54(0);
30847
- const [expandedById, setExpandedById] = useState54({});
31042
+ const [manager, setManager] = useState55(null);
31043
+ const [, setZonesVersion] = useState55(0);
31044
+ const [expandedById, setExpandedById] = useState55({});
30848
31045
  const seenIds = useRef44(/* @__PURE__ */ new Set());
30849
- useEffect44(() => {
31046
+ useEffect45(() => {
30850
31047
  if (!monacoEditor) return;
30851
31048
  const mgr = new CodeContextZoneManager(monacoEditor);
30852
31049
  const off = mgr.onDidChangeZones(() => setZonesVersion((v2) => v2 + 1));
@@ -30859,7 +31056,7 @@ function CodeContextZones({ options }) {
30859
31056
  }, [monacoEditor]);
30860
31057
  const fileTop = options.fileTop;
30861
31058
  const sections = options.sections;
30862
- const resolved = useMemo40(() => {
31059
+ const resolved = useMemo41(() => {
30863
31060
  const out = [];
30864
31061
  if (fileTop) {
30865
31062
  out.push({ spec: { id: fileTop.id, line: 0, ordinal: 0 }, section: fileTop });
@@ -30869,7 +31066,7 @@ function CodeContextZones({ options }) {
30869
31066
  });
30870
31067
  return out;
30871
31068
  }, [fileTop, sections]);
30872
- useEffect44(() => {
31069
+ useEffect45(() => {
30873
31070
  if (!manager) return;
30874
31071
  manager.sync(resolved.map((r) => r.spec));
30875
31072
  setExpandedById((prev) => {
@@ -30908,11 +31105,11 @@ function CodeContextZones({ options }) {
30908
31105
  [monacoEditor]
30909
31106
  );
30910
31107
  if (!manager) return null;
30911
- return /* @__PURE__ */ jsx60(Fragment18, { children: resolved.map(({ section }) => {
31108
+ return /* @__PURE__ */ jsx61(Fragment18, { children: resolved.map(({ section }) => {
30912
31109
  const domNode = manager.getDomNode(section.id);
30913
31110
  if (!domNode) return null;
30914
31111
  return createPortal10(
30915
- /* @__PURE__ */ jsx60(
31112
+ /* @__PURE__ */ jsx61(
30916
31113
  CodeContextSectionView,
30917
31114
  {
30918
31115
  section,
@@ -30932,7 +31129,7 @@ function CodeContextZones({ options }) {
30932
31129
  }
30933
31130
 
30934
31131
  // src/BlockCardView.tsx
30935
- import { jsx as jsx61, jsxs as jsxs48 } from "react/jsx-runtime";
31132
+ import { jsx as jsx62, jsxs as jsxs48 } from "react/jsx-runtime";
30936
31133
  function BlockCardView({
30937
31134
  active = true,
30938
31135
  blockCount,
@@ -30953,7 +31150,7 @@ function BlockCardView({
30953
31150
  className: `squisq-block-card-frame${active ? " squisq-block-card" : ""}${className ? ` ${className}` : ""}`,
30954
31151
  "data-testid": active ? "block-card-view" : void 0,
30955
31152
  children: [
30956
- /* @__PURE__ */ jsx61("div", { className: `squisq-block-card-frame-body${active ? " squisq-block-card-body" : ""}`, children }),
31153
+ /* @__PURE__ */ jsx62("div", { className: `squisq-block-card-frame-body${active ? " squisq-block-card-body" : ""}`, children }),
30957
31154
  active && /* @__PURE__ */ jsxs48("div", { className: "squisq-block-card-nav", role: "toolbar", "aria-label": "Block navigation", children: [
30958
31155
  /* @__PURE__ */ jsxs48(
30959
31156
  "button",
@@ -30965,7 +31162,7 @@ function BlockCardView({
30965
31162
  "aria-label": "Previous block",
30966
31163
  "data-tooltip": "Previous block",
30967
31164
  children: [
30968
- /* @__PURE__ */ jsx61("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx61(
31165
+ /* @__PURE__ */ jsx62("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx62(
30969
31166
  "path",
30970
31167
  {
30971
31168
  d: "M9 2.5 L4.5 7 L9 11.5",
@@ -30976,7 +31173,7 @@ function BlockCardView({
30976
31173
  fill: "none"
30977
31174
  }
30978
31175
  ) }),
30979
- /* @__PURE__ */ jsx61("span", { children: "Previous" })
31176
+ /* @__PURE__ */ jsx62("span", { children: "Previous" })
30980
31177
  ]
30981
31178
  }
30982
31179
  ),
@@ -30996,8 +31193,8 @@ function BlockCardView({
30996
31193
  "aria-label": "Next block",
30997
31194
  "data-tooltip": "Next block",
30998
31195
  children: [
30999
- /* @__PURE__ */ jsx61("span", { children: "Next" }),
31000
- /* @__PURE__ */ jsx61("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx61(
31196
+ /* @__PURE__ */ jsx62("span", { children: "Next" }),
31197
+ /* @__PURE__ */ jsx62("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx62(
31001
31198
  "path",
31002
31199
  {
31003
31200
  d: "M5 2.5 L9.5 7 L5 11.5",
@@ -31020,7 +31217,7 @@ function BlockCardView({
31020
31217
  "aria-label": "Add block",
31021
31218
  "data-tooltip": "Add block after this one",
31022
31219
  children: [
31023
- /* @__PURE__ */ jsx61("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx61(
31220
+ /* @__PURE__ */ jsx62("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx62(
31024
31221
  "path",
31025
31222
  {
31026
31223
  d: "M7 3 L7 11 M3 7 L11 7",
@@ -31030,7 +31227,7 @@ function BlockCardView({
31030
31227
  fill: "none"
31031
31228
  }
31032
31229
  ) }),
31033
- /* @__PURE__ */ jsx61("span", { children: "Add block" })
31230
+ /* @__PURE__ */ jsx62("span", { children: "Add block" })
31034
31231
  ]
31035
31232
  }
31036
31233
  )
@@ -31305,7 +31502,7 @@ function placeClipInBlock(source, fromLine, targetHeadingLine, spec, startAt) {
31305
31502
  }
31306
31503
 
31307
31504
  // src/TimelineTrack.tsx
31308
- import { useCallback as useCallback44, useEffect as useEffect47, useMemo as useMemo41, useRef as useRef47, useState as useState57 } from "react";
31505
+ import { useCallback as useCallback44, useEffect as useEffect48, useMemo as useMemo42, useRef as useRef47, useState as useState58 } from "react";
31309
31506
  import {
31310
31507
  resolveMediaSchedule as resolveMediaSchedule2,
31311
31508
  getDocPlaybackDuration,
@@ -31433,14 +31630,14 @@ function collectTimelinePlaybackSchedule(doc, scheduled) {
31433
31630
  import { memo } from "react";
31434
31631
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS5 } from "@bendyline/squisq/schemas";
31435
31632
  import { BlockRenderer as BlockRenderer4, MediaContext as MediaContext5 } from "@bendyline/squisq-react";
31436
- import { jsx as jsx62 } from "react/jsx-runtime";
31633
+ import { jsx as jsx63 } from "react/jsx-runtime";
31437
31634
  var BlockThumbnail = memo(function BlockThumbnail2({
31438
31635
  visual,
31439
31636
  viewport = VIEWPORT_PRESETS5.landscape,
31440
31637
  basePath = "/",
31441
31638
  mediaProvider = null
31442
31639
  }) {
31443
- return /* @__PURE__ */ jsx62(MediaContext5.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx62(BlockRenderer4, { block: visual, blockTime: 0, basePath, viewport }) });
31640
+ return /* @__PURE__ */ jsx63(MediaContext5.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx63(BlockRenderer4, { block: visual, blockTime: 0, basePath, viewport }) });
31444
31641
  });
31445
31642
 
31446
31643
  // src/resolveBlockVisual.ts
@@ -31464,7 +31661,7 @@ function resolveBlockVisual(doc, block, theme, viewport) {
31464
31661
  }
31465
31662
 
31466
31663
  // src/useTimelineClock.ts
31467
- import { useCallback as useCallback43, useEffect as useEffect45, useRef as useRef45, useState as useState55 } from "react";
31664
+ import { useCallback as useCallback43, useEffect as useEffect46, useRef as useRef45, useState as useState56 } from "react";
31468
31665
  function advanceTime(prev, dt, total) {
31469
31666
  if (total <= 0) return 0;
31470
31667
  return Math.min(total, Math.max(0, prev + dt));
@@ -31484,8 +31681,8 @@ function playTimelineMediaAt(root, time) {
31484
31681
  });
31485
31682
  }
31486
31683
  function useTimelineClock(total) {
31487
- const [currentTime, setCurrentTime] = useState55(0);
31488
- const [isPlaying, setIsPlaying] = useState55(false);
31684
+ const [currentTime, setCurrentTime] = useState56(0);
31685
+ const [isPlaying, setIsPlaying] = useState56(false);
31489
31686
  const rafRef = useRef45(null);
31490
31687
  const lastRef = useRef45(0);
31491
31688
  const currentTimeRef = useRef45(0);
@@ -31493,10 +31690,10 @@ function useTimelineClock(total) {
31493
31690
  const mediaHostRef = useRef45(null);
31494
31691
  currentTimeRef.current = currentTime;
31495
31692
  isPlayingRef.current = isPlaying;
31496
- useEffect45(() => {
31693
+ useEffect46(() => {
31497
31694
  setCurrentTime((t) => Math.min(t, Math.max(0, total)));
31498
31695
  }, [total]);
31499
- useEffect45(() => {
31696
+ useEffect46(() => {
31500
31697
  if (!isPlaying) return;
31501
31698
  lastRef.current = performance.now();
31502
31699
  const tick = (now) => {
@@ -31558,9 +31755,9 @@ function timelineMediaLabel(src, kind) {
31558
31755
  }
31559
31756
 
31560
31757
  // src/TimelineItemMenu.tsx
31561
- import { useEffect as useEffect46, useLayoutEffect as useLayoutEffect9, useRef as useRef46, useState as useState56 } from "react";
31758
+ import { useEffect as useEffect47, useLayoutEffect as useLayoutEffect9, useRef as useRef46, useState as useState57 } from "react";
31562
31759
  import { createPortal as createPortal11 } from "react-dom";
31563
- import { Fragment as Fragment19, jsx as jsx63, jsxs as jsxs49 } from "react/jsx-runtime";
31760
+ import { Fragment as Fragment19, jsx as jsx64, jsxs as jsxs49 } from "react/jsx-runtime";
31564
31761
  function TimelineItemMenu({
31565
31762
  anchor,
31566
31763
  target,
@@ -31573,7 +31770,7 @@ function TimelineItemMenu({
31573
31770
  onClose
31574
31771
  }) {
31575
31772
  const panelRef = useRef46(null);
31576
- const [style, setStyle] = useState56(() => menuStyle(anchor));
31773
+ const [style, setStyle] = useState57(() => menuStyle(anchor));
31577
31774
  useLayoutEffect9(() => {
31578
31775
  const panel = panelRef.current;
31579
31776
  if (!panel) return;
@@ -31587,7 +31784,7 @@ function TimelineItemMenu({
31587
31784
  resizeObserver?.disconnect();
31588
31785
  };
31589
31786
  }, [anchor]);
31590
- useEffect46(() => {
31787
+ useEffect47(() => {
31591
31788
  const onKeyDown = (event) => {
31592
31789
  if (event.key !== "Escape") return;
31593
31790
  event.preventDefault();
@@ -31619,10 +31816,10 @@ function TimelineItemMenu({
31619
31816
  style: { ...style, ...accentStyle(accentColor) },
31620
31817
  children: [
31621
31818
  /* @__PURE__ */ jsxs49("div", { className: "squisq-timeline-item-menu-header", children: [
31622
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-kind", children: target.kind === "block" ? "Block" : "Video" }),
31623
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-title", title: target.title, children: target.title })
31819
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-kind", children: target.kind === "block" ? "Block" : "Video" }),
31820
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-title", title: target.title, children: target.title })
31624
31821
  ] }),
31625
- target.kind === "block" ? /* @__PURE__ */ jsx63(
31822
+ target.kind === "block" ? /* @__PURE__ */ jsx64(
31626
31823
  BlockMenu,
31627
31824
  {
31628
31825
  target,
@@ -31632,7 +31829,7 @@ function TimelineItemMenu({
31632
31829
  onStartTime: onBlockStartTime,
31633
31830
  onTransition: onBlockTransition
31634
31831
  }
31635
- ) : /* @__PURE__ */ jsx63(VideoMenu, { target, onPatch: onVideoPatch })
31832
+ ) : /* @__PURE__ */ jsx64(VideoMenu, { target, onPatch: onVideoPatch })
31636
31833
  ]
31637
31834
  }
31638
31835
  ),
@@ -31647,12 +31844,12 @@ function BlockMenu({
31647
31844
  onStartTime,
31648
31845
  onTransition
31649
31846
  }) {
31650
- const [explicitDuration, setExplicitDuration] = useState56(target.explicitDuration);
31651
- const [duration, setDuration] = useState56(formatNumber(target.duration));
31652
- const [startTime, setStartTime] = useState56(
31847
+ const [explicitDuration, setExplicitDuration] = useState57(target.explicitDuration);
31848
+ const [duration, setDuration] = useState57(formatNumber(target.duration));
31849
+ const [startTime, setStartTime] = useState57(
31653
31850
  target.startTime == null ? "" : formatNumber(target.startTime)
31654
31851
  );
31655
- const [transition, setTransition] = useState56(target.transition);
31852
+ const [transition, setTransition] = useState57(target.transition);
31656
31853
  const toggleAutotime = (autotimed) => {
31657
31854
  setExplicitDuration(!autotimed);
31658
31855
  if (autotimed) {
@@ -31665,7 +31862,7 @@ function BlockMenu({
31665
31862
  };
31666
31863
  return /* @__PURE__ */ jsxs49("div", { className: "squisq-timeline-item-menu-body", children: [
31667
31864
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-check", children: [
31668
- /* @__PURE__ */ jsx63(
31865
+ /* @__PURE__ */ jsx64(
31669
31866
  "input",
31670
31867
  {
31671
31868
  type: "checkbox",
@@ -31673,10 +31870,10 @@ function BlockMenu({
31673
31870
  onChange: (event) => toggleAutotime(event.target.checked)
31674
31871
  }
31675
31872
  ),
31676
- /* @__PURE__ */ jsx63("span", { children: "Autotime block" })
31873
+ /* @__PURE__ */ jsx64("span", { children: "Autotime block" })
31677
31874
  ] }),
31678
- /* @__PURE__ */ jsx63("p", { className: "squisq-timeline-item-menu-hint", children: "Uses narration, content, and interior media when no explicit duration is set." }),
31679
- /* @__PURE__ */ jsx63(
31875
+ /* @__PURE__ */ jsx64("p", { className: "squisq-timeline-item-menu-hint", children: "Uses narration, content, and interior media when no explicit duration is set." }),
31876
+ /* @__PURE__ */ jsx64(
31680
31877
  MenuNumberField,
31681
31878
  {
31682
31879
  label: "Duration",
@@ -31690,7 +31887,7 @@ function BlockMenu({
31690
31887
  }
31691
31888
  }
31692
31889
  ),
31693
- /* @__PURE__ */ jsx63(
31890
+ /* @__PURE__ */ jsx64(
31694
31891
  MenuNumberField,
31695
31892
  {
31696
31893
  label: "Start time",
@@ -31704,8 +31901,8 @@ function BlockMenu({
31704
31901
  }
31705
31902
  ),
31706
31903
  /* @__PURE__ */ jsxs49("div", { className: "squisq-timeline-item-menu-row", children: [
31707
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "Transition" }),
31708
- /* @__PURE__ */ jsx63(
31904
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "Transition" }),
31905
+ /* @__PURE__ */ jsx64(
31709
31906
  TransitionPicker,
31710
31907
  {
31711
31908
  value: transition,
@@ -31724,11 +31921,11 @@ function VideoMenu({
31724
31921
  target,
31725
31922
  onPatch
31726
31923
  }) {
31727
- const [placement, setPlacement] = useState56(target.placement);
31728
- const [locked, setLocked] = useState56(target.lockToBlock);
31729
- const [pipSize, setPipSize] = useState56(target.pipSize ?? "");
31730
- const [pipShape, setPipShape] = useState56(target.pipShape ?? "");
31731
- const [pipPosition, setPipPosition] = useState56(target.pipPosition ?? "");
31924
+ const [placement, setPlacement] = useState57(target.placement);
31925
+ const [locked, setLocked] = useState57(target.lockToBlock);
31926
+ const [pipSize, setPipSize] = useState57(target.pipSize ?? "");
31927
+ const [pipShape, setPipShape] = useState57(target.pipShape ?? "");
31928
+ const [pipPosition, setPipPosition] = useState57(target.pipPosition ?? "");
31732
31929
  const placed = placement === "picture-in-picture" || placement === "overlay";
31733
31930
  const placementOptions = [
31734
31931
  target.canUseContentPlacement ? { value: "content", label: "In layout" } : { value: "default", label: "Default" },
@@ -31737,14 +31934,14 @@ function VideoMenu({
31737
31934
  ];
31738
31935
  return /* @__PURE__ */ jsxs49("div", { className: "squisq-timeline-item-menu-body", children: [
31739
31936
  /* @__PURE__ */ jsxs49("div", { className: "squisq-timeline-item-menu-field", children: [
31740
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "Placement" }),
31741
- /* @__PURE__ */ jsx63(
31937
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "Placement" }),
31938
+ /* @__PURE__ */ jsx64(
31742
31939
  "div",
31743
31940
  {
31744
31941
  className: "squisq-timeline-item-menu-segments",
31745
31942
  role: "group",
31746
31943
  "aria-label": "Video placement",
31747
- children: placementOptions.map((option) => /* @__PURE__ */ jsx63(
31944
+ children: placementOptions.map((option) => /* @__PURE__ */ jsx64(
31748
31945
  "button",
31749
31946
  {
31750
31947
  type: "button",
@@ -31766,7 +31963,7 @@ function VideoMenu({
31766
31963
  ] }),
31767
31964
  placed && /* @__PURE__ */ jsxs49(Fragment19, { children: [
31768
31965
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-check", children: [
31769
- /* @__PURE__ */ jsx63(
31966
+ /* @__PURE__ */ jsx64(
31770
31967
  "input",
31771
31968
  {
31772
31969
  type: "checkbox",
@@ -31780,11 +31977,11 @@ function VideoMenu({
31780
31977
  }
31781
31978
  }
31782
31979
  ),
31783
- /* @__PURE__ */ jsx63("span", { children: "Lock to block" })
31980
+ /* @__PURE__ */ jsx64("span", { children: "Lock to block" })
31784
31981
  ] }),
31785
31982
  placement === "picture-in-picture" && /* @__PURE__ */ jsxs49(Fragment19, { children: [
31786
31983
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31787
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "PIP size" }),
31984
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "PIP size" }),
31788
31985
  /* @__PURE__ */ jsxs49(
31789
31986
  "select",
31790
31987
  {
@@ -31801,14 +31998,14 @@ function VideoMenu({
31801
31998
  titleCase(target.defaultPipSize),
31802
31999
  ")"
31803
32000
  ] }),
31804
- /* @__PURE__ */ jsx63("option", { value: "small", children: "Small" }),
31805
- /* @__PURE__ */ jsx63("option", { value: "large", children: "Large" })
32001
+ /* @__PURE__ */ jsx64("option", { value: "small", children: "Small" }),
32002
+ /* @__PURE__ */ jsx64("option", { value: "large", children: "Large" })
31806
32003
  ]
31807
32004
  }
31808
32005
  )
31809
32006
  ] }),
31810
32007
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31811
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "PIP shape" }),
32008
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "PIP shape" }),
31812
32009
  /* @__PURE__ */ jsxs49(
31813
32010
  "select",
31814
32011
  {
@@ -31825,14 +32022,14 @@ function VideoMenu({
31825
32022
  titleCase(target.defaultPipShape),
31826
32023
  ")"
31827
32024
  ] }),
31828
- /* @__PURE__ */ jsx63("option", { value: "square", children: "Square" }),
31829
- /* @__PURE__ */ jsx63("option", { value: "wide", children: "Wide (16:9)" })
32025
+ /* @__PURE__ */ jsx64("option", { value: "square", children: "Square" }),
32026
+ /* @__PURE__ */ jsx64("option", { value: "wide", children: "Wide (16:9)" })
31830
32027
  ]
31831
32028
  }
31832
32029
  )
31833
32030
  ] }),
31834
32031
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31835
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "PIP position" }),
32032
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "PIP position" }),
31836
32033
  /* @__PURE__ */ jsxs49(
31837
32034
  "select",
31838
32035
  {
@@ -31849,10 +32046,10 @@ function VideoMenu({
31849
32046
  positionLabel(target.defaultPipPosition),
31850
32047
  ")"
31851
32048
  ] }),
31852
- /* @__PURE__ */ jsx63("option", { value: "top-left", children: "Top left" }),
31853
- /* @__PURE__ */ jsx63("option", { value: "top-right", children: "Top right" }),
31854
- /* @__PURE__ */ jsx63("option", { value: "bottom-left", children: "Bottom left" }),
31855
- /* @__PURE__ */ jsx63("option", { value: "bottom-right", children: "Bottom right" })
32049
+ /* @__PURE__ */ jsx64("option", { value: "top-left", children: "Top left" }),
32050
+ /* @__PURE__ */ jsx64("option", { value: "top-right", children: "Top right" }),
32051
+ /* @__PURE__ */ jsx64("option", { value: "bottom-left", children: "Bottom left" }),
32052
+ /* @__PURE__ */ jsx64("option", { value: "bottom-right", children: "Bottom right" })
31856
32053
  ]
31857
32054
  }
31858
32055
  )
@@ -31870,9 +32067,9 @@ function MenuNumberField({
31870
32067
  onChange
31871
32068
  }) {
31872
32069
  return /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31873
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: label }),
32070
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: label }),
31874
32071
  /* @__PURE__ */ jsxs49("span", { className: "squisq-timeline-item-menu-number", children: [
31875
- /* @__PURE__ */ jsx63(
32072
+ /* @__PURE__ */ jsx64(
31876
32073
  "input",
31877
32074
  {
31878
32075
  type: "number",
@@ -31885,7 +32082,7 @@ function MenuNumberField({
31885
32082
  onChange: (event) => onChange(event.target.value)
31886
32083
  }
31887
32084
  ),
31888
- /* @__PURE__ */ jsx63("span", { children: "sec" })
32085
+ /* @__PURE__ */ jsx64("span", { children: "sec" })
31889
32086
  ] })
31890
32087
  ] });
31891
32088
  }
@@ -31930,7 +32127,7 @@ function menuStyle(anchor, element) {
31930
32127
  }
31931
32128
 
31932
32129
  // src/TimelineTrack.tsx
31933
- import { jsx as jsx64, jsxs as jsxs50 } from "react/jsx-runtime";
32130
+ import { jsx as jsx65, jsxs as jsxs50 } from "react/jsx-runtime";
31934
32131
  var PREVIEW_VIEWPORT = VIEWPORT_PRESETS6.landscape;
31935
32132
  var DEFAULT_PX_PER_SECOND = 18;
31936
32133
  var ZOOM_MIN = 4;
@@ -31953,9 +32150,9 @@ function TimelineVideoFilmstrip({
31953
32150
  FILMSTRIP_MAX_FRAMES,
31954
32151
  Math.max(1, Math.ceil(width / FILMSTRIP_FRAME_WIDTH))
31955
32152
  );
31956
- return /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-video-filmstrip", "aria-hidden": "true", children: Array.from({ length: frameCount }, (_2, index2) => {
32153
+ return /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-video-filmstrip", "aria-hidden": "true", children: Array.from({ length: frameCount }, (_2, index2) => {
31957
32154
  const sampleTime = Math.max(0, sourceStart) + Math.max(0, sourceLength) * ((index2 + 0.5) / frameCount);
31958
- return /* @__PURE__ */ jsx64(
32155
+ return /* @__PURE__ */ jsx65(
31959
32156
  "video",
31960
32157
  {
31961
32158
  src: resolvedSrc,
@@ -31998,14 +32195,14 @@ function TimelineTrack({
31998
32195
  colorScheme
31999
32196
  } = useEditorContext();
32000
32197
  const doc = docProp ?? contextDoc;
32001
- const [drag, setDrag] = useState57(null);
32002
- const [itemMenu, setItemMenu] = useState57(null);
32003
- const [pxPerSecond, setPxPerSecond] = useState57(DEFAULT_PX_PER_SECOND);
32198
+ const [drag, setDrag] = useState58(null);
32199
+ const [itemMenu, setItemMenu] = useState58(null);
32200
+ const [pxPerSecond, setPxPerSecond] = useState58(DEFAULT_PX_PER_SECOND);
32004
32201
  const scrollRef = useRef47(null);
32005
- const blocks = useMemo41(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
32202
+ const blocks = useMemo42(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
32006
32203
  const previewSettings = usePreviewSettingsOptional();
32007
32204
  const previewTheme = previewSettings?.activeTheme ?? DEFAULT_THEME6;
32008
- const visualByBlock = useMemo41(() => {
32205
+ const visualByBlock = useMemo42(() => {
32009
32206
  const map = /* @__PURE__ */ new Map();
32010
32207
  if (doc) {
32011
32208
  for (const b of blocks) {
@@ -32015,16 +32212,16 @@ function TimelineTrack({
32015
32212
  }
32016
32213
  return map;
32017
32214
  }, [doc, blocks, previewTheme]);
32018
- const derivedClips = useMemo41(
32215
+ const derivedClips = useMemo42(
32019
32216
  () => doc ? resolveMediaSchedule2(doc) : [],
32020
32217
  [doc]
32021
32218
  );
32022
32219
  const clips = schedule ?? derivedClips;
32023
- const playbackClips = useMemo41(
32220
+ const playbackClips = useMemo42(
32024
32221
  () => doc ? collectTimelinePlaybackSchedule(doc, clips) : clips,
32025
32222
  [clips, doc]
32026
32223
  );
32027
- const total = useMemo41(() => doc ? getDocPlaybackDuration(doc) : 0, [doc]);
32224
+ const total = useMemo42(() => doc ? getDocPlaybackDuration(doc) : 0, [doc]);
32028
32225
  const width = Math.max(total * pxPerSecond, 200);
32029
32226
  const internalClock = useTimelineClock(total);
32030
32227
  const activeClock = clock ?? internalClock;
@@ -32033,8 +32230,8 @@ function TimelineTrack({
32033
32230
  setDrag(null);
32034
32231
  play();
32035
32232
  }, [play]);
32036
- const [scrubbing, setScrubbing] = useState57(false);
32037
- useEffect47(() => {
32233
+ const [scrubbing, setScrubbing] = useState58(false);
32234
+ useEffect48(() => {
32038
32235
  if (!scrubbing) return;
32039
32236
  const onMove = (e2) => {
32040
32237
  const scroll = scrollRef.current;
@@ -32051,7 +32248,7 @@ function TimelineTrack({
32051
32248
  window.removeEventListener("pointerup", onUp);
32052
32249
  };
32053
32250
  }, [scrubbing, pxPerSecond, seek]);
32054
- const rawClipById = useMemo41(() => {
32251
+ const rawClipById = useMemo42(() => {
32055
32252
  const map = /* @__PURE__ */ new Map();
32056
32253
  if (doc) {
32057
32254
  for (const b of flattenBlocks6(doc.blocks)) for (const m of b.media ?? []) map.set(m.id, m);
@@ -32072,7 +32269,7 @@ function TimelineTrack({
32072
32269
  [blocks]
32073
32270
  );
32074
32271
  const followedBlockRef = useRef47(null);
32075
- useEffect47(() => {
32272
+ useEffect48(() => {
32076
32273
  if (!isPlaying) {
32077
32274
  followedBlockRef.current = null;
32078
32275
  return;
@@ -32083,7 +32280,7 @@ function TimelineTrack({
32083
32280
  const line = headingLine(block);
32084
32281
  if (line != null) goToBlockByLine(line);
32085
32282
  }, [isPlaying, currentTime, blockAtTime, goToBlockByLine]);
32086
- useEffect47(() => {
32283
+ useEffect48(() => {
32087
32284
  if (!isPlaying) return;
32088
32285
  const scroll = scrollRef.current;
32089
32286
  if (!scroll) return;
@@ -32131,8 +32328,8 @@ function TimelineTrack({
32131
32328
  );
32132
32329
  const zoomIn = useCallback44(() => setPxPerSecond((s) => Math.min(ZOOM_MAX, s * ZOOM_FACTOR)), []);
32133
32330
  const zoomOut = useCallback44(() => setPxPerSecond((s) => Math.max(ZOOM_MIN, s / ZOOM_FACTOR)), []);
32134
- const [viewportWidth, setViewportWidth] = useState57(0);
32135
- useEffect47(() => {
32331
+ const [viewportWidth, setViewportWidth] = useState58(0);
32332
+ useEffect48(() => {
32136
32333
  const el = scrollRef.current;
32137
32334
  if (!el || typeof ResizeObserver === "undefined") return;
32138
32335
  const update = () => setViewportWidth(el.clientWidth);
@@ -32146,7 +32343,7 @@ function TimelineTrack({
32146
32343
  const dragRef = useRef47(null);
32147
32344
  dragRef.current = drag;
32148
32345
  const isDragging = drag != null && !drag.committed;
32149
- useEffect47(() => {
32346
+ useEffect48(() => {
32150
32347
  if (!isDragging) return;
32151
32348
  const onMove = (e2) => {
32152
32349
  const d = dragRef.current;
@@ -32177,7 +32374,7 @@ function TimelineTrack({
32177
32374
  window.removeEventListener("pointerup", onUp);
32178
32375
  };
32179
32376
  }, [isDragging]);
32180
- useEffect47(() => {
32377
+ useEffect48(() => {
32181
32378
  if (dragRef.current?.committed) setDrag(null);
32182
32379
  }, [doc]);
32183
32380
  const beginDrag = useCallback44(
@@ -32260,7 +32457,7 @@ function TimelineTrack({
32260
32457
  for (let t = 0; t <= rulerEnd + 1e-3 && ticks.length < 1e3; t += tickSeconds) ticks.push(t);
32261
32458
  return /* @__PURE__ */ jsxs50("div", { className: "squisq-timeline", style: { height }, "data-testid": "timeline-track", children: [
32262
32459
  /* @__PURE__ */ jsxs50("div", { className: "squisq-timeline-controls", children: [
32263
- /* @__PURE__ */ jsx64(
32460
+ /* @__PURE__ */ jsx65(
32264
32461
  "button",
32265
32462
  {
32266
32463
  type: "button",
@@ -32277,7 +32474,7 @@ function TimelineTrack({
32277
32474
  " / ",
32278
32475
  formatClock2(total)
32279
32476
  ] }),
32280
- /* @__PURE__ */ jsx64(
32477
+ /* @__PURE__ */ jsx65(
32281
32478
  "button",
32282
32479
  {
32283
32480
  type: "button",
@@ -32289,7 +32486,7 @@ function TimelineTrack({
32289
32486
  children: "\u2212"
32290
32487
  }
32291
32488
  ),
32292
- /* @__PURE__ */ jsx64(
32489
+ /* @__PURE__ */ jsx65(
32293
32490
  "button",
32294
32491
  {
32295
32492
  type: "button",
@@ -32302,8 +32499,8 @@ function TimelineTrack({
32302
32499
  }
32303
32500
  )
32304
32501
  ] }),
32305
- /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs50("div", { className: "squisq-timeline-inner", style: { width }, children: [
32306
- /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-row squisq-timeline-row--blocks", children: blocks.map((b, i) => {
32502
+ /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs50("div", { className: "squisq-timeline-inner", style: { width }, children: [
32503
+ /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-row squisq-timeline-row--blocks", children: blocks.map((b, i) => {
32307
32504
  const line = headingLine(b);
32308
32505
  const isActive = line != null && line === activeBlockStartLine;
32309
32506
  const left = previewLeft(i);
@@ -32320,7 +32517,7 @@ function TimelineTrack({
32320
32517
  if (line != null) goToBlockByLine(line);
32321
32518
  },
32322
32519
  children: [
32323
- visualByBlock.has(b.id) && /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-block-thumb", "aria-hidden": true, children: /* @__PURE__ */ jsx64(
32520
+ visualByBlock.has(b.id) && /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-block-thumb", "aria-hidden": true, children: /* @__PURE__ */ jsx65(
32324
32521
  BlockThumbnail,
32325
32522
  {
32326
32523
  visual: visualByBlock.get(b.id),
@@ -32328,7 +32525,7 @@ function TimelineTrack({
32328
32525
  mediaProvider
32329
32526
  }
32330
32527
  ) }),
32331
- prev && headingLine(prev) != null && /* @__PURE__ */ jsx64(
32528
+ prev && headingLine(prev) != null && /* @__PURE__ */ jsx65(
32332
32529
  "span",
32333
32530
  {
32334
32531
  className: "squisq-timeline-edge squisq-timeline-edge--left",
@@ -32349,8 +32546,8 @@ function TimelineTrack({
32349
32546
  )
32350
32547
  }
32351
32548
  ),
32352
- /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-block-label", children: b.title ?? b.id }),
32353
- line != null && /* @__PURE__ */ jsx64(
32549
+ /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-block-label", children: b.title ?? b.id }),
32550
+ line != null && /* @__PURE__ */ jsx65(
32354
32551
  "button",
32355
32552
  {
32356
32553
  type: "button",
@@ -32372,7 +32569,7 @@ function TimelineTrack({
32372
32569
  children: "\u2026"
32373
32570
  }
32374
32571
  ),
32375
- line != null && /* @__PURE__ */ jsx64(
32572
+ line != null && /* @__PURE__ */ jsx65(
32376
32573
  "span",
32377
32574
  {
32378
32575
  className: "squisq-timeline-edge squisq-timeline-edge--right",
@@ -32420,7 +32617,7 @@ function TimelineTrack({
32420
32617
  spillover: raw.spillover
32421
32618
  } : { kind: c.kind, src: c.src, clipStart: c.sourceIn };
32422
32619
  };
32423
- return /* @__PURE__ */ jsx64(
32620
+ return /* @__PURE__ */ jsx65(
32424
32621
  "div",
32425
32622
  {
32426
32623
  className: "squisq-timeline-row squisq-timeline-row--media",
@@ -32457,7 +32654,7 @@ function TimelineTrack({
32457
32654
  if (next) setMarkdownSource(next);
32458
32655
  },
32459
32656
  children: [
32460
- c.kind === "video" && /* @__PURE__ */ jsx64(
32657
+ c.kind === "video" && /* @__PURE__ */ jsx65(
32461
32658
  TimelineVideoFilmstrip,
32462
32659
  {
32463
32660
  src: c.src,
@@ -32466,8 +32663,8 @@ function TimelineTrack({
32466
32663
  width: clipWidth
32467
32664
  }
32468
32665
  ),
32469
- /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(c.src, c.kind) }),
32470
- c.kind === "video" && c.sourceLine != null && /* @__PURE__ */ jsx64(
32666
+ /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(c.src, c.kind) }),
32667
+ c.kind === "video" && c.sourceLine != null && /* @__PURE__ */ jsx65(
32471
32668
  "button",
32472
32669
  {
32473
32670
  type: "button",
@@ -32493,7 +32690,7 @@ function TimelineTrack({
32493
32690
  children: "\u2026"
32494
32691
  }
32495
32692
  ),
32496
- editable && /* @__PURE__ */ jsx64(
32693
+ editable && /* @__PURE__ */ jsx65(
32497
32694
  "span",
32498
32695
  {
32499
32696
  className: "squisq-timeline-edge squisq-timeline-edge--right",
@@ -32538,7 +32735,7 @@ function TimelineTrack({
32538
32735
  ...m.clipStart != null ? { clipStart: m.clipStart } : {},
32539
32736
  ...m.clipEnd != null ? { clipEnd: m.clipEnd } : {}
32540
32737
  };
32541
- return /* @__PURE__ */ jsx64(
32738
+ return /* @__PURE__ */ jsx65(
32542
32739
  "div",
32543
32740
  {
32544
32741
  className: "squisq-timeline-row squisq-timeline-row--media",
@@ -32565,7 +32762,7 @@ function TimelineTrack({
32565
32762
  { onClick: () => selectClipAt(b.startTime, b.id) }
32566
32763
  ),
32567
32764
  children: [
32568
- m.kind === "video" && /* @__PURE__ */ jsx64(
32765
+ m.kind === "video" && /* @__PURE__ */ jsx65(
32569
32766
  TimelineVideoFilmstrip,
32570
32767
  {
32571
32768
  src: m.src,
@@ -32574,8 +32771,8 @@ function TimelineTrack({
32574
32771
  width: clipWidth
32575
32772
  }
32576
32773
  ),
32577
- /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(m.src, m.kind) }),
32578
- m.kind === "video" && m.sourceLine != null && /* @__PURE__ */ jsx64(
32774
+ /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(m.src, m.kind) }),
32775
+ m.kind === "video" && m.sourceLine != null && /* @__PURE__ */ jsx65(
32579
32776
  "button",
32580
32777
  {
32581
32778
  type: "button",
@@ -32600,7 +32797,7 @@ function TimelineTrack({
32600
32797
  children: "\u2026"
32601
32798
  }
32602
32799
  ),
32603
- m.sourceLine != null && /* @__PURE__ */ jsx64(
32800
+ m.sourceLine != null && /* @__PURE__ */ jsx65(
32604
32801
  "span",
32605
32802
  {
32606
32803
  className: "squisq-timeline-edge squisq-timeline-edge--right",
@@ -32622,7 +32819,7 @@ function TimelineTrack({
32622
32819
  })
32623
32820
  )
32624
32821
  ] }),
32625
- /* @__PURE__ */ jsx64(
32822
+ /* @__PURE__ */ jsx65(
32626
32823
  "div",
32627
32824
  {
32628
32825
  className: "squisq-timeline-row squisq-timeline-row--ruler",
@@ -32630,10 +32827,10 @@ function TimelineTrack({
32630
32827
  const rect = e2.currentTarget.getBoundingClientRect();
32631
32828
  seek((e2.clientX - rect.left) / pxPerSecond);
32632
32829
  },
32633
- children: ticks.map((t) => /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-tick", style: { left: t * pxPerSecond }, children: /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-tick-label", children: formatDur(t) }) }, t))
32830
+ children: ticks.map((t) => /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-tick", style: { left: t * pxPerSecond }, children: /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-tick-label", children: formatDur(t) }) }, t))
32634
32831
  }
32635
32832
  ),
32636
- /* @__PURE__ */ jsx64(
32833
+ /* @__PURE__ */ jsx65(
32637
32834
  "div",
32638
32835
  {
32639
32836
  className: "squisq-timeline-playhead",
@@ -32645,11 +32842,11 @@ function TimelineTrack({
32645
32842
  pause();
32646
32843
  setScrubbing(true);
32647
32844
  },
32648
- children: /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-playhead-knob" })
32845
+ children: /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-playhead-knob" })
32649
32846
  }
32650
32847
  )
32651
32848
  ] }) }),
32652
- /* @__PURE__ */ jsx64("div", { ref: activeClock.registerMediaHost, className: "squisq-timeline-media-host", "aria-hidden": true, children: /* @__PURE__ */ jsx64(MediaContext6.Provider, { value: mediaProvider ?? null, children: /* @__PURE__ */ jsx64(
32849
+ /* @__PURE__ */ jsx65("div", { ref: activeClock.registerMediaHost, className: "squisq-timeline-media-host", "aria-hidden": true, children: /* @__PURE__ */ jsx65(MediaContext6.Provider, { value: mediaProvider ?? null, children: /* @__PURE__ */ jsx65(
32653
32850
  MediaClipLayer,
32654
32851
  {
32655
32852
  schedule: playbackClips,
@@ -32658,7 +32855,7 @@ function TimelineTrack({
32658
32855
  basePath
32659
32856
  }
32660
32857
  ) }) }),
32661
- itemMenu && itemMenuTarget && /* @__PURE__ */ jsx64(
32858
+ itemMenu && itemMenuTarget && /* @__PURE__ */ jsx65(
32662
32859
  TimelineItemMenu,
32663
32860
  {
32664
32861
  anchor: itemMenu.anchor,
@@ -32713,9 +32910,9 @@ function formatDur(seconds) {
32713
32910
  }
32714
32911
 
32715
32912
  // src/TimelineVideoPanel.tsx
32716
- import { useMemo as useMemo42 } from "react";
32913
+ import { useMemo as useMemo43 } from "react";
32717
32914
  import { MediaClipLayer as MediaClipLayer2 } from "@bendyline/squisq-react";
32718
- import { jsx as jsx65, jsxs as jsxs51 } from "react/jsx-runtime";
32915
+ import { jsx as jsx66, jsxs as jsxs51 } from "react/jsx-runtime";
32719
32916
  function TimelineVideoPanel({
32720
32917
  schedule,
32721
32918
  currentTime,
@@ -32723,7 +32920,7 @@ function TimelineVideoPanel({
32723
32920
  basePath = "/",
32724
32921
  onClose
32725
32922
  }) {
32726
- const videos = useMemo42(() => schedule.filter((clip) => clip.kind === "video"), [schedule]);
32923
+ const videos = useMemo43(() => schedule.filter((clip) => clip.kind === "video"), [schedule]);
32727
32924
  const activeVideos = videos.filter(
32728
32925
  (clip) => currentTime >= clip.absoluteStart && currentTime < clip.absoluteEnd
32729
32926
  );
@@ -32736,10 +32933,10 @@ function TimelineVideoPanel({
32736
32933
  "aria-label": "Timeline video preview",
32737
32934
  children: [
32738
32935
  /* @__PURE__ */ jsxs51("header", { className: "squisq-timeline-video-header", children: [
32739
- /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-video-title", children: "Video monitor" }),
32740
- /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-video-label", title: activeLabel, children: activeLabel }),
32741
- /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-video-time", children: formatClock3(currentTime) }),
32742
- onClose && /* @__PURE__ */ jsx65(
32936
+ /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-title", children: "Video monitor" }),
32937
+ /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-label", title: activeLabel, children: activeLabel }),
32938
+ /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-time", children: formatClock3(currentTime) }),
32939
+ onClose && /* @__PURE__ */ jsx66(
32743
32940
  "button",
32744
32941
  {
32745
32942
  type: "button",
@@ -32751,8 +32948,8 @@ function TimelineVideoPanel({
32751
32948
  }
32752
32949
  )
32753
32950
  ] }),
32754
- /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsxs51("div", { className: "squisq-timeline-video-stage", children: [
32755
- /* @__PURE__ */ jsx65(
32951
+ /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsxs51("div", { className: "squisq-timeline-video-stage", children: [
32952
+ /* @__PURE__ */ jsx66(
32756
32953
  MediaClipLayer2,
32757
32954
  {
32758
32955
  schedule: videos,
@@ -32764,7 +32961,7 @@ function TimelineVideoPanel({
32764
32961
  muted: true
32765
32962
  }
32766
32963
  ),
32767
- activeVideos.length === 0 && /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-video-empty", children: "Move the playhead onto a video clip" })
32964
+ activeVideos.length === 0 && /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-empty", children: "Move the playhead onto a video clip" })
32768
32965
  ] }) })
32769
32966
  ]
32770
32967
  }
@@ -32777,12 +32974,12 @@ function formatClock3(seconds) {
32777
32974
  }
32778
32975
 
32779
32976
  // src/TimelineCompositionPanel.tsx
32780
- import { useMemo as useMemo43 } from "react";
32977
+ import { useMemo as useMemo44 } from "react";
32781
32978
  import { getDocPlaybackDuration as getDocPlaybackDuration2, resolveMediaSchedule as resolveMediaSchedule3 } from "@bendyline/squisq/schemas";
32782
32979
  import { DocPlayer } from "@bendyline/squisq-react";
32783
32980
 
32784
32981
  // src/usePreviewProjection.ts
32785
- import { useEffect as useEffect48, useState as useState58 } from "react";
32982
+ import { useEffect as useEffect49, useState as useState59 } from "react";
32786
32983
  import { resolveAudioMapping } from "@bendyline/squisq/doc";
32787
32984
  import { applyTransform } from "@bendyline/squisq/transform";
32788
32985
  function hasEquivalentAudio(left, right) {
@@ -32802,8 +32999,8 @@ function preserveEquivalentAudio(previous, next) {
32802
32999
  };
32803
33000
  }
32804
33001
  function usePreviewProjection(doc, transformStyle, workspaceContainer, documentTitle2) {
32805
- const [projection, setProjection] = useState58(null);
32806
- useEffect48(() => {
33002
+ const [projection, setProjection] = useState59(null);
33003
+ useEffect49(() => {
32807
33004
  if (!doc || !doc.blocks.length) {
32808
33005
  setProjection(null);
32809
33006
  return;
@@ -32837,7 +33034,7 @@ function usePreviewProjection(doc, transformStyle, workspaceContainer, documentT
32837
33034
  }
32838
33035
 
32839
33036
  // src/TimelineCompositionPanel.tsx
32840
- import { jsx as jsx66, jsxs as jsxs52 } from "react/jsx-runtime";
33037
+ import { jsx as jsx67, jsxs as jsxs52 } from "react/jsx-runtime";
32841
33038
  function TimelineCompositionPanel({
32842
33039
  doc,
32843
33040
  clock,
@@ -32869,11 +33066,11 @@ function TimelineCompositionPanel({
32869
33066
  );
32870
33067
  const contentDoc = projection?.contentDoc ?? null;
32871
33068
  const playerDoc = projection?.playerDoc ?? null;
32872
- const totalDuration = useMemo43(
33069
+ const totalDuration = useMemo44(
32873
33070
  () => playerDoc ? getDocPlaybackDuration2(playerDoc) : 0,
32874
33071
  [playerDoc]
32875
33072
  );
32876
- const effectiveVideoPresentation = useMemo43(() => {
33073
+ const effectiveVideoPresentation = useMemo44(() => {
32877
33074
  if (!playerDoc) return activeVideoPresentation;
32878
33075
  const activeVideo = resolveMediaSchedule3(playerDoc).find(
32879
33076
  (clip) => clip.kind === "video" && clock.currentTime >= clip.absoluteStart && clock.currentTime < clip.absoluteEnd
@@ -32882,7 +33079,7 @@ function TimelineCompositionPanel({
32882
33079
  if (activeVideo?.placement === "overlay") return "full-frame";
32883
33080
  return activeVideoPresentation;
32884
33081
  }, [activeVideoPresentation, clock.currentTime, playerDoc]);
32885
- const audioController = useMemo43(
33082
+ const audioController = useMemo44(
32886
33083
  () => ({
32887
33084
  currentTime: clock.currentTime,
32888
33085
  isPlaying: clock.isPlaying,
@@ -32908,11 +33105,11 @@ function TimelineCompositionPanel({
32908
33105
  "aria-label": "Timeline video composition preview",
32909
33106
  children: [
32910
33107
  /* @__PURE__ */ jsxs52("header", { className: "squisq-timeline-video-header", children: [
32911
- /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-title", children: "Video composition" }),
32912
- /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-label", children: formatPresentation(effectiveVideoPresentation) }),
32913
- /* @__PURE__ */ jsx66(PreviewToolbarControls, { displayMode: "video" }),
32914
- /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-time", children: formatClock4(clock.currentTime) }),
32915
- onClose && /* @__PURE__ */ jsx66(
33108
+ /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-video-title", children: "Video composition" }),
33109
+ /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-video-label", children: formatPresentation(effectiveVideoPresentation) }),
33110
+ /* @__PURE__ */ jsx67(PreviewToolbarControls, { displayMode: "video" }),
33111
+ /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-video-time", children: formatClock4(clock.currentTime) }),
33112
+ onClose && /* @__PURE__ */ jsx67(
32916
33113
  "button",
32917
33114
  {
32918
33115
  type: "button",
@@ -32924,7 +33121,7 @@ function TimelineCompositionPanel({
32924
33121
  }
32925
33122
  )
32926
33123
  ] }),
32927
- /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-composition-stage", children: playerDoc ? /* @__PURE__ */ jsx66(
33124
+ /* @__PURE__ */ jsx67("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsx67("div", { className: "squisq-timeline-composition-stage", children: playerDoc ? /* @__PURE__ */ jsx67(
32928
33125
  DocPlayer,
32929
33126
  {
32930
33127
  doc: playerDoc,
@@ -32950,7 +33147,7 @@ function TimelineCompositionPanel({
32950
33147
  enableSwipe: false,
32951
33148
  globalKeyboardShortcuts: false
32952
33149
  }
32953
- ) : /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-empty", children: "Preparing video composition\u2026" }) }) })
33150
+ ) : /* @__PURE__ */ jsx67("div", { className: "squisq-timeline-video-empty", children: "Preparing video composition\u2026" }) }) })
32954
33151
  ]
32955
33152
  }
32956
33153
  );
@@ -32967,7 +33164,7 @@ function formatPresentation(presentation) {
32967
33164
  }
32968
33165
 
32969
33166
  // src/TimelineToolbar.tsx
32970
- import { jsx as jsx67, jsxs as jsxs53 } from "react/jsx-runtime";
33167
+ import { jsx as jsx68, jsxs as jsxs53 } from "react/jsx-runtime";
32971
33168
  function TimelineToolbar({
32972
33169
  literalVideoVisible,
32973
33170
  compositionVisible,
@@ -32984,7 +33181,7 @@ function TimelineToolbar({
32984
33181
  "aria-label": "Timeline view controls",
32985
33182
  "data-testid": "timeline-toolbar",
32986
33183
  children: [
32987
- /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-toolbar-title", children: "Preview panes" }),
33184
+ /* @__PURE__ */ jsx68("span", { className: "squisq-timeline-toolbar-title", children: "Preview panes" }),
32988
33185
  /* @__PURE__ */ jsxs53(
32989
33186
  "button",
32990
33187
  {
@@ -32997,7 +33194,7 @@ function TimelineToolbar({
32997
33194
  "data-tooltip": literalVideoVisible ? "Hide literal video" : "Show literal video",
32998
33195
  children: [
32999
33196
  /* @__PURE__ */ jsxs53("svg", { width: "15", height: "15", viewBox: "0 0 15 15", "aria-hidden": "true", children: [
33000
- /* @__PURE__ */ jsx67(
33197
+ /* @__PURE__ */ jsx68(
33001
33198
  "rect",
33002
33199
  {
33003
33200
  x: "1.5",
@@ -33010,7 +33207,7 @@ function TimelineToolbar({
33010
33207
  strokeWidth: "1.4"
33011
33208
  }
33012
33209
  ),
33013
- /* @__PURE__ */ jsx67(
33210
+ /* @__PURE__ */ jsx68(
33014
33211
  "path",
33015
33212
  {
33016
33213
  d: "M10 5.5 13.5 4v7L10 9.5z",
@@ -33021,7 +33218,7 @@ function TimelineToolbar({
33021
33218
  }
33022
33219
  )
33023
33220
  ] }),
33024
- /* @__PURE__ */ jsx67("span", { children: "Video monitor" })
33221
+ /* @__PURE__ */ jsx68("span", { children: "Video monitor" })
33025
33222
  ]
33026
33223
  }
33027
33224
  ),
@@ -33037,7 +33234,7 @@ function TimelineToolbar({
33037
33234
  "data-tooltip": compositionVisible ? "Hide video composition" : "Show video composition",
33038
33235
  children: [
33039
33236
  /* @__PURE__ */ jsxs53("svg", { width: "15", height: "15", viewBox: "0 0 15 15", "aria-hidden": "true", children: [
33040
- /* @__PURE__ */ jsx67(
33237
+ /* @__PURE__ */ jsx68(
33041
33238
  "rect",
33042
33239
  {
33043
33240
  x: "1.5",
@@ -33050,10 +33247,10 @@ function TimelineToolbar({
33050
33247
  strokeWidth: "1.4"
33051
33248
  }
33052
33249
  ),
33053
- /* @__PURE__ */ jsx67("path", { d: "M5 13h5M7.5 11v2", stroke: "currentColor", strokeWidth: "1.4" }),
33054
- /* @__PURE__ */ jsx67("path", { d: "m6.3 5 3 1.5-3 1.5z", fill: "currentColor" })
33250
+ /* @__PURE__ */ jsx68("path", { d: "M5 13h5M7.5 11v2", stroke: "currentColor", strokeWidth: "1.4" }),
33251
+ /* @__PURE__ */ jsx68("path", { d: "m6.3 5 3 1.5-3 1.5z", fill: "currentColor" })
33055
33252
  ] }),
33056
- /* @__PURE__ */ jsx67("span", { children: "Video composition" })
33253
+ /* @__PURE__ */ jsx68("span", { children: "Video composition" })
33057
33254
  ]
33058
33255
  }
33059
33256
  )
@@ -33063,7 +33260,7 @@ function TimelineToolbar({
33063
33260
  }
33064
33261
 
33065
33262
  // src/PlainHtmlPreview.tsx
33066
- import { useCallback as useCallback45, useEffect as useEffect49, useMemo as useMemo44, useRef as useRef48, useState as useState59 } from "react";
33263
+ import { useCallback as useCallback45, useEffect as useEffect50, useMemo as useMemo45, useRef as useRef48, useState as useState60 } from "react";
33067
33264
  import { parseMarkdown as parseMarkdown9 } from "@bendyline/squisq/markdown";
33068
33265
 
33069
33266
  // src/utils/collectInlineFontAwesomeCss.ts
@@ -33098,7 +33295,7 @@ function isFontAwesomeRule(rule) {
33098
33295
  }
33099
33296
 
33100
33297
  // src/PlainHtmlPreview.tsx
33101
- import { jsx as jsx68 } from "react/jsx-runtime";
33298
+ import { jsx as jsx69 } from "react/jsx-runtime";
33102
33299
  var cachedRender = null;
33103
33300
  var cachedRenderPromise = null;
33104
33301
  function loadRenderFn() {
@@ -33143,9 +33340,9 @@ function PlainHtmlPreview({
33143
33340
  },
33144
33341
  [onFrameChange]
33145
33342
  );
33146
- const mdDoc = useMemo44(() => parseMarkdown9(markdown), [markdown]);
33147
- const [resolvedImages, setResolvedImages] = useState59(null);
33148
- useEffect49(() => {
33343
+ const mdDoc = useMemo45(() => parseMarkdown9(markdown), [markdown]);
33344
+ const [resolvedImages, setResolvedImages] = useState60(null);
33345
+ useEffect50(() => {
33149
33346
  if (!mediaProvider) {
33150
33347
  setResolvedImages(null);
33151
33348
  return;
@@ -33173,16 +33370,16 @@ function PlainHtmlPreview({
33173
33370
  cancelled = true;
33174
33371
  };
33175
33372
  }, [mdDoc, mediaProvider, mediaRevision]);
33176
- const mergedImages = useMemo44(() => {
33373
+ const mergedImages = useMemo45(() => {
33177
33374
  if (!resolvedImages && !images) return void 0;
33178
33375
  const merged = /* @__PURE__ */ new Map();
33179
33376
  if (resolvedImages) for (const [k2, v2] of resolvedImages) merged.set(k2, v2);
33180
33377
  if (images) for (const [k2, v2] of images) merged.set(k2, v2);
33181
33378
  return merged;
33182
33379
  }, [resolvedImages, images]);
33183
- const iconsCss = useMemo44(() => collectInlineFontAwesomeCss(), []);
33184
- const [renderFn, setRenderFn] = useState59(() => cachedRender);
33185
- useEffect49(() => {
33380
+ const iconsCss = useMemo45(() => collectInlineFontAwesomeCss(), []);
33381
+ const [renderFn, setRenderFn] = useState60(() => cachedRender);
33382
+ useEffect50(() => {
33186
33383
  if (renderFn) return;
33187
33384
  let cancelled = false;
33188
33385
  loadRenderFn().then((fn) => {
@@ -33192,7 +33389,7 @@ function PlainHtmlPreview({
33192
33389
  cancelled = true;
33193
33390
  };
33194
33391
  }, [renderFn]);
33195
- const html = useMemo44(
33392
+ const html = useMemo45(
33196
33393
  () => renderFn ? renderFn(mdDoc, { title, images: mergedImages, theme, iconsCss }) : "",
33197
33394
  [renderFn, mdDoc, title, mergedImages, theme, iconsCss]
33198
33395
  );
@@ -33215,7 +33412,7 @@ function PlainHtmlPreview({
33215
33412
  frameDocument.addEventListener("click", handleClick, true);
33216
33413
  removeFrameLinkHandlerRef.current = () => frameDocument.removeEventListener("click", handleClick, true);
33217
33414
  }, [onLinkClick]);
33218
- useEffect49(() => {
33415
+ useEffect50(() => {
33219
33416
  installFrameLinkHandler();
33220
33417
  return () => removeFrameLinkHandlerRef.current();
33221
33418
  }, [html, installFrameLinkHandler]);
@@ -33311,11 +33508,11 @@ function PlainHtmlPreview({
33311
33508
  style2.remove();
33312
33509
  };
33313
33510
  }, [onCopyCode, showCodeCopyButton]);
33314
- useEffect49(() => {
33511
+ useEffect50(() => {
33315
33512
  installFrameCodeCopyControls();
33316
33513
  return () => removeFrameCodeCopyControlsRef.current();
33317
33514
  }, [html, installFrameCodeCopyControls]);
33318
- useEffect49(() => {
33515
+ useEffect50(() => {
33319
33516
  if (!globalKeyboardShortcuts) return;
33320
33517
  const handleKeyDown = (event) => {
33321
33518
  if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.key !== "ArrowDown" && event.key !== "ArrowUp") {
@@ -33339,7 +33536,7 @@ function PlainHtmlPreview({
33339
33536
  document.addEventListener("keydown", handleKeyDown);
33340
33537
  return () => document.removeEventListener("keydown", handleKeyDown);
33341
33538
  }, [globalKeyboardShortcuts]);
33342
- return /* @__PURE__ */ jsx68(
33539
+ return /* @__PURE__ */ jsx69(
33343
33540
  "iframe",
33344
33541
  {
33345
33542
  ref: setIframeRef,
@@ -33394,7 +33591,7 @@ function collectImageRefs(doc) {
33394
33591
  }
33395
33592
 
33396
33593
  // src/PreviewPanel.tsx
33397
- import { useState as useState62, useEffect as useEffect53, useMemo as useMemo48, useCallback as useCallback49, useRef as useRef52 } from "react";
33594
+ import { useState as useState63, useEffect as useEffect54, useMemo as useMemo49, useCallback as useCallback49, useRef as useRef52 } from "react";
33398
33595
  import { createPortal as createPortal13 } from "react-dom";
33399
33596
  import { DocPlayer as DocPlayer2, LinearDocView as LinearDocView2, useMediaProvider as useMediaProvider2 } from "@bendyline/squisq-react";
33400
33597
  import { resolveTransformStyle as resolveTransformStyle2 } from "@bendyline/squisq/transform";
@@ -33533,15 +33730,15 @@ import {
33533
33730
  createContext as createContext5,
33534
33731
  useCallback as useCallback46,
33535
33732
  useContext as useContext5,
33536
- useEffect as useEffect50,
33733
+ useEffect as useEffect51,
33537
33734
  useId as useId14,
33538
33735
  useLayoutEffect as useLayoutEffect10,
33539
- useMemo as useMemo45,
33736
+ useMemo as useMemo46,
33540
33737
  useRef as useRef49,
33541
- useState as useState60
33738
+ useState as useState61
33542
33739
  } from "react";
33543
33740
  import { createPortal as createPortal12 } from "react-dom";
33544
- import { jsx as jsx69, jsxs as jsxs54 } from "react/jsx-runtime";
33741
+ import { jsx as jsx70, jsxs as jsxs54 } from "react/jsx-runtime";
33545
33742
  var PresentationModeContext = createContext5(null);
33546
33743
  function usePresentationMode() {
33547
33744
  const value = useContext5(PresentationModeContext);
@@ -33621,10 +33818,10 @@ function PresentationModeProvider({
33621
33818
  const { activeView, colorScheme, doc } = useEditorContext();
33622
33819
  const { activeTheme } = usePreviewSettings();
33623
33820
  const popupNameId = useId14().replace(/[^a-zA-Z0-9_-]/g, "");
33624
- const [selectedTarget, setSelectedTarget] = useState60("control");
33625
- const [activeTarget, setActiveTarget] = useState60(null);
33626
- const [popupRoot, setPopupRoot] = useState60(null);
33627
- const [error, setError] = useState60(null);
33821
+ const [selectedTarget, setSelectedTarget] = useState61("control");
33822
+ const [activeTarget, setActiveTarget] = useState61(null);
33823
+ const [popupRoot, setPopupRoot] = useState61(null);
33824
+ const [error, setError] = useState61(null);
33628
33825
  const activeTargetRef = useRef49(activeTarget);
33629
33826
  activeTargetRef.current = activeTarget;
33630
33827
  const previousActiveTargetRef = useRef49(null);
@@ -33632,7 +33829,7 @@ function PresentationModeProvider({
33632
33829
  const popupRef = useRef49(null);
33633
33830
  const popupCleanupRef = useRef49(null);
33634
33831
  const fullscreenSupported = typeof document !== "undefined" && typeof document.documentElement.requestFullscreen === "function";
33635
- const availableTargets = useMemo45(
33832
+ const availableTargets = useMemo46(
33636
33833
  () => [
33637
33834
  "control",
33638
33835
  ...allowWindow ? ["window"] : [],
@@ -33767,12 +33964,12 @@ function PresentationModeProvider({
33767
33964
  },
33768
33965
  [availableTargets, selectedTarget, stop]
33769
33966
  );
33770
- useEffect50(() => {
33967
+ useEffect51(() => {
33771
33968
  if (availableTargets.includes(selectedTarget)) return;
33772
33969
  setSelectedTarget("control");
33773
33970
  if (activeTargetRef.current !== null) void stop();
33774
33971
  }, [availableTargets, selectedTarget, stop]);
33775
- useEffect50(() => {
33972
+ useEffect51(() => {
33776
33973
  const root = rootRef.current;
33777
33974
  const ownerDocument = root?.ownerDocument;
33778
33975
  if (!root || !ownerDocument) return;
@@ -33784,7 +33981,7 @@ function PresentationModeProvider({
33784
33981
  ownerDocument.addEventListener("fullscreenchange", handleFullscreenChange);
33785
33982
  return () => ownerDocument.removeEventListener("fullscreenchange", handleFullscreenChange);
33786
33983
  }, [rootRef]);
33787
- useEffect50(() => {
33984
+ useEffect51(() => {
33788
33985
  const root = rootRef.current;
33789
33986
  if (!root) return;
33790
33987
  if (activeTarget) root.dataset.presentationMode = activeTarget;
@@ -33793,10 +33990,10 @@ function PresentationModeProvider({
33793
33990
  delete root.dataset.presentationMode;
33794
33991
  };
33795
33992
  }, [activeTarget, rootRef]);
33796
- useEffect50(() => {
33993
+ useEffect51(() => {
33797
33994
  if (activeView !== "preview" && activeTargetRef.current !== null) void stop();
33798
33995
  }, [activeView, stop]);
33799
- useEffect50(() => {
33996
+ useEffect51(() => {
33800
33997
  const previous = previousActiveTargetRef.current;
33801
33998
  previousActiveTargetRef.current = activeTarget;
33802
33999
  if (previous === null || activeTarget !== null) return;
@@ -33804,7 +34001,7 @@ function PresentationModeProvider({
33804
34001
  returnFocusRef.current = null;
33805
34002
  if (target?.isConnected) target.focus();
33806
34003
  }, [activeTarget]);
33807
- useEffect50(() => {
34004
+ useEffect51(() => {
33808
34005
  if (activeTarget !== "control") return;
33809
34006
  const ownerDocument = rootRef.current?.ownerDocument;
33810
34007
  if (!ownerDocument) return;
@@ -33816,12 +34013,12 @@ function PresentationModeProvider({
33816
34013
  ownerDocument.addEventListener("keydown", handleKeyDown);
33817
34014
  return () => ownerDocument.removeEventListener("keydown", handleKeyDown);
33818
34015
  }, [activeTarget, rootRef, stop]);
33819
- useEffect50(() => {
34016
+ useEffect51(() => {
33820
34017
  if (!error) return;
33821
34018
  const timer = window.setTimeout(() => setError(null), 6e3);
33822
34019
  return () => window.clearTimeout(timer);
33823
34020
  }, [error]);
33824
- useEffect50(
34021
+ useEffect51(
33825
34022
  () => () => {
33826
34023
  popupCleanupRef.current?.();
33827
34024
  const popup = popupRef.current;
@@ -33834,7 +34031,7 @@ function PresentationModeProvider({
33834
34031
  },
33835
34032
  [rootRef]
33836
34033
  );
33837
- const value = useMemo45(
34034
+ const value = useMemo46(
33838
34035
  () => ({
33839
34036
  selectedTarget,
33840
34037
  activeTarget,
@@ -33873,8 +34070,8 @@ function PresentationModeProvider({
33873
34070
  "aria-label": "Exit presentation mode",
33874
34071
  title: "Exit presentation mode (Esc)",
33875
34072
  children: [
33876
- /* @__PURE__ */ jsx69(Icon, { icon: "fa-solid fa-compress" }),
33877
- /* @__PURE__ */ jsx69("span", { children: "Exit presentation" })
34073
+ /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-compress" }),
34074
+ /* @__PURE__ */ jsx70("span", { children: "Exit presentation" })
33878
34075
  ]
33879
34076
  }
33880
34077
  ) : null;
@@ -33883,7 +34080,7 @@ function PresentationModeProvider({
33883
34080
  (activeTarget === "control" || activeTarget === "fullscreen") && exitButton,
33884
34081
  activeTarget === "window" && popupRoot && exitButton ? createPortal12(exitButton, popupRoot) : null,
33885
34082
  error && typeof document !== "undefined" ? createPortal12(
33886
- /* @__PURE__ */ jsx69("div", { className: "squisq-presentation-error", "data-theme": colorScheme, role: "alert", children: error }),
34083
+ /* @__PURE__ */ jsx70("div", { className: "squisq-presentation-error", "data-theme": colorScheme, role: "alert", children: error }),
33887
34084
  document.body
33888
34085
  ) : null
33889
34086
  ] });
@@ -33924,8 +34121,8 @@ function PresentationModeControl() {
33924
34121
  const { colorScheme } = useEditorContext();
33925
34122
  const triggerRef = useRef49(null);
33926
34123
  const menuRef = useRef49(null);
33927
- const [open, setOpen] = useState60(false);
33928
- const [anchor, setAnchor] = useState60(null);
34124
+ const [open, setOpen] = useState61(false);
34125
+ const [anchor, setAnchor] = useState61(null);
33929
34126
  const options = PRESENTATION_OPTIONS.filter((option) => availableTargets.includes(option.target));
33930
34127
  const selected = options.find((option) => option.target === selectedTarget) ?? PRESENTATION_OPTIONS[0];
33931
34128
  const updatePosition = useCallback46(() => {
@@ -33950,7 +34147,7 @@ function PresentationModeControl() {
33950
34147
  updatePosition();
33951
34148
  setOpen(true);
33952
34149
  }, [updatePosition]);
33953
- useEffect50(() => {
34150
+ useEffect51(() => {
33954
34151
  if (!open) return;
33955
34152
  const handlePointerDown = (event) => {
33956
34153
  const target = event.target;
@@ -33980,7 +34177,7 @@ function PresentationModeControl() {
33980
34177
  (checked ?? first)?.focus();
33981
34178
  }, [anchor, open]);
33982
34179
  return /* @__PURE__ */ jsxs54("div", { className: "squisq-presentation-control", children: [
33983
- /* @__PURE__ */ jsx69(
34180
+ /* @__PURE__ */ jsx70(
33984
34181
  "button",
33985
34182
  {
33986
34183
  type: "button",
@@ -33989,10 +34186,10 @@ function PresentationModeControl() {
33989
34186
  "aria-pressed": activeTarget !== null,
33990
34187
  "data-tooltip": activeTarget ? "Exit presentation" : `Present: ${selected.label}`,
33991
34188
  onClick: () => void (activeTarget ? stop() : start()),
33992
- children: /* @__PURE__ */ jsx69(Icon, { icon: "fa-solid fa-display" })
34189
+ children: /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-display" })
33993
34190
  }
33994
34191
  ),
33995
- options.length > 1 && /* @__PURE__ */ jsx69(
34192
+ options.length > 1 && /* @__PURE__ */ jsx70(
33996
34193
  "button",
33997
34194
  {
33998
34195
  ref: triggerRef,
@@ -34008,11 +34205,11 @@ function PresentationModeControl() {
34008
34205
  event.preventDefault();
34009
34206
  openMenu();
34010
34207
  },
34011
- children: /* @__PURE__ */ jsx69("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx69("path", { d: "M2 3.5 5 6.5 8 3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4" }) })
34208
+ children: /* @__PURE__ */ jsx70("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx70("path", { d: "M2 3.5 5 6.5 8 3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4" }) })
34012
34209
  }
34013
34210
  ),
34014
34211
  open && anchor ? createPortal12(
34015
- /* @__PURE__ */ jsx69(
34212
+ /* @__PURE__ */ jsx70(
34016
34213
  "div",
34017
34214
  {
34018
34215
  ref: menuRef,
@@ -34056,24 +34253,24 @@ function PresentationModeControl() {
34056
34253
  closeMenu(true);
34057
34254
  },
34058
34255
  children: [
34059
- /* @__PURE__ */ jsx69(
34256
+ /* @__PURE__ */ jsx70(
34060
34257
  "span",
34061
34258
  {
34062
34259
  className: "squisq-use-mode-menu-icon squisq-presentation-menu-icon",
34063
34260
  "aria-hidden": "true",
34064
- children: /* @__PURE__ */ jsx69(Icon, { icon: option.icon })
34261
+ children: /* @__PURE__ */ jsx70(Icon, { icon: option.icon })
34065
34262
  }
34066
34263
  ),
34067
34264
  /* @__PURE__ */ jsxs54("span", { className: "squisq-use-mode-menu-copy squisq-presentation-menu-copy", children: [
34068
- /* @__PURE__ */ jsx69("span", { className: "squisq-use-mode-menu-label squisq-presentation-menu-label", children: option.label }),
34069
- /* @__PURE__ */ jsx69("span", { className: "squisq-use-mode-menu-summary squisq-presentation-menu-summary", children: disabled ? "Full screen is unavailable." : option.summary })
34265
+ /* @__PURE__ */ jsx70("span", { className: "squisq-use-mode-menu-label squisq-presentation-menu-label", children: option.label }),
34266
+ /* @__PURE__ */ jsx70("span", { className: "squisq-use-mode-menu-summary squisq-presentation-menu-summary", children: disabled ? "Full screen is unavailable." : option.summary })
34070
34267
  ] }),
34071
- /* @__PURE__ */ jsx69(
34268
+ /* @__PURE__ */ jsx70(
34072
34269
  "span",
34073
34270
  {
34074
34271
  className: "squisq-use-mode-menu-check squisq-presentation-menu-check",
34075
34272
  "aria-hidden": "true",
34076
- children: isSelected && /* @__PURE__ */ jsx69(Icon, { icon: "fa-solid fa-check" })
34273
+ children: isSelected && /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-check" })
34077
34274
  }
34078
34275
  )
34079
34276
  ]
@@ -34093,12 +34290,12 @@ import {
34093
34290
  createContext as createContext6,
34094
34291
  useCallback as useCallback47,
34095
34292
  useContext as useContext6,
34096
- useEffect as useEffect51,
34097
- useMemo as useMemo46,
34293
+ useEffect as useEffect52,
34294
+ useMemo as useMemo47,
34098
34295
  useRef as useRef50,
34099
- useState as useState61
34296
+ useState as useState62
34100
34297
  } from "react";
34101
- import { jsx as jsx70, jsxs as jsxs55 } from "react/jsx-runtime";
34298
+ import { jsx as jsx71, jsxs as jsxs55 } from "react/jsx-runtime";
34102
34299
  var PrintModeContext = createContext6(null);
34103
34300
  function usePrintMode() {
34104
34301
  const value = useContext6(PrintModeContext);
@@ -34111,8 +34308,8 @@ function usePrintModeOptional() {
34111
34308
  function PrintModeProvider({ rootRef, children }) {
34112
34309
  const { activeView } = useEditorContext();
34113
34310
  const { activeTarget: presentationTarget, stop: stopPresentation } = usePresentationMode();
34114
- const [active, setActive] = useState61(false);
34115
- const [slidesPerPage, setSlidesPerPage] = useState61(1);
34311
+ const [active, setActive] = useState62(false);
34312
+ const [slidesPerPage, setSlidesPerPage] = useState62(1);
34116
34313
  const customPrintHandlerRef = useRef50(null);
34117
34314
  const printAncestorsRef = useRef50([]);
34118
34315
  const unmarkPrinting = useCallback47(() => {
@@ -34163,7 +34360,7 @@ function PrintModeProvider({ rootRef, children }) {
34163
34360
  markPrinting();
34164
34361
  ownerWindow.print();
34165
34362
  }, [markPrinting, rootRef]);
34166
- useEffect51(() => {
34363
+ useEffect52(() => {
34167
34364
  const root = rootRef.current;
34168
34365
  if (!root) return;
34169
34366
  if (active) root.dataset.printPreview = "true";
@@ -34172,10 +34369,10 @@ function PrintModeProvider({ rootRef, children }) {
34172
34369
  delete root.dataset.printPreview;
34173
34370
  };
34174
34371
  }, [active, rootRef]);
34175
- useEffect51(() => {
34372
+ useEffect52(() => {
34176
34373
  if (activeView !== "preview" && active) close();
34177
34374
  }, [active, activeView, close]);
34178
- useEffect51(() => {
34375
+ useEffect52(() => {
34179
34376
  if (!active) return;
34180
34377
  const ownerWindow = rootRef.current?.ownerDocument.defaultView;
34181
34378
  const ownerDocument = rootRef.current?.ownerDocument;
@@ -34197,7 +34394,7 @@ function PrintModeProvider({ rootRef, children }) {
34197
34394
  handleAfterPrint();
34198
34395
  };
34199
34396
  }, [active, close, markPrinting, rootRef, unmarkPrinting]);
34200
- const value = useMemo46(
34397
+ const value = useMemo47(
34201
34398
  () => ({
34202
34399
  active,
34203
34400
  slidesPerPage,
@@ -34209,7 +34406,7 @@ function PrintModeProvider({ rootRef, children }) {
34209
34406
  }),
34210
34407
  [active, close, open, print, registerPrintHandler, slidesPerPage]
34211
34408
  );
34212
- return /* @__PURE__ */ jsx70(PrintModeContext.Provider, { value, children });
34409
+ return /* @__PURE__ */ jsx71(PrintModeContext.Provider, { value, children });
34213
34410
  }
34214
34411
  function PrintModeControl() {
34215
34412
  const { open } = usePrintMode();
@@ -34222,8 +34419,8 @@ function PrintModeControl() {
34222
34419
  "aria-label": "Print",
34223
34420
  "data-tooltip": "Print",
34224
34421
  children: [
34225
- /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-print" }),
34226
- /* @__PURE__ */ jsx70("span", { children: "Print" })
34422
+ /* @__PURE__ */ jsx71(Icon, { icon: "fa-solid fa-print" }),
34423
+ /* @__PURE__ */ jsx71("span", { children: "Print" })
34227
34424
  ]
34228
34425
  }
34229
34426
  );
@@ -34233,8 +34430,8 @@ function PrintPreviewToolbar() {
34233
34430
  const { activeDisplayMode } = usePreviewSettings();
34234
34431
  const { slidesPerPage, setSlidesPerPage, print, close } = usePrintMode();
34235
34432
  return /* @__PURE__ */ jsxs55("div", { className: "squisq-print-toolbar", "aria-label": "Print preview controls", children: [
34236
- /* @__PURE__ */ jsx70("span", { className: "squisq-print-toolbar-title", children: "Print preview" }),
34237
- activeDisplayMode === "slideshow" && /* @__PURE__ */ jsx70("div", { className: "squisq-print-density", role: "group", "aria-label": "Slides per page", children: SLIDES_PER_PAGE_OPTIONS.map((value) => /* @__PURE__ */ jsxs55(
34433
+ /* @__PURE__ */ jsx71("span", { className: "squisq-print-toolbar-title", children: "Print preview" }),
34434
+ activeDisplayMode === "slideshow" && /* @__PURE__ */ jsx71("div", { className: "squisq-print-density", role: "group", "aria-label": "Slides per page", children: SLIDES_PER_PAGE_OPTIONS.map((value) => /* @__PURE__ */ jsxs55(
34238
34435
  "button",
34239
34436
  {
34240
34437
  type: "button",
@@ -34243,7 +34440,7 @@ function PrintPreviewToolbar() {
34243
34440
  "aria-label": `${value} ${value === 1 ? "slide" : "slides"} per page`,
34244
34441
  onClick: () => setSlidesPerPage(value),
34245
34442
  children: [
34246
- /* @__PURE__ */ jsx70("span", { children: value }),
34443
+ /* @__PURE__ */ jsx71("span", { children: value }),
34247
34444
  /* @__PURE__ */ jsxs55("span", { className: "squisq-print-density-label", children: [
34248
34445
  " ",
34249
34446
  value === 1 ? "slide" : "slides",
@@ -34253,20 +34450,20 @@ function PrintPreviewToolbar() {
34253
34450
  },
34254
34451
  value
34255
34452
  )) }),
34256
- /* @__PURE__ */ jsx70("div", { className: "squisq-print-toolbar-spacer" }),
34453
+ /* @__PURE__ */ jsx71("div", { className: "squisq-print-toolbar-spacer" }),
34257
34454
  /* @__PURE__ */ jsxs55("button", { type: "button", className: "squisq-print-action", onClick: print, children: [
34258
- /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-print" }),
34259
- /* @__PURE__ */ jsx70("span", { children: "Print" })
34455
+ /* @__PURE__ */ jsx71(Icon, { icon: "fa-solid fa-print" }),
34456
+ /* @__PURE__ */ jsx71("span", { children: "Print" })
34260
34457
  ] }),
34261
34458
  /* @__PURE__ */ jsxs55("button", { type: "button", className: "squisq-print-close", onClick: close, children: [
34262
- /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-xmark" }),
34263
- /* @__PURE__ */ jsx70("span", { children: "Close" })
34459
+ /* @__PURE__ */ jsx71(Icon, { icon: "fa-solid fa-xmark" }),
34460
+ /* @__PURE__ */ jsx71("span", { children: "Close" })
34264
34461
  ] })
34265
34462
  ] });
34266
34463
  }
34267
34464
 
34268
34465
  // src/print/PrintPreview.tsx
34269
- import { useCallback as useCallback48, useEffect as useEffect52, useMemo as useMemo47, useRef as useRef51 } from "react";
34466
+ import { useCallback as useCallback48, useEffect as useEffect53, useMemo as useMemo48, useRef as useRef51 } from "react";
34270
34467
  import {
34271
34468
  BlockRenderer as BlockRenderer5,
34272
34469
  LinearDocView,
@@ -34278,7 +34475,7 @@ import {
34278
34475
  } from "@bendyline/squisq/schemas";
34279
34476
  import { expandCoverBlock as expandCoverBlock2 } from "@bendyline/squisq/doc";
34280
34477
  import { resolveTransformStyle } from "@bendyline/squisq/transform";
34281
- import { jsx as jsx71, jsxs as jsxs56 } from "react/jsx-runtime";
34478
+ import { jsx as jsx72, jsxs as jsxs56 } from "react/jsx-runtime";
34282
34479
  function chunk(values, size) {
34283
34480
  const groups = [];
34284
34481
  for (let index2 = 0; index2 < values.length; index2 += size) {
@@ -34305,7 +34502,7 @@ function PrintPreview({
34305
34502
  documentFrameRef.current = frame;
34306
34503
  }, []);
34307
34504
  const { blocks } = useDocPlayback(previewDoc, 0, { viewport, theme });
34308
- const coverBlock = useMemo47(() => {
34505
+ const coverBlock = useMemo48(() => {
34309
34506
  if (!showCover || !previewDoc?.startBlock) return null;
34310
34507
  const context = createTemplateContext2(theme, 0, 1, viewport);
34311
34508
  return {
@@ -34317,7 +34514,7 @@ function PrintPreview({
34317
34514
  };
34318
34515
  }, [previewDoc?.startBlock, showCover, theme, viewport]);
34319
34516
  const isTextDocument = displayMode === "page" || displayMode === "narrate";
34320
- useEffect52(() => {
34517
+ useEffect53(() => {
34321
34518
  if (!isTextDocument) return registerPrintHandler(null);
34322
34519
  return registerPrintHandler(() => {
34323
34520
  const frameWindow = documentFrameRef.current?.contentWindow;
@@ -34327,7 +34524,7 @@ function PrintPreview({
34327
34524
  }, [isTextDocument, registerPrintHandler]);
34328
34525
  const title = contentDoc?.frontmatter?.title ?? contentDoc?.startBlock?.title ?? void 0;
34329
34526
  if (isTextDocument) {
34330
- return /* @__PURE__ */ jsx71("div", { className: "squisq-print-preview squisq-print-preview--document", children: /* @__PURE__ */ jsx71("div", { className: "squisq-print-document-paper", children: /* @__PURE__ */ jsx71(
34527
+ return /* @__PURE__ */ jsx72("div", { className: "squisq-print-preview squisq-print-preview--document", children: /* @__PURE__ */ jsx72("div", { className: "squisq-print-document-paper", children: /* @__PURE__ */ jsx72(
34331
34528
  PlainHtmlPreview,
34332
34529
  {
34333
34530
  markdown: documentMarkdown,
@@ -34341,8 +34538,8 @@ function PrintPreview({
34341
34538
  }
34342
34539
  if (displayMode === "linear") {
34343
34540
  return /* @__PURE__ */ jsxs56("div", { className: "squisq-print-preview squisq-print-preview--page", children: [
34344
- /* @__PURE__ */ jsx71("style", { children: "@page { margin: 0; }" }),
34345
- /* @__PURE__ */ jsx71("div", { className: "squisq-print-page-paper", children: /* @__PURE__ */ jsx71(
34541
+ /* @__PURE__ */ jsx72("style", { children: "@page { margin: 0; }" }),
34542
+ /* @__PURE__ */ jsx72("div", { className: "squisq-print-page-paper", children: /* @__PURE__ */ jsx72(
34346
34543
  LinearDocView,
34347
34544
  {
34348
34545
  className: "squisq-print-linear",
@@ -34372,14 +34569,14 @@ function PrintPreview({
34372
34569
  "data-slides-per-page": density,
34373
34570
  style: previewStyle,
34374
34571
  children: [
34375
- /* @__PURE__ */ jsx71("style", { children: `@page { size: ${orientation}; margin: 0; }` }),
34376
- sheets.map((sheet, pageIndex) => /* @__PURE__ */ jsx71(
34572
+ /* @__PURE__ */ jsx72("style", { children: `@page { size: ${orientation}; margin: 0; }` }),
34573
+ sheets.map((sheet, pageIndex) => /* @__PURE__ */ jsx72(
34377
34574
  "div",
34378
34575
  {
34379
34576
  className: "squisq-print-sheet",
34380
34577
  "data-slides-per-page": density,
34381
34578
  "aria-label": `Print page ${pageIndex + 1}`,
34382
- children: sheet.map((block) => /* @__PURE__ */ jsx71("div", { className: "squisq-print-slide-cell", children: /* @__PURE__ */ jsx71("div", { className: "squisq-print-slide-frame", children: /* @__PURE__ */ jsx71(
34579
+ children: sheet.map((block) => /* @__PURE__ */ jsx72("div", { className: "squisq-print-slide-cell", children: /* @__PURE__ */ jsx72("div", { className: "squisq-print-slide-frame", children: /* @__PURE__ */ jsx72(
34383
34580
  BlockRenderer5,
34384
34581
  {
34385
34582
  block,
@@ -34393,14 +34590,14 @@ function PrintPreview({
34393
34590
  },
34394
34591
  `${density}-${pageIndex}`
34395
34592
  )),
34396
- sheets.length === 0 && /* @__PURE__ */ jsx71("p", { className: "squisq-print-empty", children: "Nothing to print." })
34593
+ sheets.length === 0 && /* @__PURE__ */ jsx72("p", { className: "squisq-print-empty", children: "Nothing to print." })
34397
34594
  ]
34398
34595
  }
34399
34596
  );
34400
34597
  }
34401
34598
 
34402
34599
  // src/PreviewPanel.tsx
34403
- import { Fragment as Fragment20, jsx as jsx72, jsxs as jsxs57 } from "react/jsx-runtime";
34600
+ import { Fragment as Fragment20, jsx as jsx73, jsxs as jsxs57 } from "react/jsx-runtime";
34404
34601
  function PreviewPanel({
34405
34602
  basePath = "/",
34406
34603
  className,
@@ -34419,7 +34616,8 @@ function PreviewPanel({
34419
34616
  bumpMediaRevision,
34420
34617
  allowRecording,
34421
34618
  colorScheme,
34422
- fileName
34619
+ fileName,
34620
+ fenceRenderers
34423
34621
  } = useEditorContext();
34424
34622
  const mediaProvider = useMediaProvider2();
34425
34623
  const presentation = usePresentationModeOptional();
@@ -34443,7 +34641,7 @@ function PreviewPanel({
34443
34641
  } = usePreviewSettings();
34444
34642
  const mainSurfaceRef = useRef52(null);
34445
34643
  const popupSurfaceRef = useRef52(null);
34446
- const [playbackState, setPlaybackState] = useState62(null);
34644
+ const [playbackState, setPlaybackState] = useState63(null);
34447
34645
  const handlePlaybackStateChange = useCallback49((next) => {
34448
34646
  setPlaybackState(next);
34449
34647
  }, []);
@@ -34455,7 +34653,7 @@ function PreviewPanel({
34455
34653
  );
34456
34654
  const previewDoc = previewProjection?.playerDoc ?? null;
34457
34655
  const contentDoc = previewProjection?.contentDoc ?? null;
34458
- const followerAudioController = useMemo48(() => {
34656
+ const followerAudioController = useMemo49(() => {
34459
34657
  if (!playbackState || !previewDoc) return null;
34460
34658
  const noOp = () => Promise.resolve();
34461
34659
  return {
@@ -34474,18 +34672,18 @@ function PreviewPanel({
34474
34672
  restart: noOp
34475
34673
  };
34476
34674
  }, [playbackState, previewDoc]);
34477
- const documentMarkdown = useMemo48(
34675
+ const documentMarkdown = useMemo49(
34478
34676
  () => activeTransformStyle && contentDoc ? buildDocumentPreviewMarkdown(contentDoc) : markdownSource,
34479
34677
  [activeTransformStyle, contentDoc, markdownSource]
34480
34678
  );
34481
34679
  const isDocumentMode = activeDisplayMode === "page";
34482
34680
  const isPageMode = activeDisplayMode === "linear";
34483
34681
  const isNarrateMode = activeDisplayMode === "narrate";
34484
- useEffect53(() => {
34682
+ useEffect54(() => {
34485
34683
  if (presentation?.activeTarget === "window") return;
34486
34684
  setPlaybackState(null);
34487
34685
  }, [presentation?.activeTarget]);
34488
- useEffect53(() => {
34686
+ useEffect54(() => {
34489
34687
  if (presentation?.activeTarget !== "window" || !presentation.popupRoot) return;
34490
34688
  const mainRoot = mainSurfaceRef.current;
34491
34689
  const followerRoot = popupSurfaceRef.current;
@@ -34548,22 +34746,22 @@ function PreviewPanel({
34548
34746
  presentation?.popupRoot
34549
34747
  ]);
34550
34748
  if (isParsing && !isNarrateMode && !previewDoc) {
34551
- return /* @__PURE__ */ jsx72("div", { className: `squisq-preview-status ${className || ""}`, "data-testid": "preview-panel", children: /* @__PURE__ */ jsx72("p", { children: "Parsing\u2026" }) });
34749
+ return /* @__PURE__ */ jsx73("div", { className: `squisq-preview-status ${className || ""}`, "data-testid": "preview-panel", children: /* @__PURE__ */ jsx73("p", { children: "Parsing\u2026" }) });
34552
34750
  }
34553
34751
  if (parseError && !isNarrateMode) {
34554
34752
  return /* @__PURE__ */ jsxs57("div", { className: `squisq-preview-status ${className || ""}`, "data-testid": "preview-panel", children: [
34555
- /* @__PURE__ */ jsx72("h3", { children: "Parse Error" }),
34556
- /* @__PURE__ */ jsx72("pre", { children: parseError })
34753
+ /* @__PURE__ */ jsx73("h3", { children: "Parse Error" }),
34754
+ /* @__PURE__ */ jsx73("pre", { children: parseError })
34557
34755
  ] });
34558
34756
  }
34559
34757
  if (!previewDoc && !isDocumentMode && !isNarrateMode) {
34560
- return /* @__PURE__ */ jsx72("div", { className: `squisq-preview-status ${className || ""}`, "data-testid": "preview-panel", children: /* @__PURE__ */ jsx72("p", { children: "No content to preview. Start typing in the editor." }) });
34758
+ return /* @__PURE__ */ jsx73("div", { className: `squisq-preview-status ${className || ""}`, "data-testid": "preview-panel", children: /* @__PURE__ */ jsx73("p", { children: "No content to preview. Start typing in the editor." }) });
34561
34759
  }
34562
34760
  const fillsContainer = printMode?.active || isDocumentMode || isPageMode || isNarrateMode ? "stretch" : "center";
34563
34761
  const audienceWindowOpen = presentation?.activeTarget === "window";
34564
34762
  const renderSurface = (audience) => {
34565
34763
  if (!audience && printMode?.active) {
34566
- return /* @__PURE__ */ jsx72(
34764
+ return /* @__PURE__ */ jsx73(
34567
34765
  PrintPreview,
34568
34766
  {
34569
34767
  displayMode: activeDisplayMode,
@@ -34580,7 +34778,7 @@ function PreviewPanel({
34580
34778
  );
34581
34779
  }
34582
34780
  if (isDocumentMode) {
34583
- return /* @__PURE__ */ jsx72(
34781
+ return /* @__PURE__ */ jsx73(
34584
34782
  PlainHtmlPreview,
34585
34783
  {
34586
34784
  markdown: documentMarkdown,
@@ -34597,7 +34795,7 @@ function PreviewPanel({
34597
34795
  }
34598
34796
  if (isNarrateMode) {
34599
34797
  if (audience) return null;
34600
- return /* @__PURE__ */ jsx72(
34798
+ return /* @__PURE__ */ jsx73(
34601
34799
  TeleprompterView,
34602
34800
  {
34603
34801
  doc,
@@ -34616,7 +34814,7 @@ function PreviewPanel({
34616
34814
  );
34617
34815
  }
34618
34816
  if (isPageMode) {
34619
- return /* @__PURE__ */ jsx72(
34817
+ return /* @__PURE__ */ jsx73(
34620
34818
  LinearDocView2,
34621
34819
  {
34622
34820
  doc: contentDoc ?? doc,
@@ -34627,15 +34825,16 @@ function PreviewPanel({
34627
34825
  showCover: activeCoverSlide,
34628
34826
  transformPage: activeTransformStyle ? resolveTransformStyle2(activeTransformStyle).page : void 0,
34629
34827
  showCodeCopyButton,
34630
- onCopyCode
34828
+ onCopyCode,
34829
+ fenceRenderers: fenceRenderers ?? void 0
34631
34830
  }
34632
34831
  );
34633
34832
  }
34634
34833
  if (audience && !followerAudioController) {
34635
- return /* @__PURE__ */ jsx72("div", { className: "squisq-presentation-connecting", children: "Connecting presentation..." });
34834
+ return /* @__PURE__ */ jsx73("div", { className: "squisq-presentation-connecting", children: "Connecting presentation..." });
34636
34835
  }
34637
34836
  const audienceCaptionMode = playbackState?.captionMode;
34638
- return /* @__PURE__ */ jsx72(
34837
+ return /* @__PURE__ */ jsx73(
34639
34838
  DocPlayer2,
34640
34839
  {
34641
34840
  doc: previewDoc,
@@ -34678,7 +34877,7 @@ function PreviewPanel({
34678
34877
  background: presentation?.activeTarget ? activeTheme.colors.background : void 0
34679
34878
  };
34680
34879
  return /* @__PURE__ */ jsxs57(Fragment20, { children: [
34681
- /* @__PURE__ */ jsx72(
34880
+ /* @__PURE__ */ jsx73(
34682
34881
  "div",
34683
34882
  {
34684
34883
  className: `squisq-preview-container ${className || ""}`,
@@ -34691,16 +34890,16 @@ function PreviewPanel({
34691
34890
  overflow: "hidden",
34692
34891
  background: "var(--squisq-bg, #f5f5f5)"
34693
34892
  },
34694
- children: /* @__PURE__ */ jsx72("div", { ref: mainSurfaceRef, className: "squisq-preview-player", style: surfaceStyle, children: renderSurface(false) })
34893
+ children: /* @__PURE__ */ jsx73("div", { ref: mainSurfaceRef, className: "squisq-preview-player", style: surfaceStyle, children: renderSurface(false) })
34695
34894
  }
34696
34895
  ),
34697
34896
  audienceWindowOpen && presentation?.popupRoot && !isNarrateMode ? createPortal13(
34698
- /* @__PURE__ */ jsx72(
34897
+ /* @__PURE__ */ jsx73(
34699
34898
  "div",
34700
34899
  {
34701
34900
  className: "squisq-editor-shell squisq-presentation-window",
34702
34901
  "data-theme": colorScheme,
34703
- children: /* @__PURE__ */ jsx72("div", { className: "squisq-preview-container squisq-presentation-window-preview", children: /* @__PURE__ */ jsx72(
34902
+ children: /* @__PURE__ */ jsx73("div", { className: "squisq-preview-container squisq-presentation-window-preview", children: /* @__PURE__ */ jsx73(
34704
34903
  "div",
34705
34904
  {
34706
34905
  ref: popupSurfaceRef,
@@ -34718,8 +34917,8 @@ function PreviewPanel({
34718
34917
  }
34719
34918
 
34720
34919
  // src/MediaBin.tsx
34721
- import { useState as useState63, useEffect as useEffect54, useRef as useRef53, useCallback as useCallback50 } from "react";
34722
- import { jsx as jsx73, jsxs as jsxs58 } from "react/jsx-runtime";
34920
+ import { useState as useState64, useEffect as useEffect55, useRef as useRef53, useCallback as useCallback50 } from "react";
34921
+ import { jsx as jsx74, jsxs as jsxs58 } from "react/jsx-runtime";
34723
34922
  function formatSize(bytes) {
34724
34923
  if (bytes < 1024) return `${bytes} B`;
34725
34924
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -34783,12 +34982,12 @@ function MediaBin({
34783
34982
  isRecorderOpen = false,
34784
34983
  allowBinaryDownloads = true
34785
34984
  }) {
34786
- const [entries, setEntries] = useState63([]);
34787
- const [thumbUrls, setThumbUrls] = useState63({});
34788
- const [loading, setLoading] = useState63(false);
34789
- const [isDropActive, setIsDropActive] = useState63(false);
34790
- const [downloadingPath, setDownloadingPath] = useState63(null);
34791
- const [contextMenu, setContextMenu] = useState63(null);
34985
+ const [entries, setEntries] = useState64([]);
34986
+ const [thumbUrls, setThumbUrls] = useState64({});
34987
+ const [loading, setLoading] = useState64(false);
34988
+ const [isDropActive, setIsDropActive] = useState64(false);
34989
+ const [downloadingPath, setDownloadingPath] = useState64(null);
34990
+ const [contextMenu, setContextMenu] = useState64(null);
34792
34991
  const fileInputRef = useRef53(null);
34793
34992
  const contextMenuRef = useRef53(null);
34794
34993
  const dropDepthRef = useRef53(0);
@@ -34810,7 +35009,7 @@ function MediaBin({
34810
35009
  },
34811
35010
  [onCountChange]
34812
35011
  );
34813
- useEffect54(() => {
35012
+ useEffect55(() => {
34814
35013
  if (!contextMenu) return;
34815
35014
  const handlePointerDown = (event) => {
34816
35015
  if (contextMenuRef.current?.contains(event.target)) return;
@@ -34831,7 +35030,7 @@ function MediaBin({
34831
35030
  window.removeEventListener("resize", close);
34832
35031
  };
34833
35032
  }, [contextMenu]);
34834
- useEffect54(() => {
35033
+ useEffect55(() => {
34835
35034
  if (!mediaProvider) {
34836
35035
  setEntries([]);
34837
35036
  setThumbUrls({});
@@ -35036,12 +35235,12 @@ function MediaBin({
35036
35235
  "aria-haspopup": "dialog",
35037
35236
  "aria-expanded": isRecorderOpen,
35038
35237
  children: [
35039
- /* @__PURE__ */ jsx73("span", { className: "squisq-media-bin-record-dot", "aria-hidden": "true" }),
35238
+ /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-record-dot", "aria-hidden": "true" }),
35040
35239
  "Record"
35041
35240
  ]
35042
35241
  }
35043
35242
  ),
35044
- /* @__PURE__ */ jsx73(
35243
+ /* @__PURE__ */ jsx74(
35045
35244
  "button",
35046
35245
  {
35047
35246
  type: "button",
@@ -35057,10 +35256,10 @@ function MediaBin({
35057
35256
  /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-list", children: [
35058
35257
  !mediaProvider && /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-empty", children: [
35059
35258
  "No media context.",
35060
- /* @__PURE__ */ jsx73("br", {}),
35259
+ /* @__PURE__ */ jsx74("br", {}),
35061
35260
  "Load a content zip or select a storage slot."
35062
35261
  ] }),
35063
- mediaProvider && entries.length === 0 && !loading && /* @__PURE__ */ jsx73("div", { className: "squisq-media-bin-empty", children: "No files yet." }),
35262
+ mediaProvider && entries.length === 0 && !loading && /* @__PURE__ */ jsx74("div", { className: "squisq-media-bin-empty", children: "No files yet." }),
35064
35263
  entries.map((entry) => {
35065
35264
  const thumb = thumbUrls[entry.name];
35066
35265
  const basename = basenameForPath(entry.name);
@@ -35092,7 +35291,7 @@ ${formatSize(entry.size)}`,
35092
35291
  onDragStart: handleDragStart,
35093
35292
  onKeyDown: (e2) => handleItemKeyDown(entry, e2),
35094
35293
  children: [
35095
- thumb ? /* @__PURE__ */ jsx73(
35294
+ thumb ? /* @__PURE__ */ jsx74(
35096
35295
  "img",
35097
35296
  {
35098
35297
  src: thumb,
@@ -35100,15 +35299,15 @@ ${formatSize(entry.size)}`,
35100
35299
  className: "squisq-media-bin-thumb",
35101
35300
  draggable: false
35102
35301
  }
35103
- ) : /* @__PURE__ */ jsx73("span", { className: "squisq-media-bin-icon", children: iconForMime(entry.mimeType) }),
35302
+ ) : /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-icon", children: iconForMime(entry.mimeType) }),
35104
35303
  /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-meta", children: [
35105
- /* @__PURE__ */ jsx73("div", { className: "squisq-media-bin-name", children: basename }),
35304
+ /* @__PURE__ */ jsx74("div", { className: "squisq-media-bin-name", children: basename }),
35106
35305
  /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-detail-row", children: [
35107
- /* @__PURE__ */ jsx73("span", { className: "squisq-media-bin-size", children: formatSize(entry.size) }),
35108
- isUnused && /* @__PURE__ */ jsx73("span", { className: "squisq-media-bin-unused-badge", title: "Not used in document", children: "Unused" })
35306
+ /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-size", children: formatSize(entry.size) }),
35307
+ isUnused && /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-unused-badge", title: "Not used in document", children: "Unused" })
35109
35308
  ] })
35110
35309
  ] }),
35111
- allowBinaryDownloads && /* @__PURE__ */ jsx73(
35310
+ allowBinaryDownloads && /* @__PURE__ */ jsx74(
35112
35311
  "button",
35113
35312
  {
35114
35313
  type: "button",
@@ -35122,7 +35321,7 @@ ${formatSize(entry.size)}`,
35122
35321
  void handleDownloadEntry(entry);
35123
35322
  },
35124
35323
  onDragStart: (event) => event.preventDefault(),
35125
- children: /* @__PURE__ */ jsx73("span", { "aria-hidden": "true", children: downloadingPath === entry.name ? "\u2026" : "\u2193" })
35324
+ children: /* @__PURE__ */ jsx74("span", { "aria-hidden": "true", children: downloadingPath === entry.name ? "\u2026" : "\u2193" })
35126
35325
  }
35127
35326
  )
35128
35327
  ]
@@ -35132,11 +35331,11 @@ ${formatSize(entry.size)}`,
35132
35331
  })
35133
35332
  ] }),
35134
35333
  isDropActive && /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-drop-target", "aria-hidden": "true", children: [
35135
- /* @__PURE__ */ jsx73("span", { className: "squisq-media-bin-drop-target-icon", children: "+" }),
35136
- /* @__PURE__ */ jsx73("strong", { children: "Drop images here" }),
35137
- /* @__PURE__ */ jsx73("span", { children: "Add to Files" })
35334
+ /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-drop-target-icon", children: "+" }),
35335
+ /* @__PURE__ */ jsx74("strong", { children: "Drop images here" }),
35336
+ /* @__PURE__ */ jsx74("span", { children: "Add to Files" })
35138
35337
  ] }),
35139
- contextMenu && /* @__PURE__ */ jsx73(
35338
+ contextMenu && /* @__PURE__ */ jsx74(
35140
35339
  "div",
35141
35340
  {
35142
35341
  ref: contextMenuRef,
@@ -35144,7 +35343,7 @@ ${formatSize(entry.size)}`,
35144
35343
  role: "menu",
35145
35344
  "aria-label": `${contextMenu.entry.name} actions`,
35146
35345
  style: contextMenuStyle,
35147
- children: /* @__PURE__ */ jsx73(
35346
+ children: /* @__PURE__ */ jsx74(
35148
35347
  "button",
35149
35348
  {
35150
35349
  type: "button",
@@ -35157,7 +35356,7 @@ ${formatSize(entry.size)}`,
35157
35356
  )
35158
35357
  }
35159
35358
  ),
35160
- /* @__PURE__ */ jsx73(
35359
+ /* @__PURE__ */ jsx74(
35161
35360
  "input",
35162
35361
  {
35163
35362
  ref: fileInputRef,
@@ -35173,8 +35372,8 @@ ${formatSize(entry.size)}`,
35173
35372
  }
35174
35373
 
35175
35374
  // src/DropZoneOverlay.tsx
35176
- import { useState as useState64 } from "react";
35177
- import { Fragment as Fragment21, jsx as jsx74, jsxs as jsxs59 } from "react/jsx-runtime";
35375
+ import { useState as useState65 } from "react";
35376
+ import { Fragment as Fragment21, jsx as jsx75, jsxs as jsxs59 } from "react/jsx-runtime";
35178
35377
  function DropZoneOverlay({
35179
35378
  dragContentType,
35180
35379
  zoneProps,
@@ -35182,8 +35381,8 @@ function DropZoneOverlay({
35182
35381
  }) {
35183
35382
  const showMedia = dragContentType === "media" || dragContentType === "mixed";
35184
35383
  const showText = dragContentType === "text" || dragContentType === "mixed";
35185
- return /* @__PURE__ */ jsx74("div", { className: "squisq-drop-overlay", children: /* @__PURE__ */ jsxs59("div", { className: "squisq-drop-overlay-inner", children: [
35186
- showMedia && /* @__PURE__ */ jsx74(
35384
+ return /* @__PURE__ */ jsx75("div", { className: "squisq-drop-overlay", children: /* @__PURE__ */ jsxs59("div", { className: "squisq-drop-overlay-inner", children: [
35385
+ showMedia && /* @__PURE__ */ jsx75(
35187
35386
  DropZone,
35188
35387
  {
35189
35388
  target: "media",
@@ -35196,7 +35395,7 @@ function DropZoneOverlay({
35196
35395
  }
35197
35396
  ),
35198
35397
  showText && /* @__PURE__ */ jsxs59(Fragment21, { children: [
35199
- /* @__PURE__ */ jsx74(
35398
+ /* @__PURE__ */ jsx75(
35200
35399
  DropZone,
35201
35400
  {
35202
35401
  target: "insert",
@@ -35207,7 +35406,7 @@ function DropZoneOverlay({
35207
35406
  variant: "insert"
35208
35407
  }
35209
35408
  ),
35210
- /* @__PURE__ */ jsx74(
35409
+ /* @__PURE__ */ jsx75(
35211
35410
  DropZone,
35212
35411
  {
35213
35412
  target: "replace",
@@ -35230,7 +35429,7 @@ function DropZone({
35230
35429
  disabled,
35231
35430
  variant
35232
35431
  }) {
35233
- const [isHovering, setIsHovering] = useState64(false);
35432
+ const [isHovering, setIsHovering] = useState65(false);
35234
35433
  const props = zoneProps(target);
35235
35434
  return /* @__PURE__ */ jsxs59(
35236
35435
  "div",
@@ -35265,16 +35464,16 @@ function DropZone({
35265
35464
  props.onDrop(e2);
35266
35465
  },
35267
35466
  children: [
35268
- /* @__PURE__ */ jsx74("span", { className: "squisq-drop-zone-icon", children: icon }),
35269
- /* @__PURE__ */ jsx74("span", { className: "squisq-drop-zone-label", children: label }),
35270
- /* @__PURE__ */ jsx74("span", { className: "squisq-drop-zone-desc", children: description })
35467
+ /* @__PURE__ */ jsx75("span", { className: "squisq-drop-zone-icon", children: icon }),
35468
+ /* @__PURE__ */ jsx75("span", { className: "squisq-drop-zone-label", children: label }),
35469
+ /* @__PURE__ */ jsx75("span", { className: "squisq-drop-zone-desc", children: description })
35271
35470
  ]
35272
35471
  }
35273
35472
  );
35274
35473
  }
35275
35474
 
35276
35475
  // src/Tooltip.tsx
35277
- import { useEffect as useEffect55, useLayoutEffect as useLayoutEffect11, useRef as useRef54, useState as useState65 } from "react";
35476
+ import { useEffect as useEffect56, useLayoutEffect as useLayoutEffect11, useRef as useRef54, useState as useState66 } from "react";
35278
35477
  import { createPortal as createPortal14 } from "react-dom";
35279
35478
 
35280
35479
  // src/tooltipPlacement.ts
@@ -35287,10 +35486,10 @@ function clampTooltipLeft(anchorX, tooltipWidth, viewportWidth, edgePadding = ED
35287
35486
  }
35288
35487
 
35289
35488
  // src/Tooltip.tsx
35290
- import { jsx as jsx75 } from "react/jsx-runtime";
35489
+ import { jsx as jsx76 } from "react/jsx-runtime";
35291
35490
  var SHOW_DELAY_MS = 180;
35292
35491
  function TooltipLayer() {
35293
- const [state, setState3] = useState65(null);
35492
+ const [state, setState3] = useState66(null);
35294
35493
  const tooltipRef = useRef54(null);
35295
35494
  const timerRef = useRef54(null);
35296
35495
  const currentTargetRef = useRef54(null);
@@ -35306,7 +35505,7 @@ function TooltipLayer() {
35306
35505
  node2.style.left = `${left}px`;
35307
35506
  node2.style.visibility = "visible";
35308
35507
  }, [state]);
35309
- useEffect55(() => {
35508
+ useEffect56(() => {
35310
35509
  const clearTimer = () => {
35311
35510
  if (timerRef.current) {
35312
35511
  clearTimeout(timerRef.current);
@@ -35372,7 +35571,7 @@ function TooltipLayer() {
35372
35571
  }, []);
35373
35572
  if (!state) return null;
35374
35573
  return createPortal14(
35375
- /* @__PURE__ */ jsx75(
35574
+ /* @__PURE__ */ jsx76(
35376
35575
  "div",
35377
35576
  {
35378
35577
  role: "tooltip",
@@ -35392,35 +35591,35 @@ function TooltipLayer() {
35392
35591
  }
35393
35592
 
35394
35593
  // src/EditorShell.tsx
35395
- import { useEffect as useEffect56, useRef as useRef55, useState as useState66, useCallback as useCallback51, useMemo as useMemo50 } from "react";
35594
+ import { useEffect as useEffect57, useRef as useRef55, useState as useState67, useCallback as useCallback51, useMemo as useMemo51 } from "react";
35396
35595
 
35397
35596
  // src/BlockPreviewPanel.tsx
35398
- import { useMemo as useMemo49 } from "react";
35597
+ import { useMemo as useMemo50 } from "react";
35399
35598
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS7 } from "@bendyline/squisq/schemas";
35400
35599
  import { flattenBlocks as flattenBlocks7, DEFAULT_THEME as DEFAULT_THEME7 } from "@bendyline/squisq/doc";
35401
- import { jsx as jsx76 } from "react/jsx-runtime";
35600
+ import { jsx as jsx77 } from "react/jsx-runtime";
35402
35601
  function BlockPreviewPanel({ basePath = "/" }) {
35403
35602
  const { doc, activeBlockStartLine, mediaProvider } = useEditorContext();
35404
35603
  const previewSettings = usePreviewSettingsOptional();
35405
35604
  const theme = previewSettings?.activeTheme ?? DEFAULT_THEME7;
35406
35605
  const viewport = previewSettings?.activeViewport ?? VIEWPORT_PRESETS7.landscape;
35407
- const block = useMemo49(() => {
35606
+ const block = useMemo50(() => {
35408
35607
  if (!doc) return null;
35409
35608
  const blocks = flattenBlocks7(doc.blocks);
35410
35609
  if (blocks.length === 0) return null;
35411
35610
  return blocks.find((b) => b.sourceHeading?.position?.start.line === activeBlockStartLine) ?? blocks[0];
35412
35611
  }, [doc, activeBlockStartLine]);
35413
- const visual = useMemo49(
35612
+ const visual = useMemo50(
35414
35613
  () => doc && block ? resolveBlockVisual(doc, block, theme, viewport) : null,
35415
35614
  [doc, block, theme, viewport]
35416
35615
  );
35417
35616
  if (!visual) return null;
35418
- return /* @__PURE__ */ jsx76("div", { className: "squisq-block-preview-panel", "data-testid": "block-preview-panel", "aria-hidden": true, children: /* @__PURE__ */ jsx76(
35617
+ return /* @__PURE__ */ jsx77("div", { className: "squisq-block-preview-panel", "data-testid": "block-preview-panel", "aria-hidden": true, children: /* @__PURE__ */ jsx77(
35419
35618
  "div",
35420
35619
  {
35421
35620
  className: "squisq-block-preview-frame",
35422
35621
  style: { aspectRatio: `${viewport.width} / ${viewport.height}` },
35423
- children: /* @__PURE__ */ jsx76(
35622
+ children: /* @__PURE__ */ jsx77(
35424
35623
  BlockThumbnail,
35425
35624
  {
35426
35625
  visual,
@@ -35674,7 +35873,7 @@ import {
35674
35873
  createMediaProviderFromContainer
35675
35874
  } from "@bendyline/squisq/storage";
35676
35875
  import { MediaContext as MediaContext7, useMediaClipDurations } from "@bendyline/squisq-react";
35677
- import { Fragment as Fragment22, jsx as jsx77, jsxs as jsxs60 } from "react/jsx-runtime";
35876
+ import { Fragment as Fragment22, jsx as jsx78, jsxs as jsxs60 } from "react/jsx-runtime";
35678
35877
  function EditorShell({
35679
35878
  initialMarkdown = "",
35680
35879
  initialView = "wysiwyg",
@@ -35724,6 +35923,7 @@ function EditorShell({
35724
35923
  onFindModeChange,
35725
35924
  mentionProvider,
35726
35925
  documentLinkProvider,
35926
+ fenceRenderers,
35727
35927
  linkSchemes,
35728
35928
  allowRecording = true,
35729
35929
  allowNarrate = true,
@@ -35747,14 +35947,14 @@ function EditorShell({
35747
35947
  themeOverride = null
35748
35948
  }) {
35749
35949
  const effectiveContainer = workspaceContainer ?? null;
35750
- const effectiveMediaProvider = useMemo50(() => {
35950
+ const effectiveMediaProvider = useMemo51(() => {
35751
35951
  if (mediaProvider !== void 0) return mediaProvider;
35752
35952
  if (effectiveContainer) return createMediaProviderFromContainer(effectiveContainer);
35753
35953
  return void 0;
35754
35954
  }, [mediaProvider, effectiveContainer]);
35755
35955
  const filesToggleEnabled = showFilesToggle ?? effectiveMediaProvider !== void 0;
35756
35956
  const effectiveInitialView = hostMode === "chat" || !showPlayTab && initialView === "preview" ? "wysiwyg" : initialView;
35757
- return /* @__PURE__ */ jsx77(MediaContext7.Provider, { value: effectiveMediaProvider ?? null, children: /* @__PURE__ */ jsx77(
35957
+ return /* @__PURE__ */ jsx78(MediaContext7.Provider, { value: effectiveMediaProvider ?? null, children: /* @__PURE__ */ jsx78(
35758
35958
  EditorProvider,
35759
35959
  {
35760
35960
  initialMarkdown,
@@ -35771,6 +35971,7 @@ function EditorShell({
35771
35971
  imageDisplayMode,
35772
35972
  mentionProvider,
35773
35973
  documentLinkProvider,
35974
+ fenceRenderers,
35774
35975
  linkSchemes,
35775
35976
  allowRecording,
35776
35977
  allowNarrate,
@@ -35787,7 +35988,7 @@ function EditorShell({
35787
35988
  themeInheritance,
35788
35989
  viewPreferences,
35789
35990
  onViewPreferencesChange,
35790
- children: /* @__PURE__ */ jsx77(
35991
+ children: /* @__PURE__ */ jsx78(
35791
35992
  EditorShellInner,
35792
35993
  {
35793
35994
  basePath,
@@ -35840,11 +36041,11 @@ function EditorShell({
35840
36041
  }
35841
36042
  function UseModeToolbarControls({ allowPrint }) {
35842
36043
  const printMode = usePrintMode();
35843
- if (printMode.active) return /* @__PURE__ */ jsx77(PrintPreviewToolbar, {});
36044
+ if (printMode.active) return /* @__PURE__ */ jsx78(PrintPreviewToolbar, {});
35844
36045
  return /* @__PURE__ */ jsxs60(Fragment22, { children: [
35845
- /* @__PURE__ */ jsx77(PreviewToolbarControls, {}),
35846
- /* @__PURE__ */ jsx77(PresentationModeControl, {}),
35847
- allowPrint && /* @__PURE__ */ jsx77(PrintModeControl, {})
36046
+ /* @__PURE__ */ jsx78(PreviewToolbarControls, {}),
36047
+ /* @__PURE__ */ jsx78(PresentationModeControl, {}),
36048
+ allowPrint && /* @__PURE__ */ jsx78(PrintModeControl, {})
35848
36049
  ] });
35849
36050
  }
35850
36051
  function UseModeProviders({
@@ -35853,13 +36054,13 @@ function UseModeProviders({
35853
36054
  allowPresentationWindow,
35854
36055
  allowPresentationFullscreen
35855
36056
  }) {
35856
- return /* @__PURE__ */ jsx77(
36057
+ return /* @__PURE__ */ jsx78(
35857
36058
  PresentationModeProvider,
35858
36059
  {
35859
36060
  rootRef,
35860
36061
  allowWindow: allowPresentationWindow,
35861
36062
  allowFullscreen: allowPresentationFullscreen,
35862
- children: /* @__PURE__ */ jsx77(PrintModeProvider, { rootRef, children })
36063
+ children: /* @__PURE__ */ jsx78(PrintModeProvider, { rootRef, children })
35863
36064
  }
35864
36065
  );
35865
36066
  }
@@ -35948,7 +36149,7 @@ function EditorShellInner({
35948
36149
  workspaceContainer
35949
36150
  );
35950
36151
  const timelineDoc = timelineProjection?.contentDoc ?? doc;
35951
- const timelineRawSchedule = useMemo50(
36152
+ const timelineRawSchedule = useMemo51(
35952
36153
  () => timelineDoc ? resolveMediaSchedule4(timelineDoc) : [],
35953
36154
  [timelineDoc]
35954
36155
  );
@@ -35957,19 +36158,19 @@ function EditorShellInner({
35957
36158
  basePath,
35958
36159
  mediaProvider ?? null
35959
36160
  );
35960
- const timelineDuration = useMemo50(
36161
+ const timelineDuration = useMemo51(
35961
36162
  () => timelineDoc ? getDocPlaybackDuration3(timelineDoc, {
35962
36163
  intrinsicDuration: (clip) => timelineClipDurations.get(clip.src)
35963
36164
  }) : 0,
35964
36165
  [timelineDoc, timelineClipDurations]
35965
36166
  );
35966
- const timelineSchedule = useMemo50(
36167
+ const timelineSchedule = useMemo51(
35967
36168
  () => timelineDoc ? resolveMediaSchedule4(timelineDoc, {
35968
36169
  intrinsicDuration: (clip) => timelineClipDurations.get(clip.src)
35969
36170
  }) : [],
35970
36171
  [timelineDoc, timelineClipDurations]
35971
36172
  );
35972
- const timelineVideoSchedule = useMemo50(
36173
+ const timelineVideoSchedule = useMemo51(
35973
36174
  () => timelineDoc ? [
35974
36175
  ...timelineSchedule.filter((clip) => clip.kind === "video"),
35975
36176
  ...collectEmbeddedVideoSchedule(timelineDoc)
@@ -35978,15 +36179,15 @@ function EditorShellInner({
35978
36179
  );
35979
36180
  const timelineClock = useTimelineClock(isTimelineMode ? timelineDuration : 0);
35980
36181
  const hasTimelineVideo = timelineVideoSchedule.length > 0;
35981
- const [timelineVideoVisible, setTimelineVideoVisible] = useState66(false);
35982
- const [timelineCompositionVisible, setTimelineCompositionVisible] = useState66(false);
36182
+ const [timelineVideoVisible, setTimelineVideoVisible] = useState67(false);
36183
+ const [timelineCompositionVisible, setTimelineCompositionVisible] = useState67(false);
35983
36184
  const timelinePreviewCount = Number(timelineVideoVisible) + Number(timelineCompositionVisible);
35984
- const [showFiles, setShowFiles] = useState66(false);
35985
- const [mediaRefreshKey, setMediaRefreshKey] = useState66(0);
35986
- const [mediaCount, setMediaCount] = useState66(0);
35987
- const [mediaBinRecorderOpen, setMediaBinRecorderOpen] = useState66(false);
36185
+ const [showFiles, setShowFiles] = useState67(false);
36186
+ const [mediaRefreshKey, setMediaRefreshKey] = useState67(0);
36187
+ const [mediaCount, setMediaCount] = useState67(0);
36188
+ const [mediaBinRecorderOpen, setMediaBinRecorderOpen] = useState67(false);
35988
36189
  const mediaListRefreshKey = mediaRefreshKey + mediaRevision;
35989
- const usedMediaPaths = useMemo50(
36190
+ const usedMediaPaths = useMemo51(
35990
36191
  () => collectMediaReferencesFromMarkdown(markdownSource),
35991
36192
  [markdownSource]
35992
36193
  );
@@ -35996,13 +36197,13 @@ function EditorShellInner({
35996
36197
  }
35997
36198
  const imageEditFallbackContainer = imageEditFallbackContainerRef.current;
35998
36199
  const isDark = colorScheme === "dark";
35999
- useEffect56(() => {
36200
+ useEffect57(() => {
36000
36201
  if (!isTimelineMode || !hasTimelineVideo) setTimelineVideoVisible(false);
36001
36202
  }, [isTimelineMode, hasTimelineVideo]);
36002
- useEffect56(() => {
36203
+ useEffect57(() => {
36003
36204
  if (!isTimelineMode || !doc?.blocks.length) setTimelineCompositionVisible(false);
36004
36205
  }, [isTimelineMode, doc]);
36005
- useEffect56(() => {
36206
+ useEffect57(() => {
36006
36207
  if (!mediaProvider) {
36007
36208
  setMediaCount(0);
36008
36209
  return;
@@ -36111,7 +36312,7 @@ ${snippet}` : snippet);
36111
36312
  onDrop: handleFileDrop,
36112
36313
  enabled: !readOnly
36113
36314
  });
36114
- useEffect56(() => {
36315
+ useEffect57(() => {
36115
36316
  onChange?.(markdownSource);
36116
36317
  }, [markdownSource, onChange]);
36117
36318
  const handleShellKeyDown = useCallback51(
@@ -36199,7 +36400,7 @@ ${snippet}` : snippet);
36199
36400
  },
36200
36401
  ...containerProps,
36201
36402
  children: [
36202
- /* @__PURE__ */ jsx77(CustomThemeProvider, { docThemes, onDocThemesChange, children: /* @__PURE__ */ jsx77(
36403
+ /* @__PURE__ */ jsx78(CustomThemeProvider, { docThemes, onDocThemesChange, children: /* @__PURE__ */ jsx78(
36203
36404
  PreviewSettingsProvider,
36204
36405
  {
36205
36406
  doc,
@@ -36214,16 +36415,16 @@ ${snippet}` : snippet);
36214
36415
  children: [
36215
36416
  isImageMode ? (toolbarSlotLeft || toolbarSlotRight) && /* @__PURE__ */ jsxs60("div", { className: "squisq-editor-header squisq-editor-header--image", children: [
36216
36417
  toolbarSlotLeft,
36217
- /* @__PURE__ */ jsx77("div", { style: { flex: 1 } }),
36418
+ /* @__PURE__ */ jsx78("div", { style: { flex: 1 } }),
36218
36419
  toolbarSlotRight
36219
- ] }) : /* @__PURE__ */ jsx77("div", { className: "squisq-editor-header", children: /* @__PURE__ */ jsx77(
36420
+ ] }) : /* @__PURE__ */ jsx78("div", { className: "squisq-editor-header", children: /* @__PURE__ */ jsx78(
36220
36421
  Toolbar,
36221
36422
  {
36222
36423
  showFiles,
36223
36424
  fileCount: mediaCount,
36224
36425
  onToggleFiles: !isCodeMode && filesToggleEnabled ? handleToggleFiles : void 0,
36225
36426
  slotLeft: toolbarSlotLeft,
36226
- slotAfterTabs: !isCodeMode && isPreview && /* @__PURE__ */ jsx77(UseModeToolbarControls, { allowPrint }),
36427
+ slotAfterTabs: !isCodeMode && isPreview && /* @__PURE__ */ jsx78(UseModeToolbarControls, { allowPrint }),
36227
36428
  slotAfterActions: toolbarSlotAfterActions,
36228
36429
  slotRight: toolbarSlotRight,
36229
36430
  showPlayTab,
@@ -36257,7 +36458,7 @@ ${snippet}` : snippet);
36257
36458
  position: "relative"
36258
36459
  },
36259
36460
  children: [
36260
- isImageMode && imageSrc && (imageMode === "edit" && imageEditorContainer ? /* @__PURE__ */ jsx77(
36461
+ isImageMode && imageSrc && (imageMode === "edit" && imageEditorContainer ? /* @__PURE__ */ jsx78(
36261
36462
  ImageEditor,
36262
36463
  {
36263
36464
  filesContainer: imageEditorContainer,
@@ -36267,10 +36468,10 @@ ${snippet}` : snippet);
36267
36468
  onExport: onImageExport,
36268
36469
  surface: colorScheme === "dark" ? DARK_SURFACE : LIGHT_SURFACE
36269
36470
  }
36270
- ) : /* @__PURE__ */ jsx77(ImageViewer, { src: imageSrc, alt: imageAlt, theme: colorScheme })),
36471
+ ) : /* @__PURE__ */ jsx78(ImageViewer, { src: imageSrc, alt: imageAlt, theme: colorScheme })),
36271
36472
  !isImageMode && activeView === "raw" && /* @__PURE__ */ jsxs60("div", { className: "squisq-editor-with-gutter", children: [
36272
- isMarkdownMode && outlineVisible && /* @__PURE__ */ jsx77(OutlinePanel, { width: outlineWidth, readOnly }, "outline"),
36273
- /* @__PURE__ */ jsx77(
36473
+ isMarkdownMode && outlineVisible && /* @__PURE__ */ jsx78(OutlinePanel, { width: outlineWidth, readOnly }, "outline"),
36474
+ /* @__PURE__ */ jsx78(
36274
36475
  BlockCardView,
36275
36476
  {
36276
36477
  active: isCardMode,
@@ -36279,7 +36480,7 @@ ${snippet}` : snippet);
36279
36480
  onPrev: prevBlock,
36280
36481
  onNext: nextBlock,
36281
36482
  onAdd: addBlock,
36282
- children: /* @__PURE__ */ jsx77("div", { className: "squisq-raw-editor-container", children: /* @__PURE__ */ jsx77(
36483
+ children: /* @__PURE__ */ jsx78("div", { className: "squisq-raw-editor-container", children: /* @__PURE__ */ jsx78(
36283
36484
  RawEditor,
36284
36485
  {
36285
36486
  monacoTheme: colorScheme === "dark" ? "vs-dark" : "vs",
@@ -36290,9 +36491,9 @@ ${snippet}` : snippet);
36290
36491
  },
36291
36492
  "raw-frame"
36292
36493
  ),
36293
- isCodeMode && codeContext && /* @__PURE__ */ jsx77(CodeContextZones, { options: codeContext }, "code-context"),
36294
- isMarkdownMode && isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx77(BlockPreviewPanel, { basePath }, "block-preview"),
36295
- isMarkdownMode && !isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx77(
36494
+ isCodeMode && codeContext && /* @__PURE__ */ jsx78(CodeContextZones, { options: codeContext }, "code-context"),
36495
+ isMarkdownMode && isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(BlockPreviewPanel, { basePath }, "block-preview"),
36496
+ isMarkdownMode && !isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(
36296
36497
  InlinePreviewGutter,
36297
36498
  {
36298
36499
  width: inlinePreviewWidth,
@@ -36303,8 +36504,8 @@ ${snippet}` : snippet);
36303
36504
  )
36304
36505
  ] }, "raw-shell"),
36305
36506
  isMarkdownMode && activeView === "wysiwyg" && /* @__PURE__ */ jsxs60("div", { className: "squisq-editor-with-gutter", children: [
36306
- outlineVisible && /* @__PURE__ */ jsx77(OutlinePanel, { width: outlineWidth, readOnly }, "outline"),
36307
- /* @__PURE__ */ jsx77(
36507
+ outlineVisible && /* @__PURE__ */ jsx78(OutlinePanel, { width: outlineWidth, readOnly }, "outline"),
36508
+ /* @__PURE__ */ jsx78(
36308
36509
  BlockCardView,
36309
36510
  {
36310
36511
  active: isCardMode,
@@ -36313,7 +36514,7 @@ ${snippet}` : snippet);
36313
36514
  onPrev: prevBlock,
36314
36515
  onNext: nextBlock,
36315
36516
  onAdd: addBlock,
36316
- children: /* @__PURE__ */ jsx77(
36517
+ children: /* @__PURE__ */ jsx78(
36317
36518
  WysiwygEditor,
36318
36519
  {
36319
36520
  submitOnEnter,
@@ -36325,8 +36526,8 @@ ${snippet}` : snippet);
36325
36526
  },
36326
36527
  "wysiwyg-frame"
36327
36528
  ),
36328
- isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx77(BlockPreviewPanel, { basePath }, "block-preview"),
36329
- !isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx77(
36529
+ isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(BlockPreviewPanel, { basePath }, "block-preview"),
36530
+ !isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(
36330
36531
  InlinePreviewGutter,
36331
36532
  {
36332
36533
  width: inlinePreviewWidth,
@@ -36336,7 +36537,7 @@ ${snippet}` : snippet);
36336
36537
  "inline"
36337
36538
  )
36338
36539
  ] }, "wysiwyg-shell"),
36339
- isMarkdownMode && isPreview && /* @__PURE__ */ jsx77(
36540
+ isMarkdownMode && isPreview && /* @__PURE__ */ jsx78(
36340
36541
  PreviewPanel,
36341
36542
  {
36342
36543
  basePath,
@@ -36349,7 +36550,7 @@ ${snippet}` : snippet);
36349
36550
  ]
36350
36551
  }
36351
36552
  ),
36352
- isTimelineMode && timelineVideoVisible && /* @__PURE__ */ jsx77(
36553
+ isTimelineMode && timelineVideoVisible && /* @__PURE__ */ jsx78(
36353
36554
  TimelineVideoPanel,
36354
36555
  {
36355
36556
  schedule: timelineVideoSchedule,
@@ -36359,7 +36560,7 @@ ${snippet}` : snippet);
36359
36560
  onClose: () => setTimelineVideoVisible(false)
36360
36561
  }
36361
36562
  ),
36362
- isTimelineMode && timelineCompositionVisible && /* @__PURE__ */ jsx77(
36563
+ isTimelineMode && timelineCompositionVisible && /* @__PURE__ */ jsx78(
36363
36564
  TimelineCompositionPanel,
36364
36565
  {
36365
36566
  doc,
@@ -36369,7 +36570,7 @@ ${snippet}` : snippet);
36369
36570
  onClose: () => setTimelineCompositionVisible(false)
36370
36571
  }
36371
36572
  ),
36372
- isMarkdownMode && showFiles && /* @__PURE__ */ jsx77(
36573
+ isMarkdownMode && showFiles && /* @__PURE__ */ jsx78(
36373
36574
  MediaBin,
36374
36575
  {
36375
36576
  mediaProvider,
@@ -36384,8 +36585,8 @@ ${snippet}` : snippet);
36384
36585
  isRecorderOpen: mediaBinRecorderOpen
36385
36586
  }
36386
36587
  ),
36387
- isMarkdownMode && /* @__PURE__ */ jsx77(ThemeDesignerDock, {}),
36388
- isMarkdownMode && isDragging && !(activeView === "wysiwyg" && dragContentType === "media") && /* @__PURE__ */ jsx77(
36588
+ isMarkdownMode && /* @__PURE__ */ jsx78(ThemeDesignerDock, {}),
36589
+ isMarkdownMode && isDragging && !(activeView === "wysiwyg" && dragContentType === "media") && /* @__PURE__ */ jsx78(
36389
36590
  DropZoneOverlay,
36390
36591
  {
36391
36592
  dragContentType,
@@ -36396,7 +36597,7 @@ ${snippet}` : snippet);
36396
36597
  ]
36397
36598
  }
36398
36599
  ),
36399
- isTimelineMode && /* @__PURE__ */ jsx77(
36600
+ isTimelineMode && /* @__PURE__ */ jsx78(
36400
36601
  TimelineToolbar,
36401
36602
  {
36402
36603
  literalVideoVisible: timelineVideoVisible,
@@ -36407,7 +36608,7 @@ ${snippet}` : snippet);
36407
36608
  onToggleComposition: () => setTimelineCompositionVisible((visible) => !visible)
36408
36609
  }
36409
36610
  ),
36410
- isTimelineMode && /* @__PURE__ */ jsx77(
36611
+ isTimelineMode && /* @__PURE__ */ jsx78(
36411
36612
  TimelineTrack,
36412
36613
  {
36413
36614
  doc: timelineDoc,
@@ -36416,8 +36617,8 @@ ${snippet}` : snippet);
36416
36617
  basePath
36417
36618
  }
36418
36619
  ),
36419
- statusBarVisible && !isImageMode && /* @__PURE__ */ jsx77(StatusBar, { slotRight: statusBarSlotRight }),
36420
- isMarkdownMode && allowRecording && mediaProvider && /* @__PURE__ */ jsx77(
36620
+ statusBarVisible && !isImageMode && /* @__PURE__ */ jsx78(StatusBar, { slotRight: statusBarSlotRight }),
36621
+ isMarkdownMode && allowRecording && mediaProvider && /* @__PURE__ */ jsx78(
36421
36622
  RecorderEntry,
36422
36623
  {
36423
36624
  open: mediaBinRecorderOpen,
@@ -36430,8 +36631,8 @@ ${snippet}` : snippet);
36430
36631
  )
36431
36632
  }
36432
36633
  ) }),
36433
- /* @__PURE__ */ jsx77(TooltipLayer, {}),
36434
- imageEditTarget !== null && mediaProvider && /* @__PURE__ */ jsx77(
36634
+ /* @__PURE__ */ jsx78(TooltipLayer, {}),
36635
+ imageEditTarget !== null && mediaProvider && /* @__PURE__ */ jsx78(
36435
36636
  ImageEditModal,
36436
36637
  {
36437
36638
  relativePath: imageEditTarget,
@@ -36466,7 +36667,7 @@ function ImageEditModal({
36466
36667
  useModalDialog({ rootRef: modalRef, dialogRef: surfaceRef, onClose });
36467
36668
  const extension = relativePath.split(/[?#]/, 1)[0]?.split(".").pop()?.toLowerCase();
36468
36669
  const saveFormat = extension === "png" ? "png" : extension === "jpg" || extension === "jpeg" ? "jpeg" : extension === "webp" ? "webp" : null;
36469
- const sidecar = useMemo50(() => {
36670
+ const sidecar = useMemo51(() => {
36470
36671
  const sanitized = relativePath.replace(/[^a-zA-Z0-9._-]+/g, "_");
36471
36672
  let hash = 2166136261;
36472
36673
  for (let i = 0; i < relativePath.length; i++) {
@@ -36477,9 +36678,9 @@ function ImageEditModal({
36477
36678
  const parent = container ?? new MemoryContentContainer();
36478
36679
  return scopeContainer(parent, `.imageEdits/${scopedName}`);
36479
36680
  }, [container, relativePath]);
36480
- const [initialSrc, setInitialSrc] = useState66(null);
36481
- const [resolveError, setResolveError] = useState66(null);
36482
- useEffect56(() => {
36681
+ const [initialSrc, setInitialSrc] = useState67(null);
36682
+ const [resolveError, setResolveError] = useState67(null);
36683
+ useEffect57(() => {
36483
36684
  let cancelled = false;
36484
36685
  setInitialSrc(null);
36485
36686
  setResolveError(null);
@@ -36509,7 +36710,7 @@ function ImageEditModal({
36509
36710
  },
36510
36711
  [mediaProvider, relativePath, onSaved]
36511
36712
  );
36512
- return /* @__PURE__ */ jsx77(
36713
+ return /* @__PURE__ */ jsx78(
36513
36714
  "div",
36514
36715
  {
36515
36716
  ref: modalRef,
@@ -36523,9 +36724,9 @@ function ImageEditModal({
36523
36724
  },
36524
36725
  children: /* @__PURE__ */ jsxs60("div", { ref: surfaceRef, className: "squisq-image-edit-modal__surface", children: [
36525
36726
  /* @__PURE__ */ jsxs60("header", { className: "squisq-image-edit-modal__header", children: [
36526
- /* @__PURE__ */ jsx77("span", { className: "squisq-image-edit-modal__title", children: "Edit image" }),
36527
- /* @__PURE__ */ jsx77("span", { className: "squisq-image-edit-modal__path", children: relativePath }),
36528
- /* @__PURE__ */ jsx77(
36727
+ /* @__PURE__ */ jsx78("span", { className: "squisq-image-edit-modal__title", children: "Edit image" }),
36728
+ /* @__PURE__ */ jsx78("span", { className: "squisq-image-edit-modal__path", children: relativePath }),
36729
+ /* @__PURE__ */ jsx78(
36529
36730
  "button",
36530
36731
  {
36531
36732
  type: "button",
@@ -36537,10 +36738,10 @@ function ImageEditModal({
36537
36738
  }
36538
36739
  )
36539
36740
  ] }),
36540
- /* @__PURE__ */ jsx77("div", { className: "squisq-image-edit-modal__body", children: resolveError ? /* @__PURE__ */ jsxs60("div", { className: "squisq-image-edit-modal__error", children: [
36741
+ /* @__PURE__ */ jsx78("div", { className: "squisq-image-edit-modal__body", children: resolveError ? /* @__PURE__ */ jsxs60("div", { className: "squisq-image-edit-modal__error", children: [
36541
36742
  "Failed to load image: ",
36542
36743
  resolveError
36543
- ] }) : !saveFormat ? /* @__PURE__ */ jsx77("div", { className: "squisq-image-edit-modal__error", children: "Editing supports PNG, JPEG, and WebP images without changing the asset type." }) : !initialSrc ? /* @__PURE__ */ jsx77("div", { className: "squisq-image-edit-modal__loading", children: "Loading image\u2026" }) : /* @__PURE__ */ jsx77(
36744
+ ] }) : !saveFormat ? /* @__PURE__ */ jsx78("div", { className: "squisq-image-edit-modal__error", children: "Editing supports PNG, JPEG, and WebP images without changing the asset type." }) : !initialSrc ? /* @__PURE__ */ jsx78("div", { className: "squisq-image-edit-modal__loading", children: "Loading image\u2026" }) : /* @__PURE__ */ jsx78(
36544
36745
  ImageEditor,
36545
36746
  {
36546
36747
  filesContainer: sidecar,
@@ -36659,6 +36860,7 @@ export {
36659
36860
  removeNodeOp,
36660
36861
  asciiDiagramToCanvas,
36661
36862
  useAsciiDiagramData,
36863
+ mapFenceEntries,
36662
36864
  REPAIRABLE_KEY,
36663
36865
  isRepairableFence,
36664
36866
  findRepairableBlockPos,
@@ -36667,6 +36869,8 @@ export {
36667
36869
  applyRepairCommand,
36668
36870
  applyAsciiDiagramCommand,
36669
36871
  AsciiDiagramWidget,
36872
+ FENCE_WIDGET_CONTAINED_EVENTS,
36873
+ containFenceWidgetEvents,
36670
36874
  findAsciiDiagramBlockPos,
36671
36875
  isAsciiSourceVisible,
36672
36876
  toggleAsciiSource,
@@ -36698,6 +36902,10 @@ export {
36698
36902
  isCodeSnippetNode,
36699
36903
  findCodeSnippetBlockPos,
36700
36904
  CodeSnippetExtension,
36905
+ HOST_FENCE_KEY,
36906
+ findHostFenceBlockPos,
36907
+ replaceHostFenceText,
36908
+ HostFenceExtension,
36701
36909
  useTreeViewData,
36702
36910
  sanitizeTreeLabel,
36703
36911
  renameItemOp,