@bendyline/squisq-editor-react 2.6.0 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,7 +15,7 @@ import {
15
15
  import {
16
16
  RecorderPanel,
17
17
  useModalDialog
18
- } from "./chunk-JUAQQTJE.js";
18
+ } from "./chunk-V3J5S7X6.js";
19
19
  import {
20
20
  Icon
21
21
  } from "./chunk-GS7QWYFT.js";
@@ -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.ts
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
25178
  import { createElement as createElement11 } from "react";
25179
+
25180
+ // src/fenceWidgets/HostFenceWidget.tsx
25181
+ import { Component, useEffect as useEffect33, useMemo as useMemo32, useState as useState42 } from "react";
25182
+ import { jsx as jsx50 } from "react/jsx-runtime";
25183
+ var HostFenceErrorBoundary = class extends Component {
25184
+ constructor() {
25185
+ super(...arguments);
25186
+ this.state = { failed: false };
25187
+ }
25188
+ static getDerivedStateFromError() {
25189
+ return { failed: true };
25190
+ }
25191
+ render() {
25192
+ return this.state.failed ? this.props.fallback : this.props.children;
25193
+ }
25194
+ };
25195
+ function HostFenceWidget({ editor, blockId, getRenderers, getTheme }) {
25196
+ const [version, setVersion] = useState42(0);
25197
+ useEffect33(() => {
25198
+ const onUpdate = () => setVersion((v2) => v2 + 1);
25199
+ editor.on("transaction", onUpdate);
25200
+ return () => {
25201
+ editor.off("transaction", onUpdate);
25202
+ };
25203
+ }, [editor]);
25204
+ const current = useMemo32(() => {
25205
+ const pos = findHostFenceBlockPos(editor, blockId);
25206
+ if (pos === null) return null;
25207
+ const node2 = editor.state.doc.nodeAt(pos);
25208
+ if (!node2 || node2.type.name !== "codeBlock") return null;
25209
+ return { lang: fenceLangToken(node2), value: node2.textContent };
25210
+ }, [editor, blockId, version]);
25211
+ if (!current) return null;
25212
+ const renderer = getRenderers()?.[current.lang];
25213
+ const rawFallback = /* @__PURE__ */ jsx50("pre", { className: "squisq-md-code-block", children: /* @__PURE__ */ jsx50("code", { children: current.value }) });
25214
+ if (!renderer) return rawFallback;
25215
+ const theme = getTheme();
25216
+ return /* @__PURE__ */ jsx50(HostFenceErrorBoundary, { fallback: rawFallback, children: renderer({
25217
+ lang: current.lang,
25218
+ value: current.value,
25219
+ ...theme ? { theme } : {},
25220
+ mode: "edit",
25221
+ replaceValue: (next) => {
25222
+ replaceHostFenceText(editor, blockId, next);
25223
+ }
25224
+ }) });
25225
+ }
25226
+
25227
+ // src/fenceWidgets/HostFenceExtension.ts
25228
+ var HOST_FENCE_KEY = new PluginKey7("squisq-host-fence");
25229
+ function fenceLangToken(node2) {
25230
+ const lang = node2.attrs.language;
25231
+ if (typeof lang !== "string") return "";
25232
+ return lang.trim().split(/\s+/, 1)[0]?.toLowerCase() ?? "";
25233
+ }
25234
+ function findHostFenceBlockPos(editor, blockId) {
25235
+ return HOST_FENCE_KEY.getState(editor.state)?.entries.find((e2) => e2.id === blockId)?.pos ?? null;
25236
+ }
25237
+ function replaceHostFenceText(editor, blockId, next) {
25238
+ const pos = findHostFenceBlockPos(editor, blockId);
25239
+ if (pos === null) return false;
25240
+ return replaceAsciiFenceText(editor, pos, next);
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,
@@ -29826,346 +30023,20 @@ function InlinePreviewGutter({
29826
30023
 
29827
30024
  // src/buildPreviewDoc.ts
29828
30025
  import {
29829
- coerceTemplateParams,
29830
- deriveTemplateInputs as deriveTemplateInputs3,
29831
- flattenRenderableBlocks,
29832
- hasTemplate as hasTemplate2
30026
+ buildPreviewDoc,
30027
+ documentTitleFromFileName
29833
30028
  } from "@bendyline/squisq/doc";
29834
- import { extractPlainText as extractPlainText4, KNOWN_BLOCK_META_KEYS as KNOWN_BLOCK_META_KEYS2 } from "@bendyline/squisq/markdown";
29835
- import { getChildren as getChildren2 } from "@bendyline/squisq/markdown";
29836
- import { iconMarker } from "@bendyline/squisq/icon-marker";
29837
- function extractRichText(node2) {
29838
- if (node2.type === "inlineIcon") {
29839
- const icon = node2;
29840
- return iconMarker(icon.family, icon.name);
29841
- }
29842
- if ("value" in node2 && typeof node2.value === "string") {
29843
- return node2.value;
29844
- }
29845
- const children = getChildren2(node2);
29846
- const separator = node2.type === "list" || node2.type === "listItem" ? "\n" : "";
29847
- return children.map(extractRichText).join(separator);
29848
- }
29849
- function extractBodyText(contents) {
29850
- if (!contents || contents.length === 0) return "";
29851
- const parts = [];
29852
- for (const node2 of contents) {
29853
- if (node2.type === "code" && node2.lang?.trim().toLowerCase() === "mermaid") continue;
29854
- parts.push(extractRichText(node2));
29855
- }
29856
- return parts.join("\n").trim();
29857
- }
29858
- function parseDim2(raw) {
29859
- if (raw === void 0) return void 0;
29860
- const n = parseFloat(raw);
29861
- return Number.isFinite(n) && n > 0 ? n : void 0;
29862
- }
29863
- function extractBlockImages2(contents) {
29864
- if (!contents || contents.length === 0) return [];
29865
- const images = [];
29866
- function walkHtml(node2) {
29867
- if (!node2 || typeof node2 !== "object") return;
29868
- const n = node2;
29869
- if (n.type === "htmlElement" && n.tagName.toLowerCase() === "img") {
29870
- const attrs = n.attributes;
29871
- const src = attrs?.src;
29872
- if (typeof src === "string" && src) {
29873
- images.push({
29874
- src,
29875
- alt: typeof attrs?.alt === "string" ? attrs.alt : "",
29876
- width: parseDim2(attrs?.width),
29877
- height: parseDim2(attrs?.height)
29878
- });
29879
- }
29880
- }
29881
- if (Array.isArray(n.children)) {
29882
- for (const child of n.children) walkHtml(child);
29883
- }
29884
- }
29885
- function walk(node2) {
29886
- if ("type" in node2 && node2.type === "image" && "url" in node2) {
29887
- const img = node2;
29888
- if (img.url) {
29889
- images.push({ src: img.url, alt: img.alt ?? "" });
29890
- }
29891
- }
29892
- if ("type" in node2 && (node2.type === "htmlBlock" || node2.type === "htmlInline")) {
29893
- const html = node2;
29894
- for (const child of html.htmlChildren ?? []) walkHtml(child);
29895
- }
29896
- for (const child of getChildren2(node2)) {
29897
- walk(child);
29898
- }
29899
- }
29900
- for (const node2 of contents) {
29901
- walk(node2);
29902
- }
29903
- return images;
29904
- }
29905
- function collectAllDocImages(blocks) {
29906
- const seen = /* @__PURE__ */ new Set();
29907
- const images = [];
29908
- function walkBlocks(blockList) {
29909
- for (const block of blockList) {
29910
- for (const img of extractBlockImages2(block.contents)) {
29911
- if (!seen.has(img.src)) {
29912
- seen.add(img.src);
29913
- images.push(img);
29914
- }
29915
- }
29916
- if (block.children) {
29917
- walkBlocks(block.children);
29918
- }
29919
- }
29920
- }
29921
- walkBlocks(blocks);
29922
- return images;
29923
- }
29924
- function extractListItems3(contents) {
29925
- if (!contents) return [];
29926
- const items = [];
29927
- for (const node2 of contents) {
29928
- if (node2.type === "list") {
29929
- for (const item of node2.children) {
29930
- const text = extractPlainText4(item).trim();
29931
- if (text) items.push(text);
29932
- }
29933
- }
29934
- }
29935
- return items;
29936
- }
29937
- function getTemplateDefaults2(templateName, headingText2, block) {
29938
- const body = extractBodyText(block.contents);
29939
- switch (templateName) {
29940
- case "statHighlight":
29941
- return deriveTemplateInputs3(templateName, headingText2, block.contents) ?? {
29942
- stat: headingText2,
29943
- description: body || headingText2
29944
- };
29945
- case "quote":
29946
- case "fullBleedQuote":
29947
- case "pullQuote":
29948
- return { quote: body || headingText2 };
29949
- case "factCard":
29950
- return { fact: headingText2, explanation: body || headingText2 };
29951
- case "comparisonBar":
29952
- return { leftLabel: "A", leftValue: 60, rightLabel: "B", rightValue: 40 };
29953
- case "list": {
29954
- const items = extractListItems3(block.contents);
29955
- return { items: items.length > 0 ? items : ["Item 1", "Item 2", "Item 3"] };
29956
- }
29957
- case "definitionCard":
29958
- return { term: headingText2, definition: body || headingText2 };
29959
- case "dateEvent":
29960
- return { date: headingText2, description: body || headingText2 };
29961
- case "leftFeature":
29962
- case "rightFeature": {
29963
- const images = extractBlockImages2(block.contents);
29964
- const img = images[0];
29965
- return {
29966
- imageSrc: img?.src ?? "",
29967
- imageAlt: img?.alt || headingText2,
29968
- imageWidth: img?.width,
29969
- imageHeight: img?.height,
29970
- title: headingText2,
29971
- body: body || headingText2
29972
- };
29973
- }
29974
- default:
29975
- return {};
29976
- }
29977
- }
29978
- function blockToSlide(block, index2, knownTemplates, documentTitle2) {
29979
- const headingText2 = block.sourceHeading ? extractPlainText4(block.sourceHeading) : block.title || documentTitle2 || "";
29980
- const implicitSectionHeader = block.template === "sectionHeader" && block.autoTemplate !== true && !!block.sourceHeading && !block.sourceHeading.templateAnnotation?.template;
29981
- const requestedTemplate = implicitSectionHeader ? "content" : block.template ?? "content";
29982
- const isCustomTemplate = knownTemplates?.has(requestedTemplate) ?? false;
29983
- const recognized = hasTemplate2(requestedTemplate) || isCustomTemplate;
29984
- const template = recognized ? requestedTemplate : "sectionHeader";
29985
- const defaults = getTemplateDefaults2(template, headingText2, block);
29986
- const templateOverrides = omitStringBlockMeta(block.templateOverrides);
29987
- const coercedTemplateOverrides = templateOverrides ? coerceTemplateParams(template, templateOverrides).input : void 0;
29988
- const {
29989
- id: _id,
29990
- startTime: _st,
29991
- duration: _d,
29992
- audioSegment: _as,
29993
- layers: _l,
29994
- transition: _tr,
29995
- template: _t,
29996
- title: _ti,
29997
- children: _c,
29998
- contents: _co,
29999
- sourceHeading: _sh,
30000
- templateOverrides: _to,
30001
- templateData: _td,
30002
- ...extraFields
30003
- } = block;
30004
- return {
30005
- id: block.id,
30006
- template,
30007
- duration: block.duration,
30008
- audioSegment: 0,
30009
- // Respect the block's authored transition (set via the toolbar / on-canvas
30010
- // properties palette → `{…}` block attrs). Only fall back to a default fade
30011
- // for blocks past the first when the author hasn't chosen one; the first
30012
- // block has no previous slide to transition in from.
30013
- transition: block.transition ?? (index2 > 0 ? { type: "fade", duration: 0.5 } : void 0),
30014
- title: headingText2,
30015
- // Preserve body nodes on every slide. Built-in templates ignore this
30016
- // structural field, while the canonical materializer uses it to retain
30017
- // authored rich elements (Mermaid fences today; other media can follow)
30018
- // independently of the selected visual template.
30019
- ...block.contents ? { contents: block.contents } : {},
30020
- // Custom templates additionally consume child blocks through tokens.
30021
- ...isCustomTemplate && block.children ? { children: block.children } : {},
30022
- ...defaults,
30023
- ...extraFields,
30024
- // Structured body data (```json data fences, GFM tables for dataTable)
30025
- // carries typed values; `{[…]}` string overrides win last so an explicit
30026
- // annotation param can still pin any field.
30027
- //
30028
- // Block-meta keys (transition, startTime, duration, …) are the exception:
30029
- // they were already coerced to typed block fields above (e.g.
30030
- // `block.transition` → `{ type, duration, direction }`). Their raw string
30031
- // form also rides along in `templateData`/`templateOverrides` because the
30032
- // author wrote them inside `{[…]}`; left un-stripped, that string would
30033
- // spread back over the typed value here and clobber it — turning
30034
- // `transition=vortex` into the string `"vortex"`, which the player can't
30035
- // animate. Omit them from the content spreads so the typed fields win.
30036
- ...omitBlockMeta(block.templateData),
30037
- ...coercedTemplateOverrides
30038
- };
30039
- }
30040
- var BLOCK_META_KEYS2 = new Set(Object.keys(KNOWN_BLOCK_META_KEYS2));
30041
- function omitBlockMeta(data) {
30042
- if (!data) return data;
30043
- let hit = false;
30044
- const out = {};
30045
- for (const key of Object.keys(data)) {
30046
- if (BLOCK_META_KEYS2.has(key)) {
30047
- hit = true;
30048
- continue;
30049
- }
30050
- out[key] = data[key];
30051
- }
30052
- return hit ? out : data;
30053
- }
30054
- function omitStringBlockMeta(data) {
30055
- if (!data) return data;
30056
- let hit = false;
30057
- const out = {};
30058
- for (const key of Object.keys(data)) {
30059
- if (BLOCK_META_KEYS2.has(key)) {
30060
- hit = true;
30061
- continue;
30062
- }
30063
- out[key] = data[key];
30064
- }
30065
- return hit ? out : data;
30066
- }
30067
- var IMAGE_MOTIONS = [
30068
- "zoomIn",
30069
- "zoomOut",
30070
- "panLeft",
30071
- "panRight"
30072
- ];
30073
- function documentTitleFromFileName(fileName) {
30074
- if (!fileName) return "";
30075
- const base = fileName.split(/[\\/]/).pop() ?? "";
30076
- return base.replace(/\.[^.]+$/, "").trim();
30077
- }
30078
- function resolveDocumentTitle(doc, provided) {
30079
- const frontmatterTitle = doc.frontmatter?.title;
30080
- if (typeof frontmatterTitle === "string" && frontmatterTitle.trim()) {
30081
- return frontmatterTitle.trim();
30082
- }
30083
- return provided?.trim() ?? "";
30084
- }
30085
- function buildPreviewDoc(doc, options) {
30086
- const flat = flattenRenderableBlocks(doc.blocks);
30087
- const allImages = collectAllDocImages(doc.blocks);
30088
- const usedImageSrcs = /* @__PURE__ */ new Set();
30089
- const knownTemplates = doc.customTemplates ? new Set(doc.customTemplates.map((d) => d.name)) : void 0;
30090
- const documentTitle2 = resolveDocumentTitle(doc, options?.documentTitle);
30091
- const slides = [];
30092
- let motionIndex = 0;
30093
- for (let i = 0; i < flat.length; i++) {
30094
- const block = flat[i];
30095
- const blockImages = extractBlockImages2(block.contents);
30096
- const slide = blockToSlide(block, i, knownTemplates, documentTitle2);
30097
- if (blockImages.length > 0 && slide.template === "sectionHeader") {
30098
- const img = blockImages[0];
30099
- usedImageSrcs.add(img.src);
30100
- slide.template = "imageWithCaption";
30101
- slide.imageSrc = img.src;
30102
- slide.imageAlt = img.alt;
30103
- slide.caption = slide.title;
30104
- slide.captionPosition = "bottom";
30105
- slide.ambientMotion = IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length];
30106
- } else if (blockImages.length > 0) {
30107
- const img = blockImages[0];
30108
- usedImageSrcs.add(img.src);
30109
- if (!slide.accentImage) {
30110
- slide.accentImage = {
30111
- src: img.src,
30112
- alt: img.alt,
30113
- position: "left-strip",
30114
- ambientMotion: IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length]
30115
- };
30116
- }
30117
- }
30118
- slides.push(slide);
30119
- }
30120
- const unusedImages = allImages.filter((img) => !usedImageSrcs.has(img.src));
30121
- if (unusedImages.length > 0 && slides.length > 0) {
30122
- const interval = Math.max(2, Math.floor(slides.length / (unusedImages.length + 1)));
30123
- let insertOffset = 0;
30124
- for (let imgIdx = 0; imgIdx < unusedImages.length; imgIdx++) {
30125
- const insertAt = Math.min((imgIdx + 1) * interval + insertOffset, slides.length);
30126
- const img = unusedImages[imgIdx];
30127
- slides.splice(insertAt, 0, {
30128
- id: `img-interleave-${imgIdx}`,
30129
- template: "imageWithCaption",
30130
- duration: 5,
30131
- audioSegment: 0,
30132
- imageSrc: img.src,
30133
- imageAlt: img.alt,
30134
- ambientMotion: IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length],
30135
- transition: { type: "fade", duration: 0.5 }
30136
- });
30137
- insertOffset++;
30138
- }
30139
- }
30140
- let t = 0;
30141
- for (const slide of slides) {
30142
- slide.startTime = t;
30143
- t += slide.duration;
30144
- }
30145
- const audio = doc.audio?.segments?.length > 0 ? doc.audio : {
30146
- segments: t > 0 ? [{ src: "", name: "preview", duration: t, startTime: 0 }] : []
30147
- };
30148
- return {
30149
- // Preserve document-wide capabilities (custom themes, persistent layers,
30150
- // scheduled media, frontmatter, captions, and future schema fields).
30151
- // Preview preparation should replace only the slide/timing projection.
30152
- ...doc,
30153
- duration: t,
30154
- blocks: slides,
30155
- audio
30156
- };
30157
- }
30158
30029
 
30159
30030
  // src/OutlinePanel.tsx
30160
30031
  import {
30161
30032
  useCallback as useCallback40,
30162
- useEffect as useEffect42,
30163
- useMemo as useMemo38,
30033
+ useEffect as useEffect43,
30034
+ useMemo as useMemo39,
30164
30035
  useRef as useRef42,
30165
- useState as useState53
30036
+ useState as useState54
30166
30037
  } from "react";
30167
- import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate3 } from "@bendyline/squisq/doc";
30168
- import { extractPlainText as extractPlainText5 } from "@bendyline/squisq/markdown";
30038
+ import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate2 } from "@bendyline/squisq/doc";
30039
+ import { extractPlainText as extractPlainText4 } from "@bendyline/squisq/markdown";
30169
30040
 
30170
30041
  // src/outlineSource.ts
30171
30042
  import { parseMarkdown as parseMarkdown7 } from "@bendyline/squisq/markdown";
@@ -30264,7 +30135,7 @@ function splitTrailingLineGap(value) {
30264
30135
  }
30265
30136
 
30266
30137
  // src/OutlinePanel.tsx
30267
- import { jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
30138
+ import { jsx as jsx59, jsxs as jsxs46 } from "react/jsx-runtime";
30268
30139
  var OUTLINE_RESPONSIVE_WIDTH = "clamp(260px, 30vw, 460px)";
30269
30140
  var OUTLINE_DRAG_MIME = "application/x-squisq-outline-section";
30270
30141
  function OutlinePanel({ width, className, readOnly = false }) {
@@ -30281,9 +30152,9 @@ function OutlinePanel({ width, className, readOnly = false }) {
30281
30152
  const { scrollToBlock } = useHeadingLayout(paneRef);
30282
30153
  const cursorActiveId = useActiveOutlineBlockId();
30283
30154
  const activeDragRef = useRef42(null);
30284
- const [draggedBlockId, setDraggedBlockId] = useState53(null);
30285
- const [dropTarget, setDropTarget] = useState53(null);
30286
- const blockModeActiveId = useMemo38(() => {
30155
+ const [draggedBlockId, setDraggedBlockId] = useState54(null);
30156
+ const [dropTarget, setDropTarget] = useState54(null);
30157
+ const blockModeActiveId = useMemo39(() => {
30287
30158
  if (layoutMode !== "block" || activeBlockStartLine == null || !doc) return null;
30288
30159
  const match = flattenBlocks5(doc.blocks).find(
30289
30160
  (b) => b.sourceHeading?.position?.start.line === activeBlockStartLine
@@ -30382,7 +30253,7 @@ function OutlinePanel({ width, className, readOnly = false }) {
30382
30253
  overflow: "auto",
30383
30254
  ...accentColor ? { ["--squisq-outline-accent"]: accentColor } : {}
30384
30255
  };
30385
- return /* @__PURE__ */ jsx58(
30256
+ return /* @__PURE__ */ jsx59(
30386
30257
  "aside",
30387
30258
  {
30388
30259
  ref: paneRef,
@@ -30390,7 +30261,7 @@ function OutlinePanel({ width, className, readOnly = false }) {
30390
30261
  style: paneStyle,
30391
30262
  "data-testid": "outline-panel",
30392
30263
  "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(
30264
+ 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
30265
  OutlineNode,
30395
30266
  {
30396
30267
  block: b,
@@ -30428,10 +30299,10 @@ function OutlineNode({
30428
30299
  const heading = block.sourceHeading;
30429
30300
  const depth = heading?.depth ?? 1;
30430
30301
  const headingLine2 = heading?.position?.start.line;
30431
- const text = heading ? extractPlainText5(heading).trim() : "";
30302
+ const text = heading ? extractPlainText4(heading).trim() : "";
30432
30303
  const annotation = heading?.templateAnnotation;
30433
30304
  const tplName = annotation?.template;
30434
- const showChip = tplName && hasTemplate3(tplName);
30305
+ const showChip = tplName && hasTemplate2(tplName);
30435
30306
  const isActive = block.id === activeBlockId;
30436
30307
  const canPromote = !!heading && depth > 1;
30437
30308
  const canDemote = !!heading && depth < 6;
@@ -30464,21 +30335,21 @@ function OutlineNode({
30464
30335
  onDragEnd,
30465
30336
  title: text || "(empty heading)",
30466
30337
  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" })
30338
+ 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: [
30339
+ /* @__PURE__ */ jsx59("circle", { cx: "2", cy: "2", r: "1", fill: "currentColor" }),
30340
+ /* @__PURE__ */ jsx59("circle", { cx: "6", cy: "2", r: "1", fill: "currentColor" }),
30341
+ /* @__PURE__ */ jsx59("circle", { cx: "2", cy: "6", r: "1", fill: "currentColor" }),
30342
+ /* @__PURE__ */ jsx59("circle", { cx: "6", cy: "6", r: "1", fill: "currentColor" }),
30343
+ /* @__PURE__ */ jsx59("circle", { cx: "2", cy: "10", r: "1", fill: "currentColor" }),
30344
+ /* @__PURE__ */ jsx59("circle", { cx: "6", cy: "10", r: "1", fill: "currentColor" })
30474
30345
  ] }) }),
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) })
30346
+ /* @__PURE__ */ jsx59("span", { className: "squisq-outline-row-text", children: text || "(untitled)" }),
30347
+ showChip && /* @__PURE__ */ jsx59("span", { className: "squisq-outline-template-chip", children: templateLabel(tplName) })
30477
30348
  ]
30478
30349
  }
30479
30350
  ),
30480
30351
  heading && /* @__PURE__ */ jsxs46("span", { className: "squisq-outline-row-actions", children: [
30481
- /* @__PURE__ */ jsx58(
30352
+ /* @__PURE__ */ jsx59(
30482
30353
  "button",
30483
30354
  {
30484
30355
  type: "button",
@@ -30487,7 +30358,7 @@ function OutlineNode({
30487
30358
  title: "Promote heading",
30488
30359
  disabled: mutationsDisabled || !canPromote,
30489
30360
  onClick: () => onChangeLevel(block, -1),
30490
- children: /* @__PURE__ */ jsx58("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx58(
30361
+ children: /* @__PURE__ */ jsx59("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx59(
30491
30362
  "path",
30492
30363
  {
30493
30364
  d: "M6.5 2.5 L3 5 L6.5 7.5",
@@ -30500,7 +30371,7 @@ function OutlineNode({
30500
30371
  ) })
30501
30372
  }
30502
30373
  ),
30503
- /* @__PURE__ */ jsx58(
30374
+ /* @__PURE__ */ jsx59(
30504
30375
  "button",
30505
30376
  {
30506
30377
  type: "button",
@@ -30509,7 +30380,7 @@ function OutlineNode({
30509
30380
  title: "Demote heading",
30510
30381
  disabled: mutationsDisabled || !canDemote,
30511
30382
  onClick: () => onChangeLevel(block, 1),
30512
- children: /* @__PURE__ */ jsx58("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx58(
30383
+ children: /* @__PURE__ */ jsx59("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx59(
30513
30384
  "path",
30514
30385
  {
30515
30386
  d: "M3.5 2.5 L7 5 L3.5 7.5",
@@ -30526,7 +30397,7 @@ function OutlineNode({
30526
30397
  ]
30527
30398
  }
30528
30399
  ),
30529
- block.children && block.children.length > 0 && /* @__PURE__ */ jsx58("ul", { className: "squisq-outline-tree", children: block.children.map((child) => /* @__PURE__ */ jsx58(
30400
+ block.children && block.children.length > 0 && /* @__PURE__ */ jsx59("ul", { className: "squisq-outline-tree", children: block.children.map((child) => /* @__PURE__ */ jsx59(
30530
30401
  OutlineNode,
30531
30402
  {
30532
30403
  block: child,
@@ -30548,12 +30419,12 @@ function OutlineNode({
30548
30419
  }
30549
30420
  function useActiveOutlineBlockId() {
30550
30421
  const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
30551
- const flatBlocks = useMemo38(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
30552
- const [activeId, setActiveId] = useState53(null);
30553
- useEffect42(() => {
30422
+ const flatBlocks = useMemo39(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
30423
+ const [activeId, setActiveId] = useState54(null);
30424
+ useEffect43(() => {
30554
30425
  setActiveId(null);
30555
30426
  }, [activeView]);
30556
- useEffect42(() => {
30427
+ useEffect43(() => {
30557
30428
  if (activeView !== "wysiwyg" || !tiptapEditor) return;
30558
30429
  const update = () => {
30559
30430
  const { from } = tiptapEditor.state.selection;
@@ -30575,7 +30446,7 @@ function useActiveOutlineBlockId() {
30575
30446
  tiptapEditor.off("update", update);
30576
30447
  };
30577
30448
  }, [activeView, tiptapEditor, flatBlocks]);
30578
- useEffect42(() => {
30449
+ useEffect43(() => {
30579
30450
  if (activeView !== "raw" || !monacoEditor) return;
30580
30451
  const update = () => {
30581
30452
  const line = monacoEditor.getPosition()?.lineNumber;
@@ -30626,7 +30497,7 @@ function bumpHeadingLevelInSource(source, line, delta) {
30626
30497
  }
30627
30498
 
30628
30499
  // src/codeContext/CodeContextZones.tsx
30629
- import { useCallback as useCallback42, useEffect as useEffect44, useMemo as useMemo40, useRef as useRef44, useState as useState54 } from "react";
30500
+ import { useCallback as useCallback42, useEffect as useEffect45, useMemo as useMemo41, useRef as useRef44, useState as useState55 } from "react";
30630
30501
  import { createPortal as createPortal10 } from "react-dom";
30631
30502
 
30632
30503
  // src/codeContext/diffContextSections.ts
@@ -30750,8 +30621,8 @@ function setOrdinal(zone, ordinal) {
30750
30621
  // src/codeContext/CodeContextSectionView.tsx
30751
30622
  import { parseMarkdown as parseMarkdown8 } from "@bendyline/squisq/markdown";
30752
30623
  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";
30624
+ import { useCallback as useCallback41, useEffect as useEffect44, useMemo as useMemo40, useRef as useRef43 } from "react";
30625
+ import { jsx as jsx60, jsxs as jsxs47 } from "react/jsx-runtime";
30755
30626
  function CodeContextSectionView({
30756
30627
  section,
30757
30628
  expanded,
@@ -30762,15 +30633,15 @@ function CodeContextSectionView({
30762
30633
  onMeasure
30763
30634
  }) {
30764
30635
  const rootRef = useRef43(null);
30765
- const stripNodes = useMemo39(
30636
+ const stripNodes = useMemo40(
30766
30637
  () => parseMarkdown8(section.summaryMarkdown).children,
30767
30638
  [section.summaryMarkdown]
30768
30639
  );
30769
- const bodyNodes = useMemo39(
30640
+ const bodyNodes = useMemo40(
30770
30641
  () => expanded && section.markdown ? parseMarkdown8(section.markdown).children : null,
30771
30642
  [expanded, section.markdown]
30772
30643
  );
30773
- useEffect43(() => {
30644
+ useEffect44(() => {
30774
30645
  const el = rootRef.current;
30775
30646
  if (!el || typeof ResizeObserver === "undefined") return;
30776
30647
  const report = () => {
@@ -30826,12 +30697,12 @@ function CodeContextSectionView({
30826
30697
  "aria-expanded": expanded,
30827
30698
  onClick: () => onToggle(section.id),
30828
30699
  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 } : {} }) })
30700
+ /* @__PURE__ */ jsx60("span", { className: "squisq-ccx-chevron", "aria-hidden": "true", children: expanded ? "\u25BE" : "\u25B8" }),
30701
+ /* @__PURE__ */ jsx60("span", { className: "squisq-ccx-strip-text", children: /* @__PURE__ */ jsx60(MarkdownRenderer, { nodes: stripNodes, ...linkSchemes ? { linkSchemes } : {} }) })
30831
30702
  ]
30832
30703
  }
30833
30704
  ),
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" }))
30705
+ 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
30706
  ]
30836
30707
  }
30837
30708
  )
@@ -30839,14 +30710,14 @@ function CodeContextSectionView({
30839
30710
  }
30840
30711
 
30841
30712
  // src/codeContext/CodeContextZones.tsx
30842
- import { Fragment as Fragment18, jsx as jsx60 } from "react/jsx-runtime";
30713
+ import { Fragment as Fragment18, jsx as jsx61 } from "react/jsx-runtime";
30843
30714
  function CodeContextZones({ options }) {
30844
30715
  const { monacoEditor } = useEditorContext();
30845
- const [manager, setManager] = useState54(null);
30846
- const [, setZonesVersion] = useState54(0);
30847
- const [expandedById, setExpandedById] = useState54({});
30716
+ const [manager, setManager] = useState55(null);
30717
+ const [, setZonesVersion] = useState55(0);
30718
+ const [expandedById, setExpandedById] = useState55({});
30848
30719
  const seenIds = useRef44(/* @__PURE__ */ new Set());
30849
- useEffect44(() => {
30720
+ useEffect45(() => {
30850
30721
  if (!monacoEditor) return;
30851
30722
  const mgr = new CodeContextZoneManager(monacoEditor);
30852
30723
  const off = mgr.onDidChangeZones(() => setZonesVersion((v2) => v2 + 1));
@@ -30859,7 +30730,7 @@ function CodeContextZones({ options }) {
30859
30730
  }, [monacoEditor]);
30860
30731
  const fileTop = options.fileTop;
30861
30732
  const sections = options.sections;
30862
- const resolved = useMemo40(() => {
30733
+ const resolved = useMemo41(() => {
30863
30734
  const out = [];
30864
30735
  if (fileTop) {
30865
30736
  out.push({ spec: { id: fileTop.id, line: 0, ordinal: 0 }, section: fileTop });
@@ -30869,7 +30740,7 @@ function CodeContextZones({ options }) {
30869
30740
  });
30870
30741
  return out;
30871
30742
  }, [fileTop, sections]);
30872
- useEffect44(() => {
30743
+ useEffect45(() => {
30873
30744
  if (!manager) return;
30874
30745
  manager.sync(resolved.map((r) => r.spec));
30875
30746
  setExpandedById((prev) => {
@@ -30908,11 +30779,11 @@ function CodeContextZones({ options }) {
30908
30779
  [monacoEditor]
30909
30780
  );
30910
30781
  if (!manager) return null;
30911
- return /* @__PURE__ */ jsx60(Fragment18, { children: resolved.map(({ section }) => {
30782
+ return /* @__PURE__ */ jsx61(Fragment18, { children: resolved.map(({ section }) => {
30912
30783
  const domNode = manager.getDomNode(section.id);
30913
30784
  if (!domNode) return null;
30914
30785
  return createPortal10(
30915
- /* @__PURE__ */ jsx60(
30786
+ /* @__PURE__ */ jsx61(
30916
30787
  CodeContextSectionView,
30917
30788
  {
30918
30789
  section,
@@ -30932,7 +30803,7 @@ function CodeContextZones({ options }) {
30932
30803
  }
30933
30804
 
30934
30805
  // src/BlockCardView.tsx
30935
- import { jsx as jsx61, jsxs as jsxs48 } from "react/jsx-runtime";
30806
+ import { jsx as jsx62, jsxs as jsxs48 } from "react/jsx-runtime";
30936
30807
  function BlockCardView({
30937
30808
  active = true,
30938
30809
  blockCount,
@@ -30953,7 +30824,7 @@ function BlockCardView({
30953
30824
  className: `squisq-block-card-frame${active ? " squisq-block-card" : ""}${className ? ` ${className}` : ""}`,
30954
30825
  "data-testid": active ? "block-card-view" : void 0,
30955
30826
  children: [
30956
- /* @__PURE__ */ jsx61("div", { className: `squisq-block-card-frame-body${active ? " squisq-block-card-body" : ""}`, children }),
30827
+ /* @__PURE__ */ jsx62("div", { className: `squisq-block-card-frame-body${active ? " squisq-block-card-body" : ""}`, children }),
30957
30828
  active && /* @__PURE__ */ jsxs48("div", { className: "squisq-block-card-nav", role: "toolbar", "aria-label": "Block navigation", children: [
30958
30829
  /* @__PURE__ */ jsxs48(
30959
30830
  "button",
@@ -30965,7 +30836,7 @@ function BlockCardView({
30965
30836
  "aria-label": "Previous block",
30966
30837
  "data-tooltip": "Previous block",
30967
30838
  children: [
30968
- /* @__PURE__ */ jsx61("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx61(
30839
+ /* @__PURE__ */ jsx62("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx62(
30969
30840
  "path",
30970
30841
  {
30971
30842
  d: "M9 2.5 L4.5 7 L9 11.5",
@@ -30976,7 +30847,7 @@ function BlockCardView({
30976
30847
  fill: "none"
30977
30848
  }
30978
30849
  ) }),
30979
- /* @__PURE__ */ jsx61("span", { children: "Previous" })
30850
+ /* @__PURE__ */ jsx62("span", { children: "Previous" })
30980
30851
  ]
30981
30852
  }
30982
30853
  ),
@@ -30996,8 +30867,8 @@ function BlockCardView({
30996
30867
  "aria-label": "Next block",
30997
30868
  "data-tooltip": "Next block",
30998
30869
  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(
30870
+ /* @__PURE__ */ jsx62("span", { children: "Next" }),
30871
+ /* @__PURE__ */ jsx62("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx62(
31001
30872
  "path",
31002
30873
  {
31003
30874
  d: "M5 2.5 L9.5 7 L5 11.5",
@@ -31020,7 +30891,7 @@ function BlockCardView({
31020
30891
  "aria-label": "Add block",
31021
30892
  "data-tooltip": "Add block after this one",
31022
30893
  children: [
31023
- /* @__PURE__ */ jsx61("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx61(
30894
+ /* @__PURE__ */ jsx62("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx62(
31024
30895
  "path",
31025
30896
  {
31026
30897
  d: "M7 3 L7 11 M3 7 L11 7",
@@ -31030,7 +30901,7 @@ function BlockCardView({
31030
30901
  fill: "none"
31031
30902
  }
31032
30903
  ) }),
31033
- /* @__PURE__ */ jsx61("span", { children: "Add block" })
30904
+ /* @__PURE__ */ jsx62("span", { children: "Add block" })
31034
30905
  ]
31035
30906
  }
31036
30907
  )
@@ -31305,7 +31176,7 @@ function placeClipInBlock(source, fromLine, targetHeadingLine, spec, startAt) {
31305
31176
  }
31306
31177
 
31307
31178
  // src/TimelineTrack.tsx
31308
- import { useCallback as useCallback44, useEffect as useEffect47, useMemo as useMemo41, useRef as useRef47, useState as useState57 } from "react";
31179
+ import { useCallback as useCallback44, useEffect as useEffect48, useMemo as useMemo42, useRef as useRef47, useState as useState58 } from "react";
31309
31180
  import {
31310
31181
  resolveMediaSchedule as resolveMediaSchedule2,
31311
31182
  getDocPlaybackDuration,
@@ -31433,14 +31304,14 @@ function collectTimelinePlaybackSchedule(doc, scheduled) {
31433
31304
  import { memo } from "react";
31434
31305
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS5 } from "@bendyline/squisq/schemas";
31435
31306
  import { BlockRenderer as BlockRenderer4, MediaContext as MediaContext5 } from "@bendyline/squisq-react";
31436
- import { jsx as jsx62 } from "react/jsx-runtime";
31307
+ import { jsx as jsx63 } from "react/jsx-runtime";
31437
31308
  var BlockThumbnail = memo(function BlockThumbnail2({
31438
31309
  visual,
31439
31310
  viewport = VIEWPORT_PRESETS5.landscape,
31440
31311
  basePath = "/",
31441
31312
  mediaProvider = null
31442
31313
  }) {
31443
- return /* @__PURE__ */ jsx62(MediaContext5.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx62(BlockRenderer4, { block: visual, blockTime: 0, basePath, viewport }) });
31314
+ return /* @__PURE__ */ jsx63(MediaContext5.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx63(BlockRenderer4, { block: visual, blockTime: 0, basePath, viewport }) });
31444
31315
  });
31445
31316
 
31446
31317
  // src/resolveBlockVisual.ts
@@ -31464,7 +31335,7 @@ function resolveBlockVisual(doc, block, theme, viewport) {
31464
31335
  }
31465
31336
 
31466
31337
  // src/useTimelineClock.ts
31467
- import { useCallback as useCallback43, useEffect as useEffect45, useRef as useRef45, useState as useState55 } from "react";
31338
+ import { useCallback as useCallback43, useEffect as useEffect46, useRef as useRef45, useState as useState56 } from "react";
31468
31339
  function advanceTime(prev, dt, total) {
31469
31340
  if (total <= 0) return 0;
31470
31341
  return Math.min(total, Math.max(0, prev + dt));
@@ -31484,8 +31355,8 @@ function playTimelineMediaAt(root, time) {
31484
31355
  });
31485
31356
  }
31486
31357
  function useTimelineClock(total) {
31487
- const [currentTime, setCurrentTime] = useState55(0);
31488
- const [isPlaying, setIsPlaying] = useState55(false);
31358
+ const [currentTime, setCurrentTime] = useState56(0);
31359
+ const [isPlaying, setIsPlaying] = useState56(false);
31489
31360
  const rafRef = useRef45(null);
31490
31361
  const lastRef = useRef45(0);
31491
31362
  const currentTimeRef = useRef45(0);
@@ -31493,10 +31364,10 @@ function useTimelineClock(total) {
31493
31364
  const mediaHostRef = useRef45(null);
31494
31365
  currentTimeRef.current = currentTime;
31495
31366
  isPlayingRef.current = isPlaying;
31496
- useEffect45(() => {
31367
+ useEffect46(() => {
31497
31368
  setCurrentTime((t) => Math.min(t, Math.max(0, total)));
31498
31369
  }, [total]);
31499
- useEffect45(() => {
31370
+ useEffect46(() => {
31500
31371
  if (!isPlaying) return;
31501
31372
  lastRef.current = performance.now();
31502
31373
  const tick = (now) => {
@@ -31558,9 +31429,9 @@ function timelineMediaLabel(src, kind) {
31558
31429
  }
31559
31430
 
31560
31431
  // src/TimelineItemMenu.tsx
31561
- import { useEffect as useEffect46, useLayoutEffect as useLayoutEffect9, useRef as useRef46, useState as useState56 } from "react";
31432
+ import { useEffect as useEffect47, useLayoutEffect as useLayoutEffect9, useRef as useRef46, useState as useState57 } from "react";
31562
31433
  import { createPortal as createPortal11 } from "react-dom";
31563
- import { Fragment as Fragment19, jsx as jsx63, jsxs as jsxs49 } from "react/jsx-runtime";
31434
+ import { Fragment as Fragment19, jsx as jsx64, jsxs as jsxs49 } from "react/jsx-runtime";
31564
31435
  function TimelineItemMenu({
31565
31436
  anchor,
31566
31437
  target,
@@ -31573,7 +31444,7 @@ function TimelineItemMenu({
31573
31444
  onClose
31574
31445
  }) {
31575
31446
  const panelRef = useRef46(null);
31576
- const [style, setStyle] = useState56(() => menuStyle(anchor));
31447
+ const [style, setStyle] = useState57(() => menuStyle(anchor));
31577
31448
  useLayoutEffect9(() => {
31578
31449
  const panel = panelRef.current;
31579
31450
  if (!panel) return;
@@ -31587,7 +31458,7 @@ function TimelineItemMenu({
31587
31458
  resizeObserver?.disconnect();
31588
31459
  };
31589
31460
  }, [anchor]);
31590
- useEffect46(() => {
31461
+ useEffect47(() => {
31591
31462
  const onKeyDown = (event) => {
31592
31463
  if (event.key !== "Escape") return;
31593
31464
  event.preventDefault();
@@ -31619,10 +31490,10 @@ function TimelineItemMenu({
31619
31490
  style: { ...style, ...accentStyle(accentColor) },
31620
31491
  children: [
31621
31492
  /* @__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 })
31493
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-kind", children: target.kind === "block" ? "Block" : "Video" }),
31494
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-title", title: target.title, children: target.title })
31624
31495
  ] }),
31625
- target.kind === "block" ? /* @__PURE__ */ jsx63(
31496
+ target.kind === "block" ? /* @__PURE__ */ jsx64(
31626
31497
  BlockMenu,
31627
31498
  {
31628
31499
  target,
@@ -31632,7 +31503,7 @@ function TimelineItemMenu({
31632
31503
  onStartTime: onBlockStartTime,
31633
31504
  onTransition: onBlockTransition
31634
31505
  }
31635
- ) : /* @__PURE__ */ jsx63(VideoMenu, { target, onPatch: onVideoPatch })
31506
+ ) : /* @__PURE__ */ jsx64(VideoMenu, { target, onPatch: onVideoPatch })
31636
31507
  ]
31637
31508
  }
31638
31509
  ),
@@ -31647,12 +31518,12 @@ function BlockMenu({
31647
31518
  onStartTime,
31648
31519
  onTransition
31649
31520
  }) {
31650
- const [explicitDuration, setExplicitDuration] = useState56(target.explicitDuration);
31651
- const [duration, setDuration] = useState56(formatNumber(target.duration));
31652
- const [startTime, setStartTime] = useState56(
31521
+ const [explicitDuration, setExplicitDuration] = useState57(target.explicitDuration);
31522
+ const [duration, setDuration] = useState57(formatNumber(target.duration));
31523
+ const [startTime, setStartTime] = useState57(
31653
31524
  target.startTime == null ? "" : formatNumber(target.startTime)
31654
31525
  );
31655
- const [transition, setTransition] = useState56(target.transition);
31526
+ const [transition, setTransition] = useState57(target.transition);
31656
31527
  const toggleAutotime = (autotimed) => {
31657
31528
  setExplicitDuration(!autotimed);
31658
31529
  if (autotimed) {
@@ -31665,7 +31536,7 @@ function BlockMenu({
31665
31536
  };
31666
31537
  return /* @__PURE__ */ jsxs49("div", { className: "squisq-timeline-item-menu-body", children: [
31667
31538
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-check", children: [
31668
- /* @__PURE__ */ jsx63(
31539
+ /* @__PURE__ */ jsx64(
31669
31540
  "input",
31670
31541
  {
31671
31542
  type: "checkbox",
@@ -31673,10 +31544,10 @@ function BlockMenu({
31673
31544
  onChange: (event) => toggleAutotime(event.target.checked)
31674
31545
  }
31675
31546
  ),
31676
- /* @__PURE__ */ jsx63("span", { children: "Autotime block" })
31547
+ /* @__PURE__ */ jsx64("span", { children: "Autotime block" })
31677
31548
  ] }),
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(
31549
+ /* @__PURE__ */ jsx64("p", { className: "squisq-timeline-item-menu-hint", children: "Uses narration, content, and interior media when no explicit duration is set." }),
31550
+ /* @__PURE__ */ jsx64(
31680
31551
  MenuNumberField,
31681
31552
  {
31682
31553
  label: "Duration",
@@ -31690,7 +31561,7 @@ function BlockMenu({
31690
31561
  }
31691
31562
  }
31692
31563
  ),
31693
- /* @__PURE__ */ jsx63(
31564
+ /* @__PURE__ */ jsx64(
31694
31565
  MenuNumberField,
31695
31566
  {
31696
31567
  label: "Start time",
@@ -31704,8 +31575,8 @@ function BlockMenu({
31704
31575
  }
31705
31576
  ),
31706
31577
  /* @__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(
31578
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "Transition" }),
31579
+ /* @__PURE__ */ jsx64(
31709
31580
  TransitionPicker,
31710
31581
  {
31711
31582
  value: transition,
@@ -31724,11 +31595,11 @@ function VideoMenu({
31724
31595
  target,
31725
31596
  onPatch
31726
31597
  }) {
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 ?? "");
31598
+ const [placement, setPlacement] = useState57(target.placement);
31599
+ const [locked, setLocked] = useState57(target.lockToBlock);
31600
+ const [pipSize, setPipSize] = useState57(target.pipSize ?? "");
31601
+ const [pipShape, setPipShape] = useState57(target.pipShape ?? "");
31602
+ const [pipPosition, setPipPosition] = useState57(target.pipPosition ?? "");
31732
31603
  const placed = placement === "picture-in-picture" || placement === "overlay";
31733
31604
  const placementOptions = [
31734
31605
  target.canUseContentPlacement ? { value: "content", label: "In layout" } : { value: "default", label: "Default" },
@@ -31737,14 +31608,14 @@ function VideoMenu({
31737
31608
  ];
31738
31609
  return /* @__PURE__ */ jsxs49("div", { className: "squisq-timeline-item-menu-body", children: [
31739
31610
  /* @__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(
31611
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "Placement" }),
31612
+ /* @__PURE__ */ jsx64(
31742
31613
  "div",
31743
31614
  {
31744
31615
  className: "squisq-timeline-item-menu-segments",
31745
31616
  role: "group",
31746
31617
  "aria-label": "Video placement",
31747
- children: placementOptions.map((option) => /* @__PURE__ */ jsx63(
31618
+ children: placementOptions.map((option) => /* @__PURE__ */ jsx64(
31748
31619
  "button",
31749
31620
  {
31750
31621
  type: "button",
@@ -31766,7 +31637,7 @@ function VideoMenu({
31766
31637
  ] }),
31767
31638
  placed && /* @__PURE__ */ jsxs49(Fragment19, { children: [
31768
31639
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-check", children: [
31769
- /* @__PURE__ */ jsx63(
31640
+ /* @__PURE__ */ jsx64(
31770
31641
  "input",
31771
31642
  {
31772
31643
  type: "checkbox",
@@ -31780,11 +31651,11 @@ function VideoMenu({
31780
31651
  }
31781
31652
  }
31782
31653
  ),
31783
- /* @__PURE__ */ jsx63("span", { children: "Lock to block" })
31654
+ /* @__PURE__ */ jsx64("span", { children: "Lock to block" })
31784
31655
  ] }),
31785
31656
  placement === "picture-in-picture" && /* @__PURE__ */ jsxs49(Fragment19, { children: [
31786
31657
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31787
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "PIP size" }),
31658
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "PIP size" }),
31788
31659
  /* @__PURE__ */ jsxs49(
31789
31660
  "select",
31790
31661
  {
@@ -31801,14 +31672,14 @@ function VideoMenu({
31801
31672
  titleCase(target.defaultPipSize),
31802
31673
  ")"
31803
31674
  ] }),
31804
- /* @__PURE__ */ jsx63("option", { value: "small", children: "Small" }),
31805
- /* @__PURE__ */ jsx63("option", { value: "large", children: "Large" })
31675
+ /* @__PURE__ */ jsx64("option", { value: "small", children: "Small" }),
31676
+ /* @__PURE__ */ jsx64("option", { value: "large", children: "Large" })
31806
31677
  ]
31807
31678
  }
31808
31679
  )
31809
31680
  ] }),
31810
31681
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31811
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "PIP shape" }),
31682
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "PIP shape" }),
31812
31683
  /* @__PURE__ */ jsxs49(
31813
31684
  "select",
31814
31685
  {
@@ -31825,14 +31696,14 @@ function VideoMenu({
31825
31696
  titleCase(target.defaultPipShape),
31826
31697
  ")"
31827
31698
  ] }),
31828
- /* @__PURE__ */ jsx63("option", { value: "square", children: "Square" }),
31829
- /* @__PURE__ */ jsx63("option", { value: "wide", children: "Wide (16:9)" })
31699
+ /* @__PURE__ */ jsx64("option", { value: "square", children: "Square" }),
31700
+ /* @__PURE__ */ jsx64("option", { value: "wide", children: "Wide (16:9)" })
31830
31701
  ]
31831
31702
  }
31832
31703
  )
31833
31704
  ] }),
31834
31705
  /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31835
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: "PIP position" }),
31706
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: "PIP position" }),
31836
31707
  /* @__PURE__ */ jsxs49(
31837
31708
  "select",
31838
31709
  {
@@ -31849,10 +31720,10 @@ function VideoMenu({
31849
31720
  positionLabel(target.defaultPipPosition),
31850
31721
  ")"
31851
31722
  ] }),
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" })
31723
+ /* @__PURE__ */ jsx64("option", { value: "top-left", children: "Top left" }),
31724
+ /* @__PURE__ */ jsx64("option", { value: "top-right", children: "Top right" }),
31725
+ /* @__PURE__ */ jsx64("option", { value: "bottom-left", children: "Bottom left" }),
31726
+ /* @__PURE__ */ jsx64("option", { value: "bottom-right", children: "Bottom right" })
31856
31727
  ]
31857
31728
  }
31858
31729
  )
@@ -31870,9 +31741,9 @@ function MenuNumberField({
31870
31741
  onChange
31871
31742
  }) {
31872
31743
  return /* @__PURE__ */ jsxs49("label", { className: "squisq-timeline-item-menu-field", children: [
31873
- /* @__PURE__ */ jsx63("span", { className: "squisq-timeline-item-menu-label", children: label }),
31744
+ /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-item-menu-label", children: label }),
31874
31745
  /* @__PURE__ */ jsxs49("span", { className: "squisq-timeline-item-menu-number", children: [
31875
- /* @__PURE__ */ jsx63(
31746
+ /* @__PURE__ */ jsx64(
31876
31747
  "input",
31877
31748
  {
31878
31749
  type: "number",
@@ -31885,7 +31756,7 @@ function MenuNumberField({
31885
31756
  onChange: (event) => onChange(event.target.value)
31886
31757
  }
31887
31758
  ),
31888
- /* @__PURE__ */ jsx63("span", { children: "sec" })
31759
+ /* @__PURE__ */ jsx64("span", { children: "sec" })
31889
31760
  ] })
31890
31761
  ] });
31891
31762
  }
@@ -31930,7 +31801,7 @@ function menuStyle(anchor, element) {
31930
31801
  }
31931
31802
 
31932
31803
  // src/TimelineTrack.tsx
31933
- import { jsx as jsx64, jsxs as jsxs50 } from "react/jsx-runtime";
31804
+ import { jsx as jsx65, jsxs as jsxs50 } from "react/jsx-runtime";
31934
31805
  var PREVIEW_VIEWPORT = VIEWPORT_PRESETS6.landscape;
31935
31806
  var DEFAULT_PX_PER_SECOND = 18;
31936
31807
  var ZOOM_MIN = 4;
@@ -31953,9 +31824,9 @@ function TimelineVideoFilmstrip({
31953
31824
  FILMSTRIP_MAX_FRAMES,
31954
31825
  Math.max(1, Math.ceil(width / FILMSTRIP_FRAME_WIDTH))
31955
31826
  );
31956
- return /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-video-filmstrip", "aria-hidden": "true", children: Array.from({ length: frameCount }, (_2, index2) => {
31827
+ return /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-video-filmstrip", "aria-hidden": "true", children: Array.from({ length: frameCount }, (_2, index2) => {
31957
31828
  const sampleTime = Math.max(0, sourceStart) + Math.max(0, sourceLength) * ((index2 + 0.5) / frameCount);
31958
- return /* @__PURE__ */ jsx64(
31829
+ return /* @__PURE__ */ jsx65(
31959
31830
  "video",
31960
31831
  {
31961
31832
  src: resolvedSrc,
@@ -31998,14 +31869,14 @@ function TimelineTrack({
31998
31869
  colorScheme
31999
31870
  } = useEditorContext();
32000
31871
  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);
31872
+ const [drag, setDrag] = useState58(null);
31873
+ const [itemMenu, setItemMenu] = useState58(null);
31874
+ const [pxPerSecond, setPxPerSecond] = useState58(DEFAULT_PX_PER_SECOND);
32004
31875
  const scrollRef = useRef47(null);
32005
- const blocks = useMemo41(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
31876
+ const blocks = useMemo42(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
32006
31877
  const previewSettings = usePreviewSettingsOptional();
32007
31878
  const previewTheme = previewSettings?.activeTheme ?? DEFAULT_THEME6;
32008
- const visualByBlock = useMemo41(() => {
31879
+ const visualByBlock = useMemo42(() => {
32009
31880
  const map = /* @__PURE__ */ new Map();
32010
31881
  if (doc) {
32011
31882
  for (const b of blocks) {
@@ -32015,16 +31886,16 @@ function TimelineTrack({
32015
31886
  }
32016
31887
  return map;
32017
31888
  }, [doc, blocks, previewTheme]);
32018
- const derivedClips = useMemo41(
31889
+ const derivedClips = useMemo42(
32019
31890
  () => doc ? resolveMediaSchedule2(doc) : [],
32020
31891
  [doc]
32021
31892
  );
32022
31893
  const clips = schedule ?? derivedClips;
32023
- const playbackClips = useMemo41(
31894
+ const playbackClips = useMemo42(
32024
31895
  () => doc ? collectTimelinePlaybackSchedule(doc, clips) : clips,
32025
31896
  [clips, doc]
32026
31897
  );
32027
- const total = useMemo41(() => doc ? getDocPlaybackDuration(doc) : 0, [doc]);
31898
+ const total = useMemo42(() => doc ? getDocPlaybackDuration(doc) : 0, [doc]);
32028
31899
  const width = Math.max(total * pxPerSecond, 200);
32029
31900
  const internalClock = useTimelineClock(total);
32030
31901
  const activeClock = clock ?? internalClock;
@@ -32033,8 +31904,8 @@ function TimelineTrack({
32033
31904
  setDrag(null);
32034
31905
  play();
32035
31906
  }, [play]);
32036
- const [scrubbing, setScrubbing] = useState57(false);
32037
- useEffect47(() => {
31907
+ const [scrubbing, setScrubbing] = useState58(false);
31908
+ useEffect48(() => {
32038
31909
  if (!scrubbing) return;
32039
31910
  const onMove = (e2) => {
32040
31911
  const scroll = scrollRef.current;
@@ -32051,7 +31922,7 @@ function TimelineTrack({
32051
31922
  window.removeEventListener("pointerup", onUp);
32052
31923
  };
32053
31924
  }, [scrubbing, pxPerSecond, seek]);
32054
- const rawClipById = useMemo41(() => {
31925
+ const rawClipById = useMemo42(() => {
32055
31926
  const map = /* @__PURE__ */ new Map();
32056
31927
  if (doc) {
32057
31928
  for (const b of flattenBlocks6(doc.blocks)) for (const m of b.media ?? []) map.set(m.id, m);
@@ -32072,7 +31943,7 @@ function TimelineTrack({
32072
31943
  [blocks]
32073
31944
  );
32074
31945
  const followedBlockRef = useRef47(null);
32075
- useEffect47(() => {
31946
+ useEffect48(() => {
32076
31947
  if (!isPlaying) {
32077
31948
  followedBlockRef.current = null;
32078
31949
  return;
@@ -32083,7 +31954,7 @@ function TimelineTrack({
32083
31954
  const line = headingLine(block);
32084
31955
  if (line != null) goToBlockByLine(line);
32085
31956
  }, [isPlaying, currentTime, blockAtTime, goToBlockByLine]);
32086
- useEffect47(() => {
31957
+ useEffect48(() => {
32087
31958
  if (!isPlaying) return;
32088
31959
  const scroll = scrollRef.current;
32089
31960
  if (!scroll) return;
@@ -32131,8 +32002,8 @@ function TimelineTrack({
32131
32002
  );
32132
32003
  const zoomIn = useCallback44(() => setPxPerSecond((s) => Math.min(ZOOM_MAX, s * ZOOM_FACTOR)), []);
32133
32004
  const zoomOut = useCallback44(() => setPxPerSecond((s) => Math.max(ZOOM_MIN, s / ZOOM_FACTOR)), []);
32134
- const [viewportWidth, setViewportWidth] = useState57(0);
32135
- useEffect47(() => {
32005
+ const [viewportWidth, setViewportWidth] = useState58(0);
32006
+ useEffect48(() => {
32136
32007
  const el = scrollRef.current;
32137
32008
  if (!el || typeof ResizeObserver === "undefined") return;
32138
32009
  const update = () => setViewportWidth(el.clientWidth);
@@ -32146,7 +32017,7 @@ function TimelineTrack({
32146
32017
  const dragRef = useRef47(null);
32147
32018
  dragRef.current = drag;
32148
32019
  const isDragging = drag != null && !drag.committed;
32149
- useEffect47(() => {
32020
+ useEffect48(() => {
32150
32021
  if (!isDragging) return;
32151
32022
  const onMove = (e2) => {
32152
32023
  const d = dragRef.current;
@@ -32177,7 +32048,7 @@ function TimelineTrack({
32177
32048
  window.removeEventListener("pointerup", onUp);
32178
32049
  };
32179
32050
  }, [isDragging]);
32180
- useEffect47(() => {
32051
+ useEffect48(() => {
32181
32052
  if (dragRef.current?.committed) setDrag(null);
32182
32053
  }, [doc]);
32183
32054
  const beginDrag = useCallback44(
@@ -32260,7 +32131,7 @@ function TimelineTrack({
32260
32131
  for (let t = 0; t <= rulerEnd + 1e-3 && ticks.length < 1e3; t += tickSeconds) ticks.push(t);
32261
32132
  return /* @__PURE__ */ jsxs50("div", { className: "squisq-timeline", style: { height }, "data-testid": "timeline-track", children: [
32262
32133
  /* @__PURE__ */ jsxs50("div", { className: "squisq-timeline-controls", children: [
32263
- /* @__PURE__ */ jsx64(
32134
+ /* @__PURE__ */ jsx65(
32264
32135
  "button",
32265
32136
  {
32266
32137
  type: "button",
@@ -32277,7 +32148,7 @@ function TimelineTrack({
32277
32148
  " / ",
32278
32149
  formatClock2(total)
32279
32150
  ] }),
32280
- /* @__PURE__ */ jsx64(
32151
+ /* @__PURE__ */ jsx65(
32281
32152
  "button",
32282
32153
  {
32283
32154
  type: "button",
@@ -32289,7 +32160,7 @@ function TimelineTrack({
32289
32160
  children: "\u2212"
32290
32161
  }
32291
32162
  ),
32292
- /* @__PURE__ */ jsx64(
32163
+ /* @__PURE__ */ jsx65(
32293
32164
  "button",
32294
32165
  {
32295
32166
  type: "button",
@@ -32302,8 +32173,8 @@ function TimelineTrack({
32302
32173
  }
32303
32174
  )
32304
32175
  ] }),
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) => {
32176
+ /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs50("div", { className: "squisq-timeline-inner", style: { width }, children: [
32177
+ /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-row squisq-timeline-row--blocks", children: blocks.map((b, i) => {
32307
32178
  const line = headingLine(b);
32308
32179
  const isActive = line != null && line === activeBlockStartLine;
32309
32180
  const left = previewLeft(i);
@@ -32320,7 +32191,7 @@ function TimelineTrack({
32320
32191
  if (line != null) goToBlockByLine(line);
32321
32192
  },
32322
32193
  children: [
32323
- visualByBlock.has(b.id) && /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-block-thumb", "aria-hidden": true, children: /* @__PURE__ */ jsx64(
32194
+ visualByBlock.has(b.id) && /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-block-thumb", "aria-hidden": true, children: /* @__PURE__ */ jsx65(
32324
32195
  BlockThumbnail,
32325
32196
  {
32326
32197
  visual: visualByBlock.get(b.id),
@@ -32328,7 +32199,7 @@ function TimelineTrack({
32328
32199
  mediaProvider
32329
32200
  }
32330
32201
  ) }),
32331
- prev && headingLine(prev) != null && /* @__PURE__ */ jsx64(
32202
+ prev && headingLine(prev) != null && /* @__PURE__ */ jsx65(
32332
32203
  "span",
32333
32204
  {
32334
32205
  className: "squisq-timeline-edge squisq-timeline-edge--left",
@@ -32349,8 +32220,8 @@ function TimelineTrack({
32349
32220
  )
32350
32221
  }
32351
32222
  ),
32352
- /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-block-label", children: b.title ?? b.id }),
32353
- line != null && /* @__PURE__ */ jsx64(
32223
+ /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-block-label", children: b.title ?? b.id }),
32224
+ line != null && /* @__PURE__ */ jsx65(
32354
32225
  "button",
32355
32226
  {
32356
32227
  type: "button",
@@ -32372,7 +32243,7 @@ function TimelineTrack({
32372
32243
  children: "\u2026"
32373
32244
  }
32374
32245
  ),
32375
- line != null && /* @__PURE__ */ jsx64(
32246
+ line != null && /* @__PURE__ */ jsx65(
32376
32247
  "span",
32377
32248
  {
32378
32249
  className: "squisq-timeline-edge squisq-timeline-edge--right",
@@ -32420,7 +32291,7 @@ function TimelineTrack({
32420
32291
  spillover: raw.spillover
32421
32292
  } : { kind: c.kind, src: c.src, clipStart: c.sourceIn };
32422
32293
  };
32423
- return /* @__PURE__ */ jsx64(
32294
+ return /* @__PURE__ */ jsx65(
32424
32295
  "div",
32425
32296
  {
32426
32297
  className: "squisq-timeline-row squisq-timeline-row--media",
@@ -32457,7 +32328,7 @@ function TimelineTrack({
32457
32328
  if (next) setMarkdownSource(next);
32458
32329
  },
32459
32330
  children: [
32460
- c.kind === "video" && /* @__PURE__ */ jsx64(
32331
+ c.kind === "video" && /* @__PURE__ */ jsx65(
32461
32332
  TimelineVideoFilmstrip,
32462
32333
  {
32463
32334
  src: c.src,
@@ -32466,8 +32337,8 @@ function TimelineTrack({
32466
32337
  width: clipWidth
32467
32338
  }
32468
32339
  ),
32469
- /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(c.src, c.kind) }),
32470
- c.kind === "video" && c.sourceLine != null && /* @__PURE__ */ jsx64(
32340
+ /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(c.src, c.kind) }),
32341
+ c.kind === "video" && c.sourceLine != null && /* @__PURE__ */ jsx65(
32471
32342
  "button",
32472
32343
  {
32473
32344
  type: "button",
@@ -32493,7 +32364,7 @@ function TimelineTrack({
32493
32364
  children: "\u2026"
32494
32365
  }
32495
32366
  ),
32496
- editable && /* @__PURE__ */ jsx64(
32367
+ editable && /* @__PURE__ */ jsx65(
32497
32368
  "span",
32498
32369
  {
32499
32370
  className: "squisq-timeline-edge squisq-timeline-edge--right",
@@ -32538,7 +32409,7 @@ function TimelineTrack({
32538
32409
  ...m.clipStart != null ? { clipStart: m.clipStart } : {},
32539
32410
  ...m.clipEnd != null ? { clipEnd: m.clipEnd } : {}
32540
32411
  };
32541
- return /* @__PURE__ */ jsx64(
32412
+ return /* @__PURE__ */ jsx65(
32542
32413
  "div",
32543
32414
  {
32544
32415
  className: "squisq-timeline-row squisq-timeline-row--media",
@@ -32565,7 +32436,7 @@ function TimelineTrack({
32565
32436
  { onClick: () => selectClipAt(b.startTime, b.id) }
32566
32437
  ),
32567
32438
  children: [
32568
- m.kind === "video" && /* @__PURE__ */ jsx64(
32439
+ m.kind === "video" && /* @__PURE__ */ jsx65(
32569
32440
  TimelineVideoFilmstrip,
32570
32441
  {
32571
32442
  src: m.src,
@@ -32574,8 +32445,8 @@ function TimelineTrack({
32574
32445
  width: clipWidth
32575
32446
  }
32576
32447
  ),
32577
- /* @__PURE__ */ jsx64("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(m.src, m.kind) }),
32578
- m.kind === "video" && m.sourceLine != null && /* @__PURE__ */ jsx64(
32448
+ /* @__PURE__ */ jsx65("span", { className: "squisq-timeline-clip-label", children: timelineMediaLabel(m.src, m.kind) }),
32449
+ m.kind === "video" && m.sourceLine != null && /* @__PURE__ */ jsx65(
32579
32450
  "button",
32580
32451
  {
32581
32452
  type: "button",
@@ -32600,7 +32471,7 @@ function TimelineTrack({
32600
32471
  children: "\u2026"
32601
32472
  }
32602
32473
  ),
32603
- m.sourceLine != null && /* @__PURE__ */ jsx64(
32474
+ m.sourceLine != null && /* @__PURE__ */ jsx65(
32604
32475
  "span",
32605
32476
  {
32606
32477
  className: "squisq-timeline-edge squisq-timeline-edge--right",
@@ -32622,7 +32493,7 @@ function TimelineTrack({
32622
32493
  })
32623
32494
  )
32624
32495
  ] }),
32625
- /* @__PURE__ */ jsx64(
32496
+ /* @__PURE__ */ jsx65(
32626
32497
  "div",
32627
32498
  {
32628
32499
  className: "squisq-timeline-row squisq-timeline-row--ruler",
@@ -32630,10 +32501,10 @@ function TimelineTrack({
32630
32501
  const rect = e2.currentTarget.getBoundingClientRect();
32631
32502
  seek((e2.clientX - rect.left) / pxPerSecond);
32632
32503
  },
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))
32504
+ 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
32505
  }
32635
32506
  ),
32636
- /* @__PURE__ */ jsx64(
32507
+ /* @__PURE__ */ jsx65(
32637
32508
  "div",
32638
32509
  {
32639
32510
  className: "squisq-timeline-playhead",
@@ -32645,11 +32516,11 @@ function TimelineTrack({
32645
32516
  pause();
32646
32517
  setScrubbing(true);
32647
32518
  },
32648
- children: /* @__PURE__ */ jsx64("div", { className: "squisq-timeline-playhead-knob" })
32519
+ children: /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-playhead-knob" })
32649
32520
  }
32650
32521
  )
32651
32522
  ] }) }),
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(
32523
+ /* @__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
32524
  MediaClipLayer,
32654
32525
  {
32655
32526
  schedule: playbackClips,
@@ -32658,7 +32529,7 @@ function TimelineTrack({
32658
32529
  basePath
32659
32530
  }
32660
32531
  ) }) }),
32661
- itemMenu && itemMenuTarget && /* @__PURE__ */ jsx64(
32532
+ itemMenu && itemMenuTarget && /* @__PURE__ */ jsx65(
32662
32533
  TimelineItemMenu,
32663
32534
  {
32664
32535
  anchor: itemMenu.anchor,
@@ -32713,9 +32584,9 @@ function formatDur(seconds) {
32713
32584
  }
32714
32585
 
32715
32586
  // src/TimelineVideoPanel.tsx
32716
- import { useMemo as useMemo42 } from "react";
32587
+ import { useMemo as useMemo43 } from "react";
32717
32588
  import { MediaClipLayer as MediaClipLayer2 } from "@bendyline/squisq-react";
32718
- import { jsx as jsx65, jsxs as jsxs51 } from "react/jsx-runtime";
32589
+ import { jsx as jsx66, jsxs as jsxs51 } from "react/jsx-runtime";
32719
32590
  function TimelineVideoPanel({
32720
32591
  schedule,
32721
32592
  currentTime,
@@ -32723,7 +32594,7 @@ function TimelineVideoPanel({
32723
32594
  basePath = "/",
32724
32595
  onClose
32725
32596
  }) {
32726
- const videos = useMemo42(() => schedule.filter((clip) => clip.kind === "video"), [schedule]);
32597
+ const videos = useMemo43(() => schedule.filter((clip) => clip.kind === "video"), [schedule]);
32727
32598
  const activeVideos = videos.filter(
32728
32599
  (clip) => currentTime >= clip.absoluteStart && currentTime < clip.absoluteEnd
32729
32600
  );
@@ -32736,10 +32607,10 @@ function TimelineVideoPanel({
32736
32607
  "aria-label": "Timeline video preview",
32737
32608
  children: [
32738
32609
  /* @__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(
32610
+ /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-title", children: "Video monitor" }),
32611
+ /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-label", title: activeLabel, children: activeLabel }),
32612
+ /* @__PURE__ */ jsx66("span", { className: "squisq-timeline-video-time", children: formatClock3(currentTime) }),
32613
+ onClose && /* @__PURE__ */ jsx66(
32743
32614
  "button",
32744
32615
  {
32745
32616
  type: "button",
@@ -32751,8 +32622,8 @@ function TimelineVideoPanel({
32751
32622
  }
32752
32623
  )
32753
32624
  ] }),
32754
- /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsxs51("div", { className: "squisq-timeline-video-stage", children: [
32755
- /* @__PURE__ */ jsx65(
32625
+ /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsxs51("div", { className: "squisq-timeline-video-stage", children: [
32626
+ /* @__PURE__ */ jsx66(
32756
32627
  MediaClipLayer2,
32757
32628
  {
32758
32629
  schedule: videos,
@@ -32764,7 +32635,7 @@ function TimelineVideoPanel({
32764
32635
  muted: true
32765
32636
  }
32766
32637
  ),
32767
- activeVideos.length === 0 && /* @__PURE__ */ jsx65("div", { className: "squisq-timeline-video-empty", children: "Move the playhead onto a video clip" })
32638
+ activeVideos.length === 0 && /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-empty", children: "Move the playhead onto a video clip" })
32768
32639
  ] }) })
32769
32640
  ]
32770
32641
  }
@@ -32777,12 +32648,12 @@ function formatClock3(seconds) {
32777
32648
  }
32778
32649
 
32779
32650
  // src/TimelineCompositionPanel.tsx
32780
- import { useMemo as useMemo43 } from "react";
32651
+ import { useMemo as useMemo44 } from "react";
32781
32652
  import { getDocPlaybackDuration as getDocPlaybackDuration2, resolveMediaSchedule as resolveMediaSchedule3 } from "@bendyline/squisq/schemas";
32782
32653
  import { DocPlayer } from "@bendyline/squisq-react";
32783
32654
 
32784
32655
  // src/usePreviewProjection.ts
32785
- import { useEffect as useEffect48, useState as useState58 } from "react";
32656
+ import { useEffect as useEffect49, useState as useState59 } from "react";
32786
32657
  import { resolveAudioMapping } from "@bendyline/squisq/doc";
32787
32658
  import { applyTransform } from "@bendyline/squisq/transform";
32788
32659
  function hasEquivalentAudio(left, right) {
@@ -32802,8 +32673,8 @@ function preserveEquivalentAudio(previous, next) {
32802
32673
  };
32803
32674
  }
32804
32675
  function usePreviewProjection(doc, transformStyle, workspaceContainer, documentTitle2) {
32805
- const [projection, setProjection] = useState58(null);
32806
- useEffect48(() => {
32676
+ const [projection, setProjection] = useState59(null);
32677
+ useEffect49(() => {
32807
32678
  if (!doc || !doc.blocks.length) {
32808
32679
  setProjection(null);
32809
32680
  return;
@@ -32837,7 +32708,7 @@ function usePreviewProjection(doc, transformStyle, workspaceContainer, documentT
32837
32708
  }
32838
32709
 
32839
32710
  // src/TimelineCompositionPanel.tsx
32840
- import { jsx as jsx66, jsxs as jsxs52 } from "react/jsx-runtime";
32711
+ import { jsx as jsx67, jsxs as jsxs52 } from "react/jsx-runtime";
32841
32712
  function TimelineCompositionPanel({
32842
32713
  doc,
32843
32714
  clock,
@@ -32869,11 +32740,11 @@ function TimelineCompositionPanel({
32869
32740
  );
32870
32741
  const contentDoc = projection?.contentDoc ?? null;
32871
32742
  const playerDoc = projection?.playerDoc ?? null;
32872
- const totalDuration = useMemo43(
32743
+ const totalDuration = useMemo44(
32873
32744
  () => playerDoc ? getDocPlaybackDuration2(playerDoc) : 0,
32874
32745
  [playerDoc]
32875
32746
  );
32876
- const effectiveVideoPresentation = useMemo43(() => {
32747
+ const effectiveVideoPresentation = useMemo44(() => {
32877
32748
  if (!playerDoc) return activeVideoPresentation;
32878
32749
  const activeVideo = resolveMediaSchedule3(playerDoc).find(
32879
32750
  (clip) => clip.kind === "video" && clock.currentTime >= clip.absoluteStart && clock.currentTime < clip.absoluteEnd
@@ -32882,7 +32753,7 @@ function TimelineCompositionPanel({
32882
32753
  if (activeVideo?.placement === "overlay") return "full-frame";
32883
32754
  return activeVideoPresentation;
32884
32755
  }, [activeVideoPresentation, clock.currentTime, playerDoc]);
32885
- const audioController = useMemo43(
32756
+ const audioController = useMemo44(
32886
32757
  () => ({
32887
32758
  currentTime: clock.currentTime,
32888
32759
  isPlaying: clock.isPlaying,
@@ -32908,11 +32779,11 @@ function TimelineCompositionPanel({
32908
32779
  "aria-label": "Timeline video composition preview",
32909
32780
  children: [
32910
32781
  /* @__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(
32782
+ /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-video-title", children: "Video composition" }),
32783
+ /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-video-label", children: formatPresentation(effectiveVideoPresentation) }),
32784
+ /* @__PURE__ */ jsx67(PreviewToolbarControls, { displayMode: "video" }),
32785
+ /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-video-time", children: formatClock4(clock.currentTime) }),
32786
+ onClose && /* @__PURE__ */ jsx67(
32916
32787
  "button",
32917
32788
  {
32918
32789
  type: "button",
@@ -32924,7 +32795,7 @@ function TimelineCompositionPanel({
32924
32795
  }
32925
32796
  )
32926
32797
  ] }),
32927
- /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-composition-stage", children: playerDoc ? /* @__PURE__ */ jsx66(
32798
+ /* @__PURE__ */ jsx67("div", { className: "squisq-timeline-video-body", children: /* @__PURE__ */ jsx67("div", { className: "squisq-timeline-composition-stage", children: playerDoc ? /* @__PURE__ */ jsx67(
32928
32799
  DocPlayer,
32929
32800
  {
32930
32801
  doc: playerDoc,
@@ -32950,7 +32821,7 @@ function TimelineCompositionPanel({
32950
32821
  enableSwipe: false,
32951
32822
  globalKeyboardShortcuts: false
32952
32823
  }
32953
- ) : /* @__PURE__ */ jsx66("div", { className: "squisq-timeline-video-empty", children: "Preparing video composition\u2026" }) }) })
32824
+ ) : /* @__PURE__ */ jsx67("div", { className: "squisq-timeline-video-empty", children: "Preparing video composition\u2026" }) }) })
32954
32825
  ]
32955
32826
  }
32956
32827
  );
@@ -32967,7 +32838,7 @@ function formatPresentation(presentation) {
32967
32838
  }
32968
32839
 
32969
32840
  // src/TimelineToolbar.tsx
32970
- import { jsx as jsx67, jsxs as jsxs53 } from "react/jsx-runtime";
32841
+ import { jsx as jsx68, jsxs as jsxs53 } from "react/jsx-runtime";
32971
32842
  function TimelineToolbar({
32972
32843
  literalVideoVisible,
32973
32844
  compositionVisible,
@@ -32984,7 +32855,7 @@ function TimelineToolbar({
32984
32855
  "aria-label": "Timeline view controls",
32985
32856
  "data-testid": "timeline-toolbar",
32986
32857
  children: [
32987
- /* @__PURE__ */ jsx67("span", { className: "squisq-timeline-toolbar-title", children: "Preview panes" }),
32858
+ /* @__PURE__ */ jsx68("span", { className: "squisq-timeline-toolbar-title", children: "Preview panes" }),
32988
32859
  /* @__PURE__ */ jsxs53(
32989
32860
  "button",
32990
32861
  {
@@ -32997,7 +32868,7 @@ function TimelineToolbar({
32997
32868
  "data-tooltip": literalVideoVisible ? "Hide literal video" : "Show literal video",
32998
32869
  children: [
32999
32870
  /* @__PURE__ */ jsxs53("svg", { width: "15", height: "15", viewBox: "0 0 15 15", "aria-hidden": "true", children: [
33000
- /* @__PURE__ */ jsx67(
32871
+ /* @__PURE__ */ jsx68(
33001
32872
  "rect",
33002
32873
  {
33003
32874
  x: "1.5",
@@ -33010,7 +32881,7 @@ function TimelineToolbar({
33010
32881
  strokeWidth: "1.4"
33011
32882
  }
33012
32883
  ),
33013
- /* @__PURE__ */ jsx67(
32884
+ /* @__PURE__ */ jsx68(
33014
32885
  "path",
33015
32886
  {
33016
32887
  d: "M10 5.5 13.5 4v7L10 9.5z",
@@ -33021,7 +32892,7 @@ function TimelineToolbar({
33021
32892
  }
33022
32893
  )
33023
32894
  ] }),
33024
- /* @__PURE__ */ jsx67("span", { children: "Video monitor" })
32895
+ /* @__PURE__ */ jsx68("span", { children: "Video monitor" })
33025
32896
  ]
33026
32897
  }
33027
32898
  ),
@@ -33037,7 +32908,7 @@ function TimelineToolbar({
33037
32908
  "data-tooltip": compositionVisible ? "Hide video composition" : "Show video composition",
33038
32909
  children: [
33039
32910
  /* @__PURE__ */ jsxs53("svg", { width: "15", height: "15", viewBox: "0 0 15 15", "aria-hidden": "true", children: [
33040
- /* @__PURE__ */ jsx67(
32911
+ /* @__PURE__ */ jsx68(
33041
32912
  "rect",
33042
32913
  {
33043
32914
  x: "1.5",
@@ -33050,10 +32921,10 @@ function TimelineToolbar({
33050
32921
  strokeWidth: "1.4"
33051
32922
  }
33052
32923
  ),
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" })
32924
+ /* @__PURE__ */ jsx68("path", { d: "M5 13h5M7.5 11v2", stroke: "currentColor", strokeWidth: "1.4" }),
32925
+ /* @__PURE__ */ jsx68("path", { d: "m6.3 5 3 1.5-3 1.5z", fill: "currentColor" })
33055
32926
  ] }),
33056
- /* @__PURE__ */ jsx67("span", { children: "Video composition" })
32927
+ /* @__PURE__ */ jsx68("span", { children: "Video composition" })
33057
32928
  ]
33058
32929
  }
33059
32930
  )
@@ -33063,7 +32934,7 @@ function TimelineToolbar({
33063
32934
  }
33064
32935
 
33065
32936
  // src/PlainHtmlPreview.tsx
33066
- import { useCallback as useCallback45, useEffect as useEffect49, useMemo as useMemo44, useRef as useRef48, useState as useState59 } from "react";
32937
+ import { useCallback as useCallback45, useEffect as useEffect50, useMemo as useMemo45, useRef as useRef48, useState as useState60 } from "react";
33067
32938
  import { parseMarkdown as parseMarkdown9 } from "@bendyline/squisq/markdown";
33068
32939
 
33069
32940
  // src/utils/collectInlineFontAwesomeCss.ts
@@ -33098,7 +32969,7 @@ function isFontAwesomeRule(rule) {
33098
32969
  }
33099
32970
 
33100
32971
  // src/PlainHtmlPreview.tsx
33101
- import { jsx as jsx68 } from "react/jsx-runtime";
32972
+ import { jsx as jsx69 } from "react/jsx-runtime";
33102
32973
  var cachedRender = null;
33103
32974
  var cachedRenderPromise = null;
33104
32975
  function loadRenderFn() {
@@ -33143,9 +33014,9 @@ function PlainHtmlPreview({
33143
33014
  },
33144
33015
  [onFrameChange]
33145
33016
  );
33146
- const mdDoc = useMemo44(() => parseMarkdown9(markdown), [markdown]);
33147
- const [resolvedImages, setResolvedImages] = useState59(null);
33148
- useEffect49(() => {
33017
+ const mdDoc = useMemo45(() => parseMarkdown9(markdown), [markdown]);
33018
+ const [resolvedImages, setResolvedImages] = useState60(null);
33019
+ useEffect50(() => {
33149
33020
  if (!mediaProvider) {
33150
33021
  setResolvedImages(null);
33151
33022
  return;
@@ -33173,16 +33044,16 @@ function PlainHtmlPreview({
33173
33044
  cancelled = true;
33174
33045
  };
33175
33046
  }, [mdDoc, mediaProvider, mediaRevision]);
33176
- const mergedImages = useMemo44(() => {
33047
+ const mergedImages = useMemo45(() => {
33177
33048
  if (!resolvedImages && !images) return void 0;
33178
33049
  const merged = /* @__PURE__ */ new Map();
33179
33050
  if (resolvedImages) for (const [k2, v2] of resolvedImages) merged.set(k2, v2);
33180
33051
  if (images) for (const [k2, v2] of images) merged.set(k2, v2);
33181
33052
  return merged;
33182
33053
  }, [resolvedImages, images]);
33183
- const iconsCss = useMemo44(() => collectInlineFontAwesomeCss(), []);
33184
- const [renderFn, setRenderFn] = useState59(() => cachedRender);
33185
- useEffect49(() => {
33054
+ const iconsCss = useMemo45(() => collectInlineFontAwesomeCss(), []);
33055
+ const [renderFn, setRenderFn] = useState60(() => cachedRender);
33056
+ useEffect50(() => {
33186
33057
  if (renderFn) return;
33187
33058
  let cancelled = false;
33188
33059
  loadRenderFn().then((fn) => {
@@ -33192,7 +33063,7 @@ function PlainHtmlPreview({
33192
33063
  cancelled = true;
33193
33064
  };
33194
33065
  }, [renderFn]);
33195
- const html = useMemo44(
33066
+ const html = useMemo45(
33196
33067
  () => renderFn ? renderFn(mdDoc, { title, images: mergedImages, theme, iconsCss }) : "",
33197
33068
  [renderFn, mdDoc, title, mergedImages, theme, iconsCss]
33198
33069
  );
@@ -33215,7 +33086,7 @@ function PlainHtmlPreview({
33215
33086
  frameDocument.addEventListener("click", handleClick, true);
33216
33087
  removeFrameLinkHandlerRef.current = () => frameDocument.removeEventListener("click", handleClick, true);
33217
33088
  }, [onLinkClick]);
33218
- useEffect49(() => {
33089
+ useEffect50(() => {
33219
33090
  installFrameLinkHandler();
33220
33091
  return () => removeFrameLinkHandlerRef.current();
33221
33092
  }, [html, installFrameLinkHandler]);
@@ -33311,11 +33182,11 @@ function PlainHtmlPreview({
33311
33182
  style2.remove();
33312
33183
  };
33313
33184
  }, [onCopyCode, showCodeCopyButton]);
33314
- useEffect49(() => {
33185
+ useEffect50(() => {
33315
33186
  installFrameCodeCopyControls();
33316
33187
  return () => removeFrameCodeCopyControlsRef.current();
33317
33188
  }, [html, installFrameCodeCopyControls]);
33318
- useEffect49(() => {
33189
+ useEffect50(() => {
33319
33190
  if (!globalKeyboardShortcuts) return;
33320
33191
  const handleKeyDown = (event) => {
33321
33192
  if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.key !== "ArrowDown" && event.key !== "ArrowUp") {
@@ -33339,7 +33210,7 @@ function PlainHtmlPreview({
33339
33210
  document.addEventListener("keydown", handleKeyDown);
33340
33211
  return () => document.removeEventListener("keydown", handleKeyDown);
33341
33212
  }, [globalKeyboardShortcuts]);
33342
- return /* @__PURE__ */ jsx68(
33213
+ return /* @__PURE__ */ jsx69(
33343
33214
  "iframe",
33344
33215
  {
33345
33216
  ref: setIframeRef,
@@ -33394,7 +33265,7 @@ function collectImageRefs(doc) {
33394
33265
  }
33395
33266
 
33396
33267
  // src/PreviewPanel.tsx
33397
- import { useState as useState62, useEffect as useEffect53, useMemo as useMemo48, useCallback as useCallback49, useRef as useRef52 } from "react";
33268
+ import { useState as useState63, useEffect as useEffect54, useMemo as useMemo49, useCallback as useCallback49, useRef as useRef52 } from "react";
33398
33269
  import { createPortal as createPortal13 } from "react-dom";
33399
33270
  import { DocPlayer as DocPlayer2, LinearDocView as LinearDocView2, useMediaProvider as useMediaProvider2 } from "@bendyline/squisq-react";
33400
33271
  import { resolveTransformStyle as resolveTransformStyle2 } from "@bendyline/squisq/transform";
@@ -33533,15 +33404,15 @@ import {
33533
33404
  createContext as createContext5,
33534
33405
  useCallback as useCallback46,
33535
33406
  useContext as useContext5,
33536
- useEffect as useEffect50,
33407
+ useEffect as useEffect51,
33537
33408
  useId as useId14,
33538
33409
  useLayoutEffect as useLayoutEffect10,
33539
- useMemo as useMemo45,
33410
+ useMemo as useMemo46,
33540
33411
  useRef as useRef49,
33541
- useState as useState60
33412
+ useState as useState61
33542
33413
  } from "react";
33543
33414
  import { createPortal as createPortal12 } from "react-dom";
33544
- import { jsx as jsx69, jsxs as jsxs54 } from "react/jsx-runtime";
33415
+ import { jsx as jsx70, jsxs as jsxs54 } from "react/jsx-runtime";
33545
33416
  var PresentationModeContext = createContext5(null);
33546
33417
  function usePresentationMode() {
33547
33418
  const value = useContext5(PresentationModeContext);
@@ -33555,6 +33426,25 @@ function usePresentationModeOptional() {
33555
33426
  }
33556
33427
  var POPUP_WIDTH = 1280;
33557
33428
  var POPUP_HEIGHT = 720;
33429
+ var FULLSCREEN_RELEASE_TIMEOUT_MS = 4e3;
33430
+ function waitForFullscreenRelease(ownerDocument, root, timeoutMs) {
33431
+ if (ownerDocument.fullscreenElement !== root) return Promise.resolve(true);
33432
+ return new Promise((resolve) => {
33433
+ const settle = (released) => {
33434
+ ownerDocument.removeEventListener("fullscreenchange", handleChange);
33435
+ window.clearTimeout(timer);
33436
+ resolve(released);
33437
+ };
33438
+ const handleChange = () => {
33439
+ if (ownerDocument.fullscreenElement !== root) settle(true);
33440
+ };
33441
+ const timer = window.setTimeout(
33442
+ () => settle(ownerDocument.fullscreenElement !== root),
33443
+ timeoutMs
33444
+ );
33445
+ ownerDocument.addEventListener("fullscreenchange", handleChange);
33446
+ });
33447
+ }
33558
33448
  function copyDocumentStyles(source, target) {
33559
33449
  for (const sheet of Array.from(source.styleSheets)) {
33560
33450
  if (sheet.href) {
@@ -33621,10 +33511,10 @@ function PresentationModeProvider({
33621
33511
  const { activeView, colorScheme, doc } = useEditorContext();
33622
33512
  const { activeTheme } = usePreviewSettings();
33623
33513
  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);
33514
+ const [selectedTarget, setSelectedTarget] = useState61("control");
33515
+ const [activeTarget, setActiveTarget] = useState61(null);
33516
+ const [popupRoot, setPopupRoot] = useState61(null);
33517
+ const [error, setError] = useState61(null);
33628
33518
  const activeTargetRef = useRef49(activeTarget);
33629
33519
  activeTargetRef.current = activeTarget;
33630
33520
  const previousActiveTargetRef = useRef49(null);
@@ -33632,7 +33522,7 @@ function PresentationModeProvider({
33632
33522
  const popupRef = useRef49(null);
33633
33523
  const popupCleanupRef = useRef49(null);
33634
33524
  const fullscreenSupported = typeof document !== "undefined" && typeof document.documentElement.requestFullscreen === "function";
33635
- const availableTargets = useMemo45(
33525
+ const availableTargets = useMemo46(
33636
33526
  () => [
33637
33527
  "control",
33638
33528
  ...allowWindow ? ["window"] : [],
@@ -33672,7 +33562,12 @@ function PresentationModeProvider({
33672
33562
  return;
33673
33563
  }
33674
33564
  }
33675
- if (ownerDocument.fullscreenElement === root) {
33565
+ const released = await waitForFullscreenRelease(
33566
+ ownerDocument,
33567
+ root,
33568
+ FULLSCREEN_RELEASE_TIMEOUT_MS
33569
+ );
33570
+ if (!released) {
33676
33571
  setError("Still in full screen. Press Escape to leave it.");
33677
33572
  return;
33678
33573
  }
@@ -33767,12 +33662,12 @@ function PresentationModeProvider({
33767
33662
  },
33768
33663
  [availableTargets, selectedTarget, stop]
33769
33664
  );
33770
- useEffect50(() => {
33665
+ useEffect51(() => {
33771
33666
  if (availableTargets.includes(selectedTarget)) return;
33772
33667
  setSelectedTarget("control");
33773
33668
  if (activeTargetRef.current !== null) void stop();
33774
33669
  }, [availableTargets, selectedTarget, stop]);
33775
- useEffect50(() => {
33670
+ useEffect51(() => {
33776
33671
  const root = rootRef.current;
33777
33672
  const ownerDocument = root?.ownerDocument;
33778
33673
  if (!root || !ownerDocument) return;
@@ -33784,7 +33679,7 @@ function PresentationModeProvider({
33784
33679
  ownerDocument.addEventListener("fullscreenchange", handleFullscreenChange);
33785
33680
  return () => ownerDocument.removeEventListener("fullscreenchange", handleFullscreenChange);
33786
33681
  }, [rootRef]);
33787
- useEffect50(() => {
33682
+ useEffect51(() => {
33788
33683
  const root = rootRef.current;
33789
33684
  if (!root) return;
33790
33685
  if (activeTarget) root.dataset.presentationMode = activeTarget;
@@ -33793,10 +33688,10 @@ function PresentationModeProvider({
33793
33688
  delete root.dataset.presentationMode;
33794
33689
  };
33795
33690
  }, [activeTarget, rootRef]);
33796
- useEffect50(() => {
33691
+ useEffect51(() => {
33797
33692
  if (activeView !== "preview" && activeTargetRef.current !== null) void stop();
33798
33693
  }, [activeView, stop]);
33799
- useEffect50(() => {
33694
+ useEffect51(() => {
33800
33695
  const previous = previousActiveTargetRef.current;
33801
33696
  previousActiveTargetRef.current = activeTarget;
33802
33697
  if (previous === null || activeTarget !== null) return;
@@ -33804,7 +33699,7 @@ function PresentationModeProvider({
33804
33699
  returnFocusRef.current = null;
33805
33700
  if (target?.isConnected) target.focus();
33806
33701
  }, [activeTarget]);
33807
- useEffect50(() => {
33702
+ useEffect51(() => {
33808
33703
  if (activeTarget !== "control") return;
33809
33704
  const ownerDocument = rootRef.current?.ownerDocument;
33810
33705
  if (!ownerDocument) return;
@@ -33816,12 +33711,12 @@ function PresentationModeProvider({
33816
33711
  ownerDocument.addEventListener("keydown", handleKeyDown);
33817
33712
  return () => ownerDocument.removeEventListener("keydown", handleKeyDown);
33818
33713
  }, [activeTarget, rootRef, stop]);
33819
- useEffect50(() => {
33714
+ useEffect51(() => {
33820
33715
  if (!error) return;
33821
33716
  const timer = window.setTimeout(() => setError(null), 6e3);
33822
33717
  return () => window.clearTimeout(timer);
33823
33718
  }, [error]);
33824
- useEffect50(
33719
+ useEffect51(
33825
33720
  () => () => {
33826
33721
  popupCleanupRef.current?.();
33827
33722
  const popup = popupRef.current;
@@ -33834,7 +33729,7 @@ function PresentationModeProvider({
33834
33729
  },
33835
33730
  [rootRef]
33836
33731
  );
33837
- const value = useMemo45(
33732
+ const value = useMemo46(
33838
33733
  () => ({
33839
33734
  selectedTarget,
33840
33735
  activeTarget,
@@ -33873,8 +33768,8 @@ function PresentationModeProvider({
33873
33768
  "aria-label": "Exit presentation mode",
33874
33769
  title: "Exit presentation mode (Esc)",
33875
33770
  children: [
33876
- /* @__PURE__ */ jsx69(Icon, { icon: "fa-solid fa-compress" }),
33877
- /* @__PURE__ */ jsx69("span", { children: "Exit presentation" })
33771
+ /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-compress" }),
33772
+ /* @__PURE__ */ jsx70("span", { children: "Exit presentation" })
33878
33773
  ]
33879
33774
  }
33880
33775
  ) : null;
@@ -33883,7 +33778,7 @@ function PresentationModeProvider({
33883
33778
  (activeTarget === "control" || activeTarget === "fullscreen") && exitButton,
33884
33779
  activeTarget === "window" && popupRoot && exitButton ? createPortal12(exitButton, popupRoot) : null,
33885
33780
  error && typeof document !== "undefined" ? createPortal12(
33886
- /* @__PURE__ */ jsx69("div", { className: "squisq-presentation-error", "data-theme": colorScheme, role: "alert", children: error }),
33781
+ /* @__PURE__ */ jsx70("div", { className: "squisq-presentation-error", "data-theme": colorScheme, role: "alert", children: error }),
33887
33782
  document.body
33888
33783
  ) : null
33889
33784
  ] });
@@ -33924,8 +33819,8 @@ function PresentationModeControl() {
33924
33819
  const { colorScheme } = useEditorContext();
33925
33820
  const triggerRef = useRef49(null);
33926
33821
  const menuRef = useRef49(null);
33927
- const [open, setOpen] = useState60(false);
33928
- const [anchor, setAnchor] = useState60(null);
33822
+ const [open, setOpen] = useState61(false);
33823
+ const [anchor, setAnchor] = useState61(null);
33929
33824
  const options = PRESENTATION_OPTIONS.filter((option) => availableTargets.includes(option.target));
33930
33825
  const selected = options.find((option) => option.target === selectedTarget) ?? PRESENTATION_OPTIONS[0];
33931
33826
  const updatePosition = useCallback46(() => {
@@ -33950,7 +33845,7 @@ function PresentationModeControl() {
33950
33845
  updatePosition();
33951
33846
  setOpen(true);
33952
33847
  }, [updatePosition]);
33953
- useEffect50(() => {
33848
+ useEffect51(() => {
33954
33849
  if (!open) return;
33955
33850
  const handlePointerDown = (event) => {
33956
33851
  const target = event.target;
@@ -33980,7 +33875,7 @@ function PresentationModeControl() {
33980
33875
  (checked ?? first)?.focus();
33981
33876
  }, [anchor, open]);
33982
33877
  return /* @__PURE__ */ jsxs54("div", { className: "squisq-presentation-control", children: [
33983
- /* @__PURE__ */ jsx69(
33878
+ /* @__PURE__ */ jsx70(
33984
33879
  "button",
33985
33880
  {
33986
33881
  type: "button",
@@ -33989,10 +33884,10 @@ function PresentationModeControl() {
33989
33884
  "aria-pressed": activeTarget !== null,
33990
33885
  "data-tooltip": activeTarget ? "Exit presentation" : `Present: ${selected.label}`,
33991
33886
  onClick: () => void (activeTarget ? stop() : start()),
33992
- children: /* @__PURE__ */ jsx69(Icon, { icon: "fa-solid fa-display" })
33887
+ children: /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-display" })
33993
33888
  }
33994
33889
  ),
33995
- options.length > 1 && /* @__PURE__ */ jsx69(
33890
+ options.length > 1 && /* @__PURE__ */ jsx70(
33996
33891
  "button",
33997
33892
  {
33998
33893
  ref: triggerRef,
@@ -34008,11 +33903,11 @@ function PresentationModeControl() {
34008
33903
  event.preventDefault();
34009
33904
  openMenu();
34010
33905
  },
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" }) })
33906
+ 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
33907
  }
34013
33908
  ),
34014
33909
  open && anchor ? createPortal12(
34015
- /* @__PURE__ */ jsx69(
33910
+ /* @__PURE__ */ jsx70(
34016
33911
  "div",
34017
33912
  {
34018
33913
  ref: menuRef,
@@ -34056,24 +33951,24 @@ function PresentationModeControl() {
34056
33951
  closeMenu(true);
34057
33952
  },
34058
33953
  children: [
34059
- /* @__PURE__ */ jsx69(
33954
+ /* @__PURE__ */ jsx70(
34060
33955
  "span",
34061
33956
  {
34062
33957
  className: "squisq-use-mode-menu-icon squisq-presentation-menu-icon",
34063
33958
  "aria-hidden": "true",
34064
- children: /* @__PURE__ */ jsx69(Icon, { icon: option.icon })
33959
+ children: /* @__PURE__ */ jsx70(Icon, { icon: option.icon })
34065
33960
  }
34066
33961
  ),
34067
33962
  /* @__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 })
33963
+ /* @__PURE__ */ jsx70("span", { className: "squisq-use-mode-menu-label squisq-presentation-menu-label", children: option.label }),
33964
+ /* @__PURE__ */ jsx70("span", { className: "squisq-use-mode-menu-summary squisq-presentation-menu-summary", children: disabled ? "Full screen is unavailable." : option.summary })
34070
33965
  ] }),
34071
- /* @__PURE__ */ jsx69(
33966
+ /* @__PURE__ */ jsx70(
34072
33967
  "span",
34073
33968
  {
34074
33969
  className: "squisq-use-mode-menu-check squisq-presentation-menu-check",
34075
33970
  "aria-hidden": "true",
34076
- children: isSelected && /* @__PURE__ */ jsx69(Icon, { icon: "fa-solid fa-check" })
33971
+ children: isSelected && /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-check" })
34077
33972
  }
34078
33973
  )
34079
33974
  ]
@@ -34093,12 +33988,12 @@ import {
34093
33988
  createContext as createContext6,
34094
33989
  useCallback as useCallback47,
34095
33990
  useContext as useContext6,
34096
- useEffect as useEffect51,
34097
- useMemo as useMemo46,
33991
+ useEffect as useEffect52,
33992
+ useMemo as useMemo47,
34098
33993
  useRef as useRef50,
34099
- useState as useState61
33994
+ useState as useState62
34100
33995
  } from "react";
34101
- import { jsx as jsx70, jsxs as jsxs55 } from "react/jsx-runtime";
33996
+ import { jsx as jsx71, jsxs as jsxs55 } from "react/jsx-runtime";
34102
33997
  var PrintModeContext = createContext6(null);
34103
33998
  function usePrintMode() {
34104
33999
  const value = useContext6(PrintModeContext);
@@ -34111,8 +34006,8 @@ function usePrintModeOptional() {
34111
34006
  function PrintModeProvider({ rootRef, children }) {
34112
34007
  const { activeView } = useEditorContext();
34113
34008
  const { activeTarget: presentationTarget, stop: stopPresentation } = usePresentationMode();
34114
- const [active, setActive] = useState61(false);
34115
- const [slidesPerPage, setSlidesPerPage] = useState61(1);
34009
+ const [active, setActive] = useState62(false);
34010
+ const [slidesPerPage, setSlidesPerPage] = useState62(1);
34116
34011
  const customPrintHandlerRef = useRef50(null);
34117
34012
  const printAncestorsRef = useRef50([]);
34118
34013
  const unmarkPrinting = useCallback47(() => {
@@ -34163,7 +34058,7 @@ function PrintModeProvider({ rootRef, children }) {
34163
34058
  markPrinting();
34164
34059
  ownerWindow.print();
34165
34060
  }, [markPrinting, rootRef]);
34166
- useEffect51(() => {
34061
+ useEffect52(() => {
34167
34062
  const root = rootRef.current;
34168
34063
  if (!root) return;
34169
34064
  if (active) root.dataset.printPreview = "true";
@@ -34172,10 +34067,10 @@ function PrintModeProvider({ rootRef, children }) {
34172
34067
  delete root.dataset.printPreview;
34173
34068
  };
34174
34069
  }, [active, rootRef]);
34175
- useEffect51(() => {
34070
+ useEffect52(() => {
34176
34071
  if (activeView !== "preview" && active) close();
34177
34072
  }, [active, activeView, close]);
34178
- useEffect51(() => {
34073
+ useEffect52(() => {
34179
34074
  if (!active) return;
34180
34075
  const ownerWindow = rootRef.current?.ownerDocument.defaultView;
34181
34076
  const ownerDocument = rootRef.current?.ownerDocument;
@@ -34197,7 +34092,7 @@ function PrintModeProvider({ rootRef, children }) {
34197
34092
  handleAfterPrint();
34198
34093
  };
34199
34094
  }, [active, close, markPrinting, rootRef, unmarkPrinting]);
34200
- const value = useMemo46(
34095
+ const value = useMemo47(
34201
34096
  () => ({
34202
34097
  active,
34203
34098
  slidesPerPage,
@@ -34209,7 +34104,7 @@ function PrintModeProvider({ rootRef, children }) {
34209
34104
  }),
34210
34105
  [active, close, open, print, registerPrintHandler, slidesPerPage]
34211
34106
  );
34212
- return /* @__PURE__ */ jsx70(PrintModeContext.Provider, { value, children });
34107
+ return /* @__PURE__ */ jsx71(PrintModeContext.Provider, { value, children });
34213
34108
  }
34214
34109
  function PrintModeControl() {
34215
34110
  const { open } = usePrintMode();
@@ -34222,8 +34117,8 @@ function PrintModeControl() {
34222
34117
  "aria-label": "Print",
34223
34118
  "data-tooltip": "Print",
34224
34119
  children: [
34225
- /* @__PURE__ */ jsx70(Icon, { icon: "fa-solid fa-print" }),
34226
- /* @__PURE__ */ jsx70("span", { children: "Print" })
34120
+ /* @__PURE__ */ jsx71(Icon, { icon: "fa-solid fa-print" }),
34121
+ /* @__PURE__ */ jsx71("span", { children: "Print" })
34227
34122
  ]
34228
34123
  }
34229
34124
  );
@@ -34233,8 +34128,8 @@ function PrintPreviewToolbar() {
34233
34128
  const { activeDisplayMode } = usePreviewSettings();
34234
34129
  const { slidesPerPage, setSlidesPerPage, print, close } = usePrintMode();
34235
34130
  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(
34131
+ /* @__PURE__ */ jsx71("span", { className: "squisq-print-toolbar-title", children: "Print preview" }),
34132
+ 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
34133
  "button",
34239
34134
  {
34240
34135
  type: "button",
@@ -34243,7 +34138,7 @@ function PrintPreviewToolbar() {
34243
34138
  "aria-label": `${value} ${value === 1 ? "slide" : "slides"} per page`,
34244
34139
  onClick: () => setSlidesPerPage(value),
34245
34140
  children: [
34246
- /* @__PURE__ */ jsx70("span", { children: value }),
34141
+ /* @__PURE__ */ jsx71("span", { children: value }),
34247
34142
  /* @__PURE__ */ jsxs55("span", { className: "squisq-print-density-label", children: [
34248
34143
  " ",
34249
34144
  value === 1 ? "slide" : "slides",
@@ -34253,20 +34148,20 @@ function PrintPreviewToolbar() {
34253
34148
  },
34254
34149
  value
34255
34150
  )) }),
34256
- /* @__PURE__ */ jsx70("div", { className: "squisq-print-toolbar-spacer" }),
34151
+ /* @__PURE__ */ jsx71("div", { className: "squisq-print-toolbar-spacer" }),
34257
34152
  /* @__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" })
34153
+ /* @__PURE__ */ jsx71(Icon, { icon: "fa-solid fa-print" }),
34154
+ /* @__PURE__ */ jsx71("span", { children: "Print" })
34260
34155
  ] }),
34261
34156
  /* @__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" })
34157
+ /* @__PURE__ */ jsx71(Icon, { icon: "fa-solid fa-xmark" }),
34158
+ /* @__PURE__ */ jsx71("span", { children: "Close" })
34264
34159
  ] })
34265
34160
  ] });
34266
34161
  }
34267
34162
 
34268
34163
  // src/print/PrintPreview.tsx
34269
- import { useCallback as useCallback48, useEffect as useEffect52, useMemo as useMemo47, useRef as useRef51 } from "react";
34164
+ import { useCallback as useCallback48, useEffect as useEffect53, useMemo as useMemo48, useRef as useRef51 } from "react";
34270
34165
  import {
34271
34166
  BlockRenderer as BlockRenderer5,
34272
34167
  LinearDocView,
@@ -34278,7 +34173,7 @@ import {
34278
34173
  } from "@bendyline/squisq/schemas";
34279
34174
  import { expandCoverBlock as expandCoverBlock2 } from "@bendyline/squisq/doc";
34280
34175
  import { resolveTransformStyle } from "@bendyline/squisq/transform";
34281
- import { jsx as jsx71, jsxs as jsxs56 } from "react/jsx-runtime";
34176
+ import { jsx as jsx72, jsxs as jsxs56 } from "react/jsx-runtime";
34282
34177
  function chunk(values, size) {
34283
34178
  const groups = [];
34284
34179
  for (let index2 = 0; index2 < values.length; index2 += size) {
@@ -34305,7 +34200,7 @@ function PrintPreview({
34305
34200
  documentFrameRef.current = frame;
34306
34201
  }, []);
34307
34202
  const { blocks } = useDocPlayback(previewDoc, 0, { viewport, theme });
34308
- const coverBlock = useMemo47(() => {
34203
+ const coverBlock = useMemo48(() => {
34309
34204
  if (!showCover || !previewDoc?.startBlock) return null;
34310
34205
  const context = createTemplateContext2(theme, 0, 1, viewport);
34311
34206
  return {
@@ -34317,7 +34212,7 @@ function PrintPreview({
34317
34212
  };
34318
34213
  }, [previewDoc?.startBlock, showCover, theme, viewport]);
34319
34214
  const isTextDocument = displayMode === "page" || displayMode === "narrate";
34320
- useEffect52(() => {
34215
+ useEffect53(() => {
34321
34216
  if (!isTextDocument) return registerPrintHandler(null);
34322
34217
  return registerPrintHandler(() => {
34323
34218
  const frameWindow = documentFrameRef.current?.contentWindow;
@@ -34327,7 +34222,7 @@ function PrintPreview({
34327
34222
  }, [isTextDocument, registerPrintHandler]);
34328
34223
  const title = contentDoc?.frontmatter?.title ?? contentDoc?.startBlock?.title ?? void 0;
34329
34224
  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(
34225
+ 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
34226
  PlainHtmlPreview,
34332
34227
  {
34333
34228
  markdown: documentMarkdown,
@@ -34341,8 +34236,8 @@ function PrintPreview({
34341
34236
  }
34342
34237
  if (displayMode === "linear") {
34343
34238
  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(
34239
+ /* @__PURE__ */ jsx72("style", { children: "@page { margin: 0; }" }),
34240
+ /* @__PURE__ */ jsx72("div", { className: "squisq-print-page-paper", children: /* @__PURE__ */ jsx72(
34346
34241
  LinearDocView,
34347
34242
  {
34348
34243
  className: "squisq-print-linear",
@@ -34372,14 +34267,14 @@ function PrintPreview({
34372
34267
  "data-slides-per-page": density,
34373
34268
  style: previewStyle,
34374
34269
  children: [
34375
- /* @__PURE__ */ jsx71("style", { children: `@page { size: ${orientation}; margin: 0; }` }),
34376
- sheets.map((sheet, pageIndex) => /* @__PURE__ */ jsx71(
34270
+ /* @__PURE__ */ jsx72("style", { children: `@page { size: ${orientation}; margin: 0; }` }),
34271
+ sheets.map((sheet, pageIndex) => /* @__PURE__ */ jsx72(
34377
34272
  "div",
34378
34273
  {
34379
34274
  className: "squisq-print-sheet",
34380
34275
  "data-slides-per-page": density,
34381
34276
  "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(
34277
+ 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
34278
  BlockRenderer5,
34384
34279
  {
34385
34280
  block,
@@ -34393,14 +34288,14 @@ function PrintPreview({
34393
34288
  },
34394
34289
  `${density}-${pageIndex}`
34395
34290
  )),
34396
- sheets.length === 0 && /* @__PURE__ */ jsx71("p", { className: "squisq-print-empty", children: "Nothing to print." })
34291
+ sheets.length === 0 && /* @__PURE__ */ jsx72("p", { className: "squisq-print-empty", children: "Nothing to print." })
34397
34292
  ]
34398
34293
  }
34399
34294
  );
34400
34295
  }
34401
34296
 
34402
34297
  // src/PreviewPanel.tsx
34403
- import { Fragment as Fragment20, jsx as jsx72, jsxs as jsxs57 } from "react/jsx-runtime";
34298
+ import { Fragment as Fragment20, jsx as jsx73, jsxs as jsxs57 } from "react/jsx-runtime";
34404
34299
  function PreviewPanel({
34405
34300
  basePath = "/",
34406
34301
  className,
@@ -34419,7 +34314,8 @@ function PreviewPanel({
34419
34314
  bumpMediaRevision,
34420
34315
  allowRecording,
34421
34316
  colorScheme,
34422
- fileName
34317
+ fileName,
34318
+ fenceRenderers
34423
34319
  } = useEditorContext();
34424
34320
  const mediaProvider = useMediaProvider2();
34425
34321
  const presentation = usePresentationModeOptional();
@@ -34443,7 +34339,7 @@ function PreviewPanel({
34443
34339
  } = usePreviewSettings();
34444
34340
  const mainSurfaceRef = useRef52(null);
34445
34341
  const popupSurfaceRef = useRef52(null);
34446
- const [playbackState, setPlaybackState] = useState62(null);
34342
+ const [playbackState, setPlaybackState] = useState63(null);
34447
34343
  const handlePlaybackStateChange = useCallback49((next) => {
34448
34344
  setPlaybackState(next);
34449
34345
  }, []);
@@ -34455,7 +34351,7 @@ function PreviewPanel({
34455
34351
  );
34456
34352
  const previewDoc = previewProjection?.playerDoc ?? null;
34457
34353
  const contentDoc = previewProjection?.contentDoc ?? null;
34458
- const followerAudioController = useMemo48(() => {
34354
+ const followerAudioController = useMemo49(() => {
34459
34355
  if (!playbackState || !previewDoc) return null;
34460
34356
  const noOp = () => Promise.resolve();
34461
34357
  return {
@@ -34474,18 +34370,18 @@ function PreviewPanel({
34474
34370
  restart: noOp
34475
34371
  };
34476
34372
  }, [playbackState, previewDoc]);
34477
- const documentMarkdown = useMemo48(
34373
+ const documentMarkdown = useMemo49(
34478
34374
  () => activeTransformStyle && contentDoc ? buildDocumentPreviewMarkdown(contentDoc) : markdownSource,
34479
34375
  [activeTransformStyle, contentDoc, markdownSource]
34480
34376
  );
34481
34377
  const isDocumentMode = activeDisplayMode === "page";
34482
34378
  const isPageMode = activeDisplayMode === "linear";
34483
34379
  const isNarrateMode = activeDisplayMode === "narrate";
34484
- useEffect53(() => {
34380
+ useEffect54(() => {
34485
34381
  if (presentation?.activeTarget === "window") return;
34486
34382
  setPlaybackState(null);
34487
34383
  }, [presentation?.activeTarget]);
34488
- useEffect53(() => {
34384
+ useEffect54(() => {
34489
34385
  if (presentation?.activeTarget !== "window" || !presentation.popupRoot) return;
34490
34386
  const mainRoot = mainSurfaceRef.current;
34491
34387
  const followerRoot = popupSurfaceRef.current;
@@ -34548,22 +34444,22 @@ function PreviewPanel({
34548
34444
  presentation?.popupRoot
34549
34445
  ]);
34550
34446
  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" }) });
34447
+ return /* @__PURE__ */ jsx73("div", { className: `squisq-preview-status ${className || ""}`, "data-testid": "preview-panel", children: /* @__PURE__ */ jsx73("p", { children: "Parsing\u2026" }) });
34552
34448
  }
34553
34449
  if (parseError && !isNarrateMode) {
34554
34450
  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 })
34451
+ /* @__PURE__ */ jsx73("h3", { children: "Parse Error" }),
34452
+ /* @__PURE__ */ jsx73("pre", { children: parseError })
34557
34453
  ] });
34558
34454
  }
34559
34455
  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." }) });
34456
+ 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
34457
  }
34562
34458
  const fillsContainer = printMode?.active || isDocumentMode || isPageMode || isNarrateMode ? "stretch" : "center";
34563
34459
  const audienceWindowOpen = presentation?.activeTarget === "window";
34564
34460
  const renderSurface = (audience) => {
34565
34461
  if (!audience && printMode?.active) {
34566
- return /* @__PURE__ */ jsx72(
34462
+ return /* @__PURE__ */ jsx73(
34567
34463
  PrintPreview,
34568
34464
  {
34569
34465
  displayMode: activeDisplayMode,
@@ -34580,7 +34476,7 @@ function PreviewPanel({
34580
34476
  );
34581
34477
  }
34582
34478
  if (isDocumentMode) {
34583
- return /* @__PURE__ */ jsx72(
34479
+ return /* @__PURE__ */ jsx73(
34584
34480
  PlainHtmlPreview,
34585
34481
  {
34586
34482
  markdown: documentMarkdown,
@@ -34597,7 +34493,7 @@ function PreviewPanel({
34597
34493
  }
34598
34494
  if (isNarrateMode) {
34599
34495
  if (audience) return null;
34600
- return /* @__PURE__ */ jsx72(
34496
+ return /* @__PURE__ */ jsx73(
34601
34497
  TeleprompterView,
34602
34498
  {
34603
34499
  doc,
@@ -34616,7 +34512,7 @@ function PreviewPanel({
34616
34512
  );
34617
34513
  }
34618
34514
  if (isPageMode) {
34619
- return /* @__PURE__ */ jsx72(
34515
+ return /* @__PURE__ */ jsx73(
34620
34516
  LinearDocView2,
34621
34517
  {
34622
34518
  doc: contentDoc ?? doc,
@@ -34627,15 +34523,16 @@ function PreviewPanel({
34627
34523
  showCover: activeCoverSlide,
34628
34524
  transformPage: activeTransformStyle ? resolveTransformStyle2(activeTransformStyle).page : void 0,
34629
34525
  showCodeCopyButton,
34630
- onCopyCode
34526
+ onCopyCode,
34527
+ fenceRenderers: fenceRenderers ?? void 0
34631
34528
  }
34632
34529
  );
34633
34530
  }
34634
34531
  if (audience && !followerAudioController) {
34635
- return /* @__PURE__ */ jsx72("div", { className: "squisq-presentation-connecting", children: "Connecting presentation..." });
34532
+ return /* @__PURE__ */ jsx73("div", { className: "squisq-presentation-connecting", children: "Connecting presentation..." });
34636
34533
  }
34637
34534
  const audienceCaptionMode = playbackState?.captionMode;
34638
- return /* @__PURE__ */ jsx72(
34535
+ return /* @__PURE__ */ jsx73(
34639
34536
  DocPlayer2,
34640
34537
  {
34641
34538
  doc: previewDoc,
@@ -34678,7 +34575,7 @@ function PreviewPanel({
34678
34575
  background: presentation?.activeTarget ? activeTheme.colors.background : void 0
34679
34576
  };
34680
34577
  return /* @__PURE__ */ jsxs57(Fragment20, { children: [
34681
- /* @__PURE__ */ jsx72(
34578
+ /* @__PURE__ */ jsx73(
34682
34579
  "div",
34683
34580
  {
34684
34581
  className: `squisq-preview-container ${className || ""}`,
@@ -34691,16 +34588,16 @@ function PreviewPanel({
34691
34588
  overflow: "hidden",
34692
34589
  background: "var(--squisq-bg, #f5f5f5)"
34693
34590
  },
34694
- children: /* @__PURE__ */ jsx72("div", { ref: mainSurfaceRef, className: "squisq-preview-player", style: surfaceStyle, children: renderSurface(false) })
34591
+ children: /* @__PURE__ */ jsx73("div", { ref: mainSurfaceRef, className: "squisq-preview-player", style: surfaceStyle, children: renderSurface(false) })
34695
34592
  }
34696
34593
  ),
34697
34594
  audienceWindowOpen && presentation?.popupRoot && !isNarrateMode ? createPortal13(
34698
- /* @__PURE__ */ jsx72(
34595
+ /* @__PURE__ */ jsx73(
34699
34596
  "div",
34700
34597
  {
34701
34598
  className: "squisq-editor-shell squisq-presentation-window",
34702
34599
  "data-theme": colorScheme,
34703
- children: /* @__PURE__ */ jsx72("div", { className: "squisq-preview-container squisq-presentation-window-preview", children: /* @__PURE__ */ jsx72(
34600
+ children: /* @__PURE__ */ jsx73("div", { className: "squisq-preview-container squisq-presentation-window-preview", children: /* @__PURE__ */ jsx73(
34704
34601
  "div",
34705
34602
  {
34706
34603
  ref: popupSurfaceRef,
@@ -34718,8 +34615,8 @@ function PreviewPanel({
34718
34615
  }
34719
34616
 
34720
34617
  // 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";
34618
+ import { useState as useState64, useEffect as useEffect55, useRef as useRef53, useCallback as useCallback50 } from "react";
34619
+ import { jsx as jsx74, jsxs as jsxs58 } from "react/jsx-runtime";
34723
34620
  function formatSize(bytes) {
34724
34621
  if (bytes < 1024) return `${bytes} B`;
34725
34622
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -34783,12 +34680,12 @@ function MediaBin({
34783
34680
  isRecorderOpen = false,
34784
34681
  allowBinaryDownloads = true
34785
34682
  }) {
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);
34683
+ const [entries, setEntries] = useState64([]);
34684
+ const [thumbUrls, setThumbUrls] = useState64({});
34685
+ const [loading, setLoading] = useState64(false);
34686
+ const [isDropActive, setIsDropActive] = useState64(false);
34687
+ const [downloadingPath, setDownloadingPath] = useState64(null);
34688
+ const [contextMenu, setContextMenu] = useState64(null);
34792
34689
  const fileInputRef = useRef53(null);
34793
34690
  const contextMenuRef = useRef53(null);
34794
34691
  const dropDepthRef = useRef53(0);
@@ -34810,7 +34707,7 @@ function MediaBin({
34810
34707
  },
34811
34708
  [onCountChange]
34812
34709
  );
34813
- useEffect54(() => {
34710
+ useEffect55(() => {
34814
34711
  if (!contextMenu) return;
34815
34712
  const handlePointerDown = (event) => {
34816
34713
  if (contextMenuRef.current?.contains(event.target)) return;
@@ -34831,7 +34728,7 @@ function MediaBin({
34831
34728
  window.removeEventListener("resize", close);
34832
34729
  };
34833
34730
  }, [contextMenu]);
34834
- useEffect54(() => {
34731
+ useEffect55(() => {
34835
34732
  if (!mediaProvider) {
34836
34733
  setEntries([]);
34837
34734
  setThumbUrls({});
@@ -35036,12 +34933,12 @@ function MediaBin({
35036
34933
  "aria-haspopup": "dialog",
35037
34934
  "aria-expanded": isRecorderOpen,
35038
34935
  children: [
35039
- /* @__PURE__ */ jsx73("span", { className: "squisq-media-bin-record-dot", "aria-hidden": "true" }),
34936
+ /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-record-dot", "aria-hidden": "true" }),
35040
34937
  "Record"
35041
34938
  ]
35042
34939
  }
35043
34940
  ),
35044
- /* @__PURE__ */ jsx73(
34941
+ /* @__PURE__ */ jsx74(
35045
34942
  "button",
35046
34943
  {
35047
34944
  type: "button",
@@ -35057,10 +34954,10 @@ function MediaBin({
35057
34954
  /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-list", children: [
35058
34955
  !mediaProvider && /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-empty", children: [
35059
34956
  "No media context.",
35060
- /* @__PURE__ */ jsx73("br", {}),
34957
+ /* @__PURE__ */ jsx74("br", {}),
35061
34958
  "Load a content zip or select a storage slot."
35062
34959
  ] }),
35063
- mediaProvider && entries.length === 0 && !loading && /* @__PURE__ */ jsx73("div", { className: "squisq-media-bin-empty", children: "No files yet." }),
34960
+ mediaProvider && entries.length === 0 && !loading && /* @__PURE__ */ jsx74("div", { className: "squisq-media-bin-empty", children: "No files yet." }),
35064
34961
  entries.map((entry) => {
35065
34962
  const thumb = thumbUrls[entry.name];
35066
34963
  const basename = basenameForPath(entry.name);
@@ -35092,7 +34989,7 @@ ${formatSize(entry.size)}`,
35092
34989
  onDragStart: handleDragStart,
35093
34990
  onKeyDown: (e2) => handleItemKeyDown(entry, e2),
35094
34991
  children: [
35095
- thumb ? /* @__PURE__ */ jsx73(
34992
+ thumb ? /* @__PURE__ */ jsx74(
35096
34993
  "img",
35097
34994
  {
35098
34995
  src: thumb,
@@ -35100,15 +34997,15 @@ ${formatSize(entry.size)}`,
35100
34997
  className: "squisq-media-bin-thumb",
35101
34998
  draggable: false
35102
34999
  }
35103
- ) : /* @__PURE__ */ jsx73("span", { className: "squisq-media-bin-icon", children: iconForMime(entry.mimeType) }),
35000
+ ) : /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-icon", children: iconForMime(entry.mimeType) }),
35104
35001
  /* @__PURE__ */ jsxs58("div", { className: "squisq-media-bin-meta", children: [
35105
- /* @__PURE__ */ jsx73("div", { className: "squisq-media-bin-name", children: basename }),
35002
+ /* @__PURE__ */ jsx74("div", { className: "squisq-media-bin-name", children: basename }),
35106
35003
  /* @__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" })
35004
+ /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-size", children: formatSize(entry.size) }),
35005
+ isUnused && /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-unused-badge", title: "Not used in document", children: "Unused" })
35109
35006
  ] })
35110
35007
  ] }),
35111
- allowBinaryDownloads && /* @__PURE__ */ jsx73(
35008
+ allowBinaryDownloads && /* @__PURE__ */ jsx74(
35112
35009
  "button",
35113
35010
  {
35114
35011
  type: "button",
@@ -35122,7 +35019,7 @@ ${formatSize(entry.size)}`,
35122
35019
  void handleDownloadEntry(entry);
35123
35020
  },
35124
35021
  onDragStart: (event) => event.preventDefault(),
35125
- children: /* @__PURE__ */ jsx73("span", { "aria-hidden": "true", children: downloadingPath === entry.name ? "\u2026" : "\u2193" })
35022
+ children: /* @__PURE__ */ jsx74("span", { "aria-hidden": "true", children: downloadingPath === entry.name ? "\u2026" : "\u2193" })
35126
35023
  }
35127
35024
  )
35128
35025
  ]
@@ -35132,11 +35029,11 @@ ${formatSize(entry.size)}`,
35132
35029
  })
35133
35030
  ] }),
35134
35031
  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" })
35032
+ /* @__PURE__ */ jsx74("span", { className: "squisq-media-bin-drop-target-icon", children: "+" }),
35033
+ /* @__PURE__ */ jsx74("strong", { children: "Drop images here" }),
35034
+ /* @__PURE__ */ jsx74("span", { children: "Add to Files" })
35138
35035
  ] }),
35139
- contextMenu && /* @__PURE__ */ jsx73(
35036
+ contextMenu && /* @__PURE__ */ jsx74(
35140
35037
  "div",
35141
35038
  {
35142
35039
  ref: contextMenuRef,
@@ -35144,7 +35041,7 @@ ${formatSize(entry.size)}`,
35144
35041
  role: "menu",
35145
35042
  "aria-label": `${contextMenu.entry.name} actions`,
35146
35043
  style: contextMenuStyle,
35147
- children: /* @__PURE__ */ jsx73(
35044
+ children: /* @__PURE__ */ jsx74(
35148
35045
  "button",
35149
35046
  {
35150
35047
  type: "button",
@@ -35157,7 +35054,7 @@ ${formatSize(entry.size)}`,
35157
35054
  )
35158
35055
  }
35159
35056
  ),
35160
- /* @__PURE__ */ jsx73(
35057
+ /* @__PURE__ */ jsx74(
35161
35058
  "input",
35162
35059
  {
35163
35060
  ref: fileInputRef,
@@ -35173,8 +35070,8 @@ ${formatSize(entry.size)}`,
35173
35070
  }
35174
35071
 
35175
35072
  // 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";
35073
+ import { useState as useState65 } from "react";
35074
+ import { Fragment as Fragment21, jsx as jsx75, jsxs as jsxs59 } from "react/jsx-runtime";
35178
35075
  function DropZoneOverlay({
35179
35076
  dragContentType,
35180
35077
  zoneProps,
@@ -35182,8 +35079,8 @@ function DropZoneOverlay({
35182
35079
  }) {
35183
35080
  const showMedia = dragContentType === "media" || dragContentType === "mixed";
35184
35081
  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(
35082
+ return /* @__PURE__ */ jsx75("div", { className: "squisq-drop-overlay", children: /* @__PURE__ */ jsxs59("div", { className: "squisq-drop-overlay-inner", children: [
35083
+ showMedia && /* @__PURE__ */ jsx75(
35187
35084
  DropZone,
35188
35085
  {
35189
35086
  target: "media",
@@ -35196,7 +35093,7 @@ function DropZoneOverlay({
35196
35093
  }
35197
35094
  ),
35198
35095
  showText && /* @__PURE__ */ jsxs59(Fragment21, { children: [
35199
- /* @__PURE__ */ jsx74(
35096
+ /* @__PURE__ */ jsx75(
35200
35097
  DropZone,
35201
35098
  {
35202
35099
  target: "insert",
@@ -35207,7 +35104,7 @@ function DropZoneOverlay({
35207
35104
  variant: "insert"
35208
35105
  }
35209
35106
  ),
35210
- /* @__PURE__ */ jsx74(
35107
+ /* @__PURE__ */ jsx75(
35211
35108
  DropZone,
35212
35109
  {
35213
35110
  target: "replace",
@@ -35230,7 +35127,7 @@ function DropZone({
35230
35127
  disabled,
35231
35128
  variant
35232
35129
  }) {
35233
- const [isHovering, setIsHovering] = useState64(false);
35130
+ const [isHovering, setIsHovering] = useState65(false);
35234
35131
  const props = zoneProps(target);
35235
35132
  return /* @__PURE__ */ jsxs59(
35236
35133
  "div",
@@ -35265,16 +35162,16 @@ function DropZone({
35265
35162
  props.onDrop(e2);
35266
35163
  },
35267
35164
  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 })
35165
+ /* @__PURE__ */ jsx75("span", { className: "squisq-drop-zone-icon", children: icon }),
35166
+ /* @__PURE__ */ jsx75("span", { className: "squisq-drop-zone-label", children: label }),
35167
+ /* @__PURE__ */ jsx75("span", { className: "squisq-drop-zone-desc", children: description })
35271
35168
  ]
35272
35169
  }
35273
35170
  );
35274
35171
  }
35275
35172
 
35276
35173
  // src/Tooltip.tsx
35277
- import { useEffect as useEffect55, useLayoutEffect as useLayoutEffect11, useRef as useRef54, useState as useState65 } from "react";
35174
+ import { useEffect as useEffect56, useLayoutEffect as useLayoutEffect11, useRef as useRef54, useState as useState66 } from "react";
35278
35175
  import { createPortal as createPortal14 } from "react-dom";
35279
35176
 
35280
35177
  // src/tooltipPlacement.ts
@@ -35287,10 +35184,10 @@ function clampTooltipLeft(anchorX, tooltipWidth, viewportWidth, edgePadding = ED
35287
35184
  }
35288
35185
 
35289
35186
  // src/Tooltip.tsx
35290
- import { jsx as jsx75 } from "react/jsx-runtime";
35187
+ import { jsx as jsx76 } from "react/jsx-runtime";
35291
35188
  var SHOW_DELAY_MS = 180;
35292
35189
  function TooltipLayer() {
35293
- const [state, setState3] = useState65(null);
35190
+ const [state, setState3] = useState66(null);
35294
35191
  const tooltipRef = useRef54(null);
35295
35192
  const timerRef = useRef54(null);
35296
35193
  const currentTargetRef = useRef54(null);
@@ -35306,7 +35203,7 @@ function TooltipLayer() {
35306
35203
  node2.style.left = `${left}px`;
35307
35204
  node2.style.visibility = "visible";
35308
35205
  }, [state]);
35309
- useEffect55(() => {
35206
+ useEffect56(() => {
35310
35207
  const clearTimer = () => {
35311
35208
  if (timerRef.current) {
35312
35209
  clearTimeout(timerRef.current);
@@ -35372,7 +35269,7 @@ function TooltipLayer() {
35372
35269
  }, []);
35373
35270
  if (!state) return null;
35374
35271
  return createPortal14(
35375
- /* @__PURE__ */ jsx75(
35272
+ /* @__PURE__ */ jsx76(
35376
35273
  "div",
35377
35274
  {
35378
35275
  role: "tooltip",
@@ -35392,35 +35289,35 @@ function TooltipLayer() {
35392
35289
  }
35393
35290
 
35394
35291
  // src/EditorShell.tsx
35395
- import { useEffect as useEffect56, useRef as useRef55, useState as useState66, useCallback as useCallback51, useMemo as useMemo50 } from "react";
35292
+ import { useEffect as useEffect57, useRef as useRef55, useState as useState67, useCallback as useCallback51, useMemo as useMemo51 } from "react";
35396
35293
 
35397
35294
  // src/BlockPreviewPanel.tsx
35398
- import { useMemo as useMemo49 } from "react";
35295
+ import { useMemo as useMemo50 } from "react";
35399
35296
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS7 } from "@bendyline/squisq/schemas";
35400
35297
  import { flattenBlocks as flattenBlocks7, DEFAULT_THEME as DEFAULT_THEME7 } from "@bendyline/squisq/doc";
35401
- import { jsx as jsx76 } from "react/jsx-runtime";
35298
+ import { jsx as jsx77 } from "react/jsx-runtime";
35402
35299
  function BlockPreviewPanel({ basePath = "/" }) {
35403
35300
  const { doc, activeBlockStartLine, mediaProvider } = useEditorContext();
35404
35301
  const previewSettings = usePreviewSettingsOptional();
35405
35302
  const theme = previewSettings?.activeTheme ?? DEFAULT_THEME7;
35406
35303
  const viewport = previewSettings?.activeViewport ?? VIEWPORT_PRESETS7.landscape;
35407
- const block = useMemo49(() => {
35304
+ const block = useMemo50(() => {
35408
35305
  if (!doc) return null;
35409
35306
  const blocks = flattenBlocks7(doc.blocks);
35410
35307
  if (blocks.length === 0) return null;
35411
35308
  return blocks.find((b) => b.sourceHeading?.position?.start.line === activeBlockStartLine) ?? blocks[0];
35412
35309
  }, [doc, activeBlockStartLine]);
35413
- const visual = useMemo49(
35310
+ const visual = useMemo50(
35414
35311
  () => doc && block ? resolveBlockVisual(doc, block, theme, viewport) : null,
35415
35312
  [doc, block, theme, viewport]
35416
35313
  );
35417
35314
  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(
35315
+ return /* @__PURE__ */ jsx77("div", { className: "squisq-block-preview-panel", "data-testid": "block-preview-panel", "aria-hidden": true, children: /* @__PURE__ */ jsx77(
35419
35316
  "div",
35420
35317
  {
35421
35318
  className: "squisq-block-preview-frame",
35422
35319
  style: { aspectRatio: `${viewport.width} / ${viewport.height}` },
35423
- children: /* @__PURE__ */ jsx76(
35320
+ children: /* @__PURE__ */ jsx77(
35424
35321
  BlockThumbnail,
35425
35322
  {
35426
35323
  visual,
@@ -35674,7 +35571,7 @@ import {
35674
35571
  createMediaProviderFromContainer
35675
35572
  } from "@bendyline/squisq/storage";
35676
35573
  import { MediaContext as MediaContext7, useMediaClipDurations } from "@bendyline/squisq-react";
35677
- import { Fragment as Fragment22, jsx as jsx77, jsxs as jsxs60 } from "react/jsx-runtime";
35574
+ import { Fragment as Fragment22, jsx as jsx78, jsxs as jsxs60 } from "react/jsx-runtime";
35678
35575
  function EditorShell({
35679
35576
  initialMarkdown = "",
35680
35577
  initialView = "wysiwyg",
@@ -35724,6 +35621,7 @@ function EditorShell({
35724
35621
  onFindModeChange,
35725
35622
  mentionProvider,
35726
35623
  documentLinkProvider,
35624
+ fenceRenderers,
35727
35625
  linkSchemes,
35728
35626
  allowRecording = true,
35729
35627
  allowNarrate = true,
@@ -35747,14 +35645,14 @@ function EditorShell({
35747
35645
  themeOverride = null
35748
35646
  }) {
35749
35647
  const effectiveContainer = workspaceContainer ?? null;
35750
- const effectiveMediaProvider = useMemo50(() => {
35648
+ const effectiveMediaProvider = useMemo51(() => {
35751
35649
  if (mediaProvider !== void 0) return mediaProvider;
35752
35650
  if (effectiveContainer) return createMediaProviderFromContainer(effectiveContainer);
35753
35651
  return void 0;
35754
35652
  }, [mediaProvider, effectiveContainer]);
35755
35653
  const filesToggleEnabled = showFilesToggle ?? effectiveMediaProvider !== void 0;
35756
35654
  const effectiveInitialView = hostMode === "chat" || !showPlayTab && initialView === "preview" ? "wysiwyg" : initialView;
35757
- return /* @__PURE__ */ jsx77(MediaContext7.Provider, { value: effectiveMediaProvider ?? null, children: /* @__PURE__ */ jsx77(
35655
+ return /* @__PURE__ */ jsx78(MediaContext7.Provider, { value: effectiveMediaProvider ?? null, children: /* @__PURE__ */ jsx78(
35758
35656
  EditorProvider,
35759
35657
  {
35760
35658
  initialMarkdown,
@@ -35771,6 +35669,7 @@ function EditorShell({
35771
35669
  imageDisplayMode,
35772
35670
  mentionProvider,
35773
35671
  documentLinkProvider,
35672
+ fenceRenderers,
35774
35673
  linkSchemes,
35775
35674
  allowRecording,
35776
35675
  allowNarrate,
@@ -35787,7 +35686,7 @@ function EditorShell({
35787
35686
  themeInheritance,
35788
35687
  viewPreferences,
35789
35688
  onViewPreferencesChange,
35790
- children: /* @__PURE__ */ jsx77(
35689
+ children: /* @__PURE__ */ jsx78(
35791
35690
  EditorShellInner,
35792
35691
  {
35793
35692
  basePath,
@@ -35840,11 +35739,11 @@ function EditorShell({
35840
35739
  }
35841
35740
  function UseModeToolbarControls({ allowPrint }) {
35842
35741
  const printMode = usePrintMode();
35843
- if (printMode.active) return /* @__PURE__ */ jsx77(PrintPreviewToolbar, {});
35742
+ if (printMode.active) return /* @__PURE__ */ jsx78(PrintPreviewToolbar, {});
35844
35743
  return /* @__PURE__ */ jsxs60(Fragment22, { children: [
35845
- /* @__PURE__ */ jsx77(PreviewToolbarControls, {}),
35846
- /* @__PURE__ */ jsx77(PresentationModeControl, {}),
35847
- allowPrint && /* @__PURE__ */ jsx77(PrintModeControl, {})
35744
+ /* @__PURE__ */ jsx78(PreviewToolbarControls, {}),
35745
+ /* @__PURE__ */ jsx78(PresentationModeControl, {}),
35746
+ allowPrint && /* @__PURE__ */ jsx78(PrintModeControl, {})
35848
35747
  ] });
35849
35748
  }
35850
35749
  function UseModeProviders({
@@ -35853,13 +35752,13 @@ function UseModeProviders({
35853
35752
  allowPresentationWindow,
35854
35753
  allowPresentationFullscreen
35855
35754
  }) {
35856
- return /* @__PURE__ */ jsx77(
35755
+ return /* @__PURE__ */ jsx78(
35857
35756
  PresentationModeProvider,
35858
35757
  {
35859
35758
  rootRef,
35860
35759
  allowWindow: allowPresentationWindow,
35861
35760
  allowFullscreen: allowPresentationFullscreen,
35862
- children: /* @__PURE__ */ jsx77(PrintModeProvider, { rootRef, children })
35761
+ children: /* @__PURE__ */ jsx78(PrintModeProvider, { rootRef, children })
35863
35762
  }
35864
35763
  );
35865
35764
  }
@@ -35948,7 +35847,7 @@ function EditorShellInner({
35948
35847
  workspaceContainer
35949
35848
  );
35950
35849
  const timelineDoc = timelineProjection?.contentDoc ?? doc;
35951
- const timelineRawSchedule = useMemo50(
35850
+ const timelineRawSchedule = useMemo51(
35952
35851
  () => timelineDoc ? resolveMediaSchedule4(timelineDoc) : [],
35953
35852
  [timelineDoc]
35954
35853
  );
@@ -35957,19 +35856,19 @@ function EditorShellInner({
35957
35856
  basePath,
35958
35857
  mediaProvider ?? null
35959
35858
  );
35960
- const timelineDuration = useMemo50(
35859
+ const timelineDuration = useMemo51(
35961
35860
  () => timelineDoc ? getDocPlaybackDuration3(timelineDoc, {
35962
35861
  intrinsicDuration: (clip) => timelineClipDurations.get(clip.src)
35963
35862
  }) : 0,
35964
35863
  [timelineDoc, timelineClipDurations]
35965
35864
  );
35966
- const timelineSchedule = useMemo50(
35865
+ const timelineSchedule = useMemo51(
35967
35866
  () => timelineDoc ? resolveMediaSchedule4(timelineDoc, {
35968
35867
  intrinsicDuration: (clip) => timelineClipDurations.get(clip.src)
35969
35868
  }) : [],
35970
35869
  [timelineDoc, timelineClipDurations]
35971
35870
  );
35972
- const timelineVideoSchedule = useMemo50(
35871
+ const timelineVideoSchedule = useMemo51(
35973
35872
  () => timelineDoc ? [
35974
35873
  ...timelineSchedule.filter((clip) => clip.kind === "video"),
35975
35874
  ...collectEmbeddedVideoSchedule(timelineDoc)
@@ -35978,15 +35877,15 @@ function EditorShellInner({
35978
35877
  );
35979
35878
  const timelineClock = useTimelineClock(isTimelineMode ? timelineDuration : 0);
35980
35879
  const hasTimelineVideo = timelineVideoSchedule.length > 0;
35981
- const [timelineVideoVisible, setTimelineVideoVisible] = useState66(false);
35982
- const [timelineCompositionVisible, setTimelineCompositionVisible] = useState66(false);
35880
+ const [timelineVideoVisible, setTimelineVideoVisible] = useState67(false);
35881
+ const [timelineCompositionVisible, setTimelineCompositionVisible] = useState67(false);
35983
35882
  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);
35883
+ const [showFiles, setShowFiles] = useState67(false);
35884
+ const [mediaRefreshKey, setMediaRefreshKey] = useState67(0);
35885
+ const [mediaCount, setMediaCount] = useState67(0);
35886
+ const [mediaBinRecorderOpen, setMediaBinRecorderOpen] = useState67(false);
35988
35887
  const mediaListRefreshKey = mediaRefreshKey + mediaRevision;
35989
- const usedMediaPaths = useMemo50(
35888
+ const usedMediaPaths = useMemo51(
35990
35889
  () => collectMediaReferencesFromMarkdown(markdownSource),
35991
35890
  [markdownSource]
35992
35891
  );
@@ -35996,13 +35895,13 @@ function EditorShellInner({
35996
35895
  }
35997
35896
  const imageEditFallbackContainer = imageEditFallbackContainerRef.current;
35998
35897
  const isDark = colorScheme === "dark";
35999
- useEffect56(() => {
35898
+ useEffect57(() => {
36000
35899
  if (!isTimelineMode || !hasTimelineVideo) setTimelineVideoVisible(false);
36001
35900
  }, [isTimelineMode, hasTimelineVideo]);
36002
- useEffect56(() => {
35901
+ useEffect57(() => {
36003
35902
  if (!isTimelineMode || !doc?.blocks.length) setTimelineCompositionVisible(false);
36004
35903
  }, [isTimelineMode, doc]);
36005
- useEffect56(() => {
35904
+ useEffect57(() => {
36006
35905
  if (!mediaProvider) {
36007
35906
  setMediaCount(0);
36008
35907
  return;
@@ -36111,7 +36010,7 @@ ${snippet}` : snippet);
36111
36010
  onDrop: handleFileDrop,
36112
36011
  enabled: !readOnly
36113
36012
  });
36114
- useEffect56(() => {
36013
+ useEffect57(() => {
36115
36014
  onChange?.(markdownSource);
36116
36015
  }, [markdownSource, onChange]);
36117
36016
  const handleShellKeyDown = useCallback51(
@@ -36199,7 +36098,7 @@ ${snippet}` : snippet);
36199
36098
  },
36200
36099
  ...containerProps,
36201
36100
  children: [
36202
- /* @__PURE__ */ jsx77(CustomThemeProvider, { docThemes, onDocThemesChange, children: /* @__PURE__ */ jsx77(
36101
+ /* @__PURE__ */ jsx78(CustomThemeProvider, { docThemes, onDocThemesChange, children: /* @__PURE__ */ jsx78(
36203
36102
  PreviewSettingsProvider,
36204
36103
  {
36205
36104
  doc,
@@ -36214,16 +36113,16 @@ ${snippet}` : snippet);
36214
36113
  children: [
36215
36114
  isImageMode ? (toolbarSlotLeft || toolbarSlotRight) && /* @__PURE__ */ jsxs60("div", { className: "squisq-editor-header squisq-editor-header--image", children: [
36216
36115
  toolbarSlotLeft,
36217
- /* @__PURE__ */ jsx77("div", { style: { flex: 1 } }),
36116
+ /* @__PURE__ */ jsx78("div", { style: { flex: 1 } }),
36218
36117
  toolbarSlotRight
36219
- ] }) : /* @__PURE__ */ jsx77("div", { className: "squisq-editor-header", children: /* @__PURE__ */ jsx77(
36118
+ ] }) : /* @__PURE__ */ jsx78("div", { className: "squisq-editor-header", children: /* @__PURE__ */ jsx78(
36220
36119
  Toolbar,
36221
36120
  {
36222
36121
  showFiles,
36223
36122
  fileCount: mediaCount,
36224
36123
  onToggleFiles: !isCodeMode && filesToggleEnabled ? handleToggleFiles : void 0,
36225
36124
  slotLeft: toolbarSlotLeft,
36226
- slotAfterTabs: !isCodeMode && isPreview && /* @__PURE__ */ jsx77(UseModeToolbarControls, { allowPrint }),
36125
+ slotAfterTabs: !isCodeMode && isPreview && /* @__PURE__ */ jsx78(UseModeToolbarControls, { allowPrint }),
36227
36126
  slotAfterActions: toolbarSlotAfterActions,
36228
36127
  slotRight: toolbarSlotRight,
36229
36128
  showPlayTab,
@@ -36257,7 +36156,7 @@ ${snippet}` : snippet);
36257
36156
  position: "relative"
36258
36157
  },
36259
36158
  children: [
36260
- isImageMode && imageSrc && (imageMode === "edit" && imageEditorContainer ? /* @__PURE__ */ jsx77(
36159
+ isImageMode && imageSrc && (imageMode === "edit" && imageEditorContainer ? /* @__PURE__ */ jsx78(
36261
36160
  ImageEditor,
36262
36161
  {
36263
36162
  filesContainer: imageEditorContainer,
@@ -36267,10 +36166,10 @@ ${snippet}` : snippet);
36267
36166
  onExport: onImageExport,
36268
36167
  surface: colorScheme === "dark" ? DARK_SURFACE : LIGHT_SURFACE
36269
36168
  }
36270
- ) : /* @__PURE__ */ jsx77(ImageViewer, { src: imageSrc, alt: imageAlt, theme: colorScheme })),
36169
+ ) : /* @__PURE__ */ jsx78(ImageViewer, { src: imageSrc, alt: imageAlt, theme: colorScheme })),
36271
36170
  !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(
36171
+ isMarkdownMode && outlineVisible && /* @__PURE__ */ jsx78(OutlinePanel, { width: outlineWidth, readOnly }, "outline"),
36172
+ /* @__PURE__ */ jsx78(
36274
36173
  BlockCardView,
36275
36174
  {
36276
36175
  active: isCardMode,
@@ -36279,7 +36178,7 @@ ${snippet}` : snippet);
36279
36178
  onPrev: prevBlock,
36280
36179
  onNext: nextBlock,
36281
36180
  onAdd: addBlock,
36282
- children: /* @__PURE__ */ jsx77("div", { className: "squisq-raw-editor-container", children: /* @__PURE__ */ jsx77(
36181
+ children: /* @__PURE__ */ jsx78("div", { className: "squisq-raw-editor-container", children: /* @__PURE__ */ jsx78(
36283
36182
  RawEditor,
36284
36183
  {
36285
36184
  monacoTheme: colorScheme === "dark" ? "vs-dark" : "vs",
@@ -36290,9 +36189,9 @@ ${snippet}` : snippet);
36290
36189
  },
36291
36190
  "raw-frame"
36292
36191
  ),
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(
36192
+ isCodeMode && codeContext && /* @__PURE__ */ jsx78(CodeContextZones, { options: codeContext }, "code-context"),
36193
+ isMarkdownMode && isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(BlockPreviewPanel, { basePath }, "block-preview"),
36194
+ isMarkdownMode && !isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(
36296
36195
  InlinePreviewGutter,
36297
36196
  {
36298
36197
  width: inlinePreviewWidth,
@@ -36303,8 +36202,8 @@ ${snippet}` : snippet);
36303
36202
  )
36304
36203
  ] }, "raw-shell"),
36305
36204
  isMarkdownMode && activeView === "wysiwyg" && /* @__PURE__ */ jsxs60("div", { className: "squisq-editor-with-gutter", children: [
36306
- outlineVisible && /* @__PURE__ */ jsx77(OutlinePanel, { width: outlineWidth, readOnly }, "outline"),
36307
- /* @__PURE__ */ jsx77(
36205
+ outlineVisible && /* @__PURE__ */ jsx78(OutlinePanel, { width: outlineWidth, readOnly }, "outline"),
36206
+ /* @__PURE__ */ jsx78(
36308
36207
  BlockCardView,
36309
36208
  {
36310
36209
  active: isCardMode,
@@ -36313,7 +36212,7 @@ ${snippet}` : snippet);
36313
36212
  onPrev: prevBlock,
36314
36213
  onNext: nextBlock,
36315
36214
  onAdd: addBlock,
36316
- children: /* @__PURE__ */ jsx77(
36215
+ children: /* @__PURE__ */ jsx78(
36317
36216
  WysiwygEditor,
36318
36217
  {
36319
36218
  submitOnEnter,
@@ -36325,8 +36224,8 @@ ${snippet}` : snippet);
36325
36224
  },
36326
36225
  "wysiwyg-frame"
36327
36226
  ),
36328
- isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx77(BlockPreviewPanel, { basePath }, "block-preview"),
36329
- !isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx77(
36227
+ isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(BlockPreviewPanel, { basePath }, "block-preview"),
36228
+ !isCardMode && inlinePreviewVisible && /* @__PURE__ */ jsx78(
36330
36229
  InlinePreviewGutter,
36331
36230
  {
36332
36231
  width: inlinePreviewWidth,
@@ -36336,7 +36235,7 @@ ${snippet}` : snippet);
36336
36235
  "inline"
36337
36236
  )
36338
36237
  ] }, "wysiwyg-shell"),
36339
- isMarkdownMode && isPreview && /* @__PURE__ */ jsx77(
36238
+ isMarkdownMode && isPreview && /* @__PURE__ */ jsx78(
36340
36239
  PreviewPanel,
36341
36240
  {
36342
36241
  basePath,
@@ -36349,7 +36248,7 @@ ${snippet}` : snippet);
36349
36248
  ]
36350
36249
  }
36351
36250
  ),
36352
- isTimelineMode && timelineVideoVisible && /* @__PURE__ */ jsx77(
36251
+ isTimelineMode && timelineVideoVisible && /* @__PURE__ */ jsx78(
36353
36252
  TimelineVideoPanel,
36354
36253
  {
36355
36254
  schedule: timelineVideoSchedule,
@@ -36359,7 +36258,7 @@ ${snippet}` : snippet);
36359
36258
  onClose: () => setTimelineVideoVisible(false)
36360
36259
  }
36361
36260
  ),
36362
- isTimelineMode && timelineCompositionVisible && /* @__PURE__ */ jsx77(
36261
+ isTimelineMode && timelineCompositionVisible && /* @__PURE__ */ jsx78(
36363
36262
  TimelineCompositionPanel,
36364
36263
  {
36365
36264
  doc,
@@ -36369,7 +36268,7 @@ ${snippet}` : snippet);
36369
36268
  onClose: () => setTimelineCompositionVisible(false)
36370
36269
  }
36371
36270
  ),
36372
- isMarkdownMode && showFiles && /* @__PURE__ */ jsx77(
36271
+ isMarkdownMode && showFiles && /* @__PURE__ */ jsx78(
36373
36272
  MediaBin,
36374
36273
  {
36375
36274
  mediaProvider,
@@ -36384,8 +36283,8 @@ ${snippet}` : snippet);
36384
36283
  isRecorderOpen: mediaBinRecorderOpen
36385
36284
  }
36386
36285
  ),
36387
- isMarkdownMode && /* @__PURE__ */ jsx77(ThemeDesignerDock, {}),
36388
- isMarkdownMode && isDragging && !(activeView === "wysiwyg" && dragContentType === "media") && /* @__PURE__ */ jsx77(
36286
+ isMarkdownMode && /* @__PURE__ */ jsx78(ThemeDesignerDock, {}),
36287
+ isMarkdownMode && isDragging && !(activeView === "wysiwyg" && dragContentType === "media") && /* @__PURE__ */ jsx78(
36389
36288
  DropZoneOverlay,
36390
36289
  {
36391
36290
  dragContentType,
@@ -36396,7 +36295,7 @@ ${snippet}` : snippet);
36396
36295
  ]
36397
36296
  }
36398
36297
  ),
36399
- isTimelineMode && /* @__PURE__ */ jsx77(
36298
+ isTimelineMode && /* @__PURE__ */ jsx78(
36400
36299
  TimelineToolbar,
36401
36300
  {
36402
36301
  literalVideoVisible: timelineVideoVisible,
@@ -36407,7 +36306,7 @@ ${snippet}` : snippet);
36407
36306
  onToggleComposition: () => setTimelineCompositionVisible((visible) => !visible)
36408
36307
  }
36409
36308
  ),
36410
- isTimelineMode && /* @__PURE__ */ jsx77(
36309
+ isTimelineMode && /* @__PURE__ */ jsx78(
36411
36310
  TimelineTrack,
36412
36311
  {
36413
36312
  doc: timelineDoc,
@@ -36416,8 +36315,8 @@ ${snippet}` : snippet);
36416
36315
  basePath
36417
36316
  }
36418
36317
  ),
36419
- statusBarVisible && !isImageMode && /* @__PURE__ */ jsx77(StatusBar, { slotRight: statusBarSlotRight }),
36420
- isMarkdownMode && allowRecording && mediaProvider && /* @__PURE__ */ jsx77(
36318
+ statusBarVisible && !isImageMode && /* @__PURE__ */ jsx78(StatusBar, { slotRight: statusBarSlotRight }),
36319
+ isMarkdownMode && allowRecording && mediaProvider && /* @__PURE__ */ jsx78(
36421
36320
  RecorderEntry,
36422
36321
  {
36423
36322
  open: mediaBinRecorderOpen,
@@ -36430,8 +36329,8 @@ ${snippet}` : snippet);
36430
36329
  )
36431
36330
  }
36432
36331
  ) }),
36433
- /* @__PURE__ */ jsx77(TooltipLayer, {}),
36434
- imageEditTarget !== null && mediaProvider && /* @__PURE__ */ jsx77(
36332
+ /* @__PURE__ */ jsx78(TooltipLayer, {}),
36333
+ imageEditTarget !== null && mediaProvider && /* @__PURE__ */ jsx78(
36435
36334
  ImageEditModal,
36436
36335
  {
36437
36336
  relativePath: imageEditTarget,
@@ -36466,7 +36365,7 @@ function ImageEditModal({
36466
36365
  useModalDialog({ rootRef: modalRef, dialogRef: surfaceRef, onClose });
36467
36366
  const extension = relativePath.split(/[?#]/, 1)[0]?.split(".").pop()?.toLowerCase();
36468
36367
  const saveFormat = extension === "png" ? "png" : extension === "jpg" || extension === "jpeg" ? "jpeg" : extension === "webp" ? "webp" : null;
36469
- const sidecar = useMemo50(() => {
36368
+ const sidecar = useMemo51(() => {
36470
36369
  const sanitized = relativePath.replace(/[^a-zA-Z0-9._-]+/g, "_");
36471
36370
  let hash = 2166136261;
36472
36371
  for (let i = 0; i < relativePath.length; i++) {
@@ -36477,9 +36376,9 @@ function ImageEditModal({
36477
36376
  const parent = container ?? new MemoryContentContainer();
36478
36377
  return scopeContainer(parent, `.imageEdits/${scopedName}`);
36479
36378
  }, [container, relativePath]);
36480
- const [initialSrc, setInitialSrc] = useState66(null);
36481
- const [resolveError, setResolveError] = useState66(null);
36482
- useEffect56(() => {
36379
+ const [initialSrc, setInitialSrc] = useState67(null);
36380
+ const [resolveError, setResolveError] = useState67(null);
36381
+ useEffect57(() => {
36483
36382
  let cancelled = false;
36484
36383
  setInitialSrc(null);
36485
36384
  setResolveError(null);
@@ -36509,7 +36408,7 @@ function ImageEditModal({
36509
36408
  },
36510
36409
  [mediaProvider, relativePath, onSaved]
36511
36410
  );
36512
- return /* @__PURE__ */ jsx77(
36411
+ return /* @__PURE__ */ jsx78(
36513
36412
  "div",
36514
36413
  {
36515
36414
  ref: modalRef,
@@ -36523,9 +36422,9 @@ function ImageEditModal({
36523
36422
  },
36524
36423
  children: /* @__PURE__ */ jsxs60("div", { ref: surfaceRef, className: "squisq-image-edit-modal__surface", children: [
36525
36424
  /* @__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(
36425
+ /* @__PURE__ */ jsx78("span", { className: "squisq-image-edit-modal__title", children: "Edit image" }),
36426
+ /* @__PURE__ */ jsx78("span", { className: "squisq-image-edit-modal__path", children: relativePath }),
36427
+ /* @__PURE__ */ jsx78(
36529
36428
  "button",
36530
36429
  {
36531
36430
  type: "button",
@@ -36537,10 +36436,10 @@ function ImageEditModal({
36537
36436
  }
36538
36437
  )
36539
36438
  ] }),
36540
- /* @__PURE__ */ jsx77("div", { className: "squisq-image-edit-modal__body", children: resolveError ? /* @__PURE__ */ jsxs60("div", { className: "squisq-image-edit-modal__error", children: [
36439
+ /* @__PURE__ */ jsx78("div", { className: "squisq-image-edit-modal__body", children: resolveError ? /* @__PURE__ */ jsxs60("div", { className: "squisq-image-edit-modal__error", children: [
36541
36440
  "Failed to load image: ",
36542
36441
  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(
36442
+ ] }) : !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
36443
  ImageEditor,
36545
36444
  {
36546
36445
  filesContainer: sidecar,
@@ -36659,6 +36558,7 @@ export {
36659
36558
  removeNodeOp,
36660
36559
  asciiDiagramToCanvas,
36661
36560
  useAsciiDiagramData,
36561
+ mapFenceEntries,
36662
36562
  REPAIRABLE_KEY,
36663
36563
  isRepairableFence,
36664
36564
  findRepairableBlockPos,
@@ -36667,6 +36567,8 @@ export {
36667
36567
  applyRepairCommand,
36668
36568
  applyAsciiDiagramCommand,
36669
36569
  AsciiDiagramWidget,
36570
+ FENCE_WIDGET_CONTAINED_EVENTS,
36571
+ containFenceWidgetEvents,
36670
36572
  findAsciiDiagramBlockPos,
36671
36573
  isAsciiSourceVisible,
36672
36574
  toggleAsciiSource,
@@ -36698,6 +36600,10 @@ export {
36698
36600
  isCodeSnippetNode,
36699
36601
  findCodeSnippetBlockPos,
36700
36602
  CodeSnippetExtension,
36603
+ HOST_FENCE_KEY,
36604
+ findHostFenceBlockPos,
36605
+ replaceHostFenceText,
36606
+ HostFenceExtension,
36701
36607
  useTreeViewData,
36702
36608
  sanitizeTreeLabel,
36703
36609
  renameItemOp,
@@ -36733,8 +36639,8 @@ export {
36733
36639
  persistFromWrite,
36734
36640
  WysiwygEditor,
36735
36641
  InlinePreviewGutter,
36736
- documentTitleFromFileName,
36737
36642
  buildPreviewDoc,
36643
+ documentTitleFromFileName,
36738
36644
  OutlinePanel,
36739
36645
  CodeContextZones,
36740
36646
  BlockCardView,