@bendyline/squisq-editor-react 2.7.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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";
@@ -22616,8 +22616,71 @@ function mermaidErrorMessage(error) {
22616
22616
  return message || "Unknown Mermaid rendering error.";
22617
22617
  }
22618
22618
 
22619
+ // src/mermaid/mermaidSurfaceTheme.ts
22620
+ import { useEffect as useEffect27, useMemo as useMemo29, useState as useState36 } from "react";
22621
+ import { relativeLuminance } from "@bendyline/squisq/schemas";
22622
+ var EDITOR_SURFACE = {
22623
+ light: {
22624
+ background: "#ffffff",
22625
+ backgroundLight: "#f5f5f5",
22626
+ text: "#1f2937",
22627
+ textMuted: "#6b7280"
22628
+ },
22629
+ dark: {
22630
+ background: "#111827",
22631
+ backgroundLight: "#1f2937",
22632
+ text: "#e5e7eb",
22633
+ textMuted: "#9ca3af"
22634
+ }
22635
+ };
22636
+ function mermaidSurfaceScheme(theme) {
22637
+ return relativeLuminance(theme.colors.background) < 0.5 ? "dark" : "light";
22638
+ }
22639
+ function adaptThemeToSurface(theme, scheme) {
22640
+ return { ...theme, colors: { ...theme.colors, ...EDITOR_SURFACE[scheme] } };
22641
+ }
22642
+ function readHostSurface(host) {
22643
+ const inheritance = host?.closest("[data-theme-inheritance]")?.dataset.themeInheritance;
22644
+ return {
22645
+ scheme: host?.closest("[data-theme]")?.dataset.theme === "dark" ? "dark" : "light",
22646
+ inheritsThemeColors: inheritance === "fonts-colors"
22647
+ };
22648
+ }
22649
+ function applyHostSurface(surface, theme) {
22650
+ return surface.inheritsThemeColors ? theme : adaptThemeToSurface(theme, surface.scheme);
22651
+ }
22652
+ function resolveMermaidSurfaceTheme(host, theme) {
22653
+ return applyHostSurface(readHostSurface(host), theme);
22654
+ }
22655
+ function useMermaidSurfaceTheme(host, theme) {
22656
+ const [surface, setSurface] = useState36(() => readHostSurface(host));
22657
+ useEffect27(() => {
22658
+ const sync = () => setSurface((current) => {
22659
+ const next = readHostSurface(host);
22660
+ return current.scheme === next.scheme && current.inheritsThemeColors === next.inheritsThemeColors ? current : next;
22661
+ });
22662
+ sync();
22663
+ if (typeof MutationObserver === "undefined") return;
22664
+ const observer = new MutationObserver(sync);
22665
+ const ancestors = new Set(
22666
+ [
22667
+ host?.closest("[data-theme]"),
22668
+ host?.closest("[data-theme-inheritance]")
22669
+ ].filter((element) => Boolean(element))
22670
+ );
22671
+ for (const ancestor of ancestors) {
22672
+ observer.observe(ancestor, {
22673
+ attributes: true,
22674
+ attributeFilter: ["data-theme", "data-theme-inheritance"]
22675
+ });
22676
+ }
22677
+ return () => observer.disconnect();
22678
+ }, [host]);
22679
+ return useMemo29(() => applyHostSurface(surface, theme), [surface, theme]);
22680
+ }
22681
+
22619
22682
  // src/mermaid/MermaidDiagramCanvas.tsx
22620
- import { useCallback as useCallback33, useEffect as useEffect27, useId as useId12, useLayoutEffect as useLayoutEffect5, useRef as useRef32, useState as useState36 } from "react";
22683
+ import { useCallback as useCallback33, useEffect as useEffect28, useId as useId12, useLayoutEffect as useLayoutEffect5, useRef as useRef32, useState as useState37 } from "react";
22621
22684
  import { jsx as jsx46, jsxs as jsxs35 } from "react/jsx-runtime";
22622
22685
  var renderSequence = 0;
22623
22686
  function excludesCanvasPan(target, viewport) {
@@ -22681,20 +22744,20 @@ function MermaidDiagramCanvas({
22681
22744
  const renameInputRef = useRef32(null);
22682
22745
  const panDragRef = useRef32(null);
22683
22746
  const renameHintId = useId12();
22684
- const [svg, setSvg] = useState36("");
22685
- const [model2, setModel] = useState36(null);
22686
- const [diagramType, setDiagramType] = useState36("mermaid");
22687
- const [error, setError] = useState36("");
22688
- const [rendering, setRendering] = useState36(true);
22689
- const [zoom, setZoom] = useState36(1);
22690
- const [viewMode, setViewMode] = useState36("fit");
22691
- const [contentSize, setContentSize] = useState36(null);
22692
- const [canvasSize, setCanvasSize] = useState36(null);
22693
- const [pan, setPan] = useState36({ x: 0, y: 0 });
22694
- const [panning, setPanning] = useState36(false);
22695
- const [selectionAnchor, setSelectionAnchor] = useState36(null);
22696
- const [renameValue, setRenameValue] = useState36("");
22697
- useEffect27(() => {
22747
+ const [svg, setSvg] = useState37("");
22748
+ const [model2, setModel] = useState37(null);
22749
+ const [diagramType, setDiagramType] = useState37("mermaid");
22750
+ const [error, setError] = useState37("");
22751
+ const [rendering, setRendering] = useState37(true);
22752
+ const [zoom, setZoom] = useState37(1);
22753
+ const [viewMode, setViewMode] = useState37("fit");
22754
+ const [contentSize, setContentSize] = useState37(null);
22755
+ const [canvasSize, setCanvasSize] = useState37(null);
22756
+ const [pan, setPan] = useState37({ x: 0, y: 0 });
22757
+ const [panning, setPanning] = useState37(false);
22758
+ const [selectionAnchor, setSelectionAnchor] = useState37(null);
22759
+ const [renameValue, setRenameValue] = useState37("");
22760
+ useEffect28(() => {
22698
22761
  if (!panning) return;
22699
22762
  const finish = () => {
22700
22763
  panDragRef.current = null;
@@ -22722,7 +22785,7 @@ function MermaidDiagramCanvas({
22722
22785
  window.removeEventListener("blur", finish);
22723
22786
  };
22724
22787
  }, [panning]);
22725
- useEffect27(() => {
22788
+ useEffect28(() => {
22726
22789
  let current = true;
22727
22790
  const id = `squisq-mermaid-svg-${++renderSequence}`;
22728
22791
  setRendering(true);
@@ -22993,7 +23056,7 @@ function MermaidDiagramCanvas({
22993
23056
  updateSelectionAnchor,
22994
23057
  zoom
22995
23058
  ]);
22996
- useEffect27(() => {
23059
+ useEffect28(() => {
22997
23060
  const scroll = scrollRef.current;
22998
23061
  if (!scroll) return;
22999
23062
  const update = () => updateSelectionAnchor();
@@ -23130,6 +23193,7 @@ function MermaidDiagramCanvas({
23130
23193
  {
23131
23194
  className: "squisq-mermaid-canvas",
23132
23195
  "aria-label": `${diagramType} diagram editor`,
23196
+ "data-surface": mermaidSurfaceScheme(theme),
23133
23197
  style: { background: theme.colors.backgroundLight, color: theme.colors.text },
23134
23198
  children: [
23135
23199
  /* @__PURE__ */ jsx46(
@@ -23397,7 +23461,7 @@ function CanvasAction({
23397
23461
  }
23398
23462
 
23399
23463
  // src/mermaid/MermaidShapePalette.tsx
23400
- import { useEffect as useEffect28, useLayoutEffect as useLayoutEffect6, useMemo as useMemo29, useRef as useRef33, useState as useState37 } from "react";
23464
+ import { useEffect as useEffect29, useLayoutEffect as useLayoutEffect6, useMemo as useMemo30, useRef as useRef33, useState as useState38 } from "react";
23401
23465
  import { jsx as jsx47, jsxs as jsxs36 } from "react/jsx-runtime";
23402
23466
  var CATEGORIES = ["Basic", "Process", "Data", "Documents", "Symbols"];
23403
23467
  var PALETTE_WIDTH = 360;
@@ -23405,10 +23469,10 @@ var PALETTE_MAX_HEIGHT = 520;
23405
23469
  var PALETTE_GAP = 6;
23406
23470
  var VIEWPORT_GUTTER = 8;
23407
23471
  function MermaidShapePalette({ selected, onPick, onClose }) {
23408
- const [query, setQuery] = useState37("");
23409
- const [position, setPosition] = useState37(null);
23472
+ const [query, setQuery] = useState38("");
23473
+ const [position, setPosition] = useState38(null);
23410
23474
  const ref = useRef33(null);
23411
- useEffect28(() => {
23475
+ useEffect29(() => {
23412
23476
  const onPointerDown = (event) => {
23413
23477
  const target = event.target;
23414
23478
  if (target?.closest(".squisq-scene-block-toolbar")) return;
@@ -23424,7 +23488,7 @@ function MermaidShapePalette({ selected, onPick, onClose }) {
23424
23488
  document.removeEventListener("keydown", onKeyDown);
23425
23489
  };
23426
23490
  }, [onClose]);
23427
- const sections = useMemo29(() => {
23491
+ const sections = useMemo30(() => {
23428
23492
  const normalized = query.trim().toLowerCase();
23429
23493
  return CATEGORIES.map((category) => ({
23430
23494
  category,
@@ -23579,7 +23643,7 @@ function MermaidShapeThumb({ shape }) {
23579
23643
  }
23580
23644
 
23581
23645
  // src/mermaid/mermaidData.ts
23582
- import { useEffect as useEffect30, useMemo as useMemo30, useState as useState39 } from "react";
23646
+ import { useEffect as useEffect31, useMemo as useMemo31, useState as useState40 } from "react";
23583
23647
 
23584
23648
  // src/mermaid/MermaidDiagramExtension.ts
23585
23649
  import { Extension as Extension5 } from "@tiptap/core";
@@ -23591,10 +23655,10 @@ import { createRoot as createRoot3 } from "react-dom/client";
23591
23655
  // src/mermaid/MermaidDiagramWidget.tsx
23592
23656
  import {
23593
23657
  useCallback as useCallback34,
23594
- useEffect as useEffect29,
23658
+ useEffect as useEffect30,
23595
23659
  useLayoutEffect as useLayoutEffect7,
23596
23660
  useRef as useRef34,
23597
- useState as useState38,
23661
+ useState as useState39,
23598
23662
  useSyncExternalStore
23599
23663
  } from "react";
23600
23664
 
@@ -23957,21 +24021,22 @@ function MermaidDiagramWidget({
23957
24021
  themeStore
23958
24022
  }) {
23959
24023
  const data = useMermaidDiagramData(editor, blockId);
23960
- const theme = useSyncExternalStore(
24024
+ const docTheme = useSyncExternalStore(
23961
24025
  themeStore?.subscribe ?? subscribeToDefaultTheme,
23962
24026
  themeStore?.getSnapshot ?? getDefaultTheme,
23963
24027
  themeStore?.getSnapshot ?? getDefaultTheme
23964
24028
  );
23965
- const [model2, setModel] = useState38(null);
23966
- const [selection, setSelection] = useState38(null);
23967
- const [renaming, setRenaming] = useState38(null);
23968
- const [connecting, setConnecting] = useState38(false);
23969
- const [connectSourceId, setConnectSourceId] = useState38(null);
23970
- const [openPopover, setOpenPopover] = useState38(null);
23971
- const [editNotice, setEditNotice] = useState38("");
23972
- const [maximized, setMaximized] = useState38(false);
23973
- const [height, setHeight] = useState38(null);
23974
- const [dragHeight, setDragHeight] = useState38(null);
24029
+ const theme = useMermaidSurfaceTheme(host, docTheme);
24030
+ const [model2, setModel] = useState39(null);
24031
+ const [selection, setSelection] = useState39(null);
24032
+ const [renaming, setRenaming] = useState39(null);
24033
+ const [connecting, setConnecting] = useState39(false);
24034
+ const [connectSourceId, setConnectSourceId] = useState39(null);
24035
+ const [openPopover, setOpenPopover] = useState39(null);
24036
+ const [editNotice, setEditNotice] = useState39("");
24037
+ const [maximized, setMaximized] = useState39(false);
24038
+ const [height, setHeight] = useState39(null);
24039
+ const [dragHeight, setDragHeight] = useState39(null);
23975
24040
  const inlineRef = useRef34(null);
23976
24041
  const effectiveHeight = dragHeight ?? height;
23977
24042
  const onModelChange = useCallback34((next) => {
@@ -24230,7 +24295,7 @@ function MermaidDiagramWidget({
24230
24295
  },
24231
24296
  [effectiveHeight]
24232
24297
  );
24233
- useEffect29(() => {
24298
+ useEffect30(() => {
24234
24299
  if (!editNotice) return;
24235
24300
  const timeout = window.setTimeout(() => setEditNotice(""), 7e3);
24236
24301
  return () => window.clearTimeout(timeout);
@@ -24467,7 +24532,7 @@ function MermaidDiagramWidget({
24467
24532
  ] });
24468
24533
  }
24469
24534
  function useDismissibleMermaidPopover(ref, onClose) {
24470
- useEffect29(() => {
24535
+ useEffect30(() => {
24471
24536
  const onPointerDown = (event) => {
24472
24537
  const target = event.target;
24473
24538
  if (target?.closest(".squisq-scene-block-toolbar")) return;
@@ -24485,7 +24550,7 @@ function useDismissibleMermaidPopover(ref, onClose) {
24485
24550
  }, [onClose, ref]);
24486
24551
  }
24487
24552
  function useClampedMermaidPopoverPosition(ref, preferredWidth, preferredMaxHeight) {
24488
- const [position, setPosition] = useState38(null);
24553
+ const [position, setPosition] = useState39(null);
24489
24554
  useLayoutEffect7(() => {
24490
24555
  const picker = ref.current;
24491
24556
  const anchor = picker?.parentElement;
@@ -24551,7 +24616,7 @@ function MermaidPropertiesPalette({
24551
24616
  onApply,
24552
24617
  onClose
24553
24618
  }) {
24554
- const [values, setValues] = useState38(
24619
+ const [values, setValues] = useState39(
24555
24620
  () => Object.fromEntries(properties.map((property) => [property.id, property.value]))
24556
24621
  );
24557
24622
  const ref = useRef34(null);
@@ -24845,15 +24910,15 @@ var MermaidDiagramExtension = Extension5.create({
24845
24910
 
24846
24911
  // src/mermaid/mermaidData.ts
24847
24912
  function useMermaidDiagramData(editor, blockId) {
24848
- const [version, setVersion] = useState39(0);
24849
- useEffect30(() => {
24913
+ const [version, setVersion] = useState40(0);
24914
+ useEffect31(() => {
24850
24915
  const onTransaction = () => setVersion((value) => value + 1);
24851
24916
  editor.on("transaction", onTransaction);
24852
24917
  return () => {
24853
24918
  editor.off("transaction", onTransaction);
24854
24919
  };
24855
24920
  }, [editor]);
24856
- return useMemo30(() => {
24921
+ return useMemo31(() => {
24857
24922
  const pos = findMermaidDiagramBlockPos(editor, blockId);
24858
24923
  if (pos === null) return null;
24859
24924
  const node2 = editor.state.doc.nodeAt(pos);
@@ -24870,20 +24935,20 @@ import { createElement as createElement10 } from "react";
24870
24935
  import { createRoot as createRoot4 } from "react-dom/client";
24871
24936
 
24872
24937
  // src/codeSnippet/CodeSnippetWidget.tsx
24873
- import { useCallback as useCallback35, useEffect as useEffect32, useState as useState41 } from "react";
24938
+ import { useCallback as useCallback35, useEffect as useEffect33, useState as useState42 } from "react";
24874
24939
 
24875
24940
  // src/codeSnippet/codeSnippetData.ts
24876
- import { useEffect as useEffect31, useMemo as useMemo31, useState as useState40 } from "react";
24941
+ import { useEffect as useEffect32, useMemo as useMemo32, useState as useState41 } from "react";
24877
24942
  function useCodeSnippetData(editor, blockId) {
24878
- const [version, setVersion] = useState40(0);
24879
- useEffect31(() => {
24943
+ const [version, setVersion] = useState41(0);
24944
+ useEffect32(() => {
24880
24945
  const onTransaction = () => setVersion((value) => value + 1);
24881
24946
  editor.on("transaction", onTransaction);
24882
24947
  return () => {
24883
24948
  editor.off("transaction", onTransaction);
24884
24949
  };
24885
24950
  }, [editor]);
24886
- return useMemo31(() => {
24951
+ return useMemo32(() => {
24887
24952
  const pos = findCodeSnippetBlockPos(editor, blockId);
24888
24953
  if (pos === null) return null;
24889
24954
  const node2 = editor.state.doc.nodeAt(pos);
@@ -24921,8 +24986,17 @@ function schemeFromHost(host) {
24921
24986
  return host?.closest("[data-theme]")?.dataset.theme === "dark" ? "dark" : "light";
24922
24987
  }
24923
24988
  function useHostColorScheme(host) {
24924
- const [scheme, setScheme] = useState41(() => schemeFromHost(host));
24925
- useEffect32(() => {
24989
+ const [scheme, setScheme] = useState42(
24990
+ () => host != null && !host.isConnected ? null : schemeFromHost(host)
24991
+ );
24992
+ useEffect33(() => {
24993
+ if (host != null && !host.isConnected) {
24994
+ setScheme(null);
24995
+ const raf = requestAnimationFrame(() => {
24996
+ if (host.isConnected) setScheme(schemeFromHost(host));
24997
+ });
24998
+ return () => cancelAnimationFrame(raf);
24999
+ }
24926
25000
  const themedAncestor = host?.closest("[data-theme]");
24927
25001
  setScheme(schemeFromHost(host));
24928
25002
  if (!themedAncestor || typeof MutationObserver === "undefined") return;
@@ -24933,8 +25007,8 @@ function useHostColorScheme(host) {
24933
25007
  return scheme;
24934
25008
  }
24935
25009
  function useEditorEditable(editor) {
24936
- const [editable, setEditable] = useState41(editor.isEditable);
24937
- useEffect32(() => {
25010
+ const [editable, setEditable] = useState42(editor.isEditable);
25011
+ useEffect33(() => {
24938
25012
  const sync = () => setEditable(editor.isEditable);
24939
25013
  editor.on("update", sync);
24940
25014
  editor.on("transaction", sync);
@@ -24955,7 +25029,7 @@ function CodeSnippetWidget({
24955
25029
  const { ready } = useMonacoLoader(data?.monacoLanguage);
24956
25030
  const colorScheme = useHostColorScheme(host);
24957
25031
  const editable = useEditorEditable(editor);
24958
- const [modelInstanceId] = useState41(allocateCodeSnippetModelInstanceId);
25032
+ const [modelInstanceId] = useState42(allocateCodeSnippetModelInstanceId);
24959
25033
  const handleChange = useCallback35(
24960
25034
  (value) => {
24961
25035
  if (!editable) return;
@@ -24985,7 +25059,7 @@ function CodeSnippetWidget({
24985
25059
  /* @__PURE__ */ jsx49(Icon, { icon: "fa-solid fa-file-code" }),
24986
25060
  /* @__PURE__ */ jsx49("span", { children: data.label })
24987
25061
  ] }) }),
24988
- /* @__PURE__ */ jsx49("div", { className: "squisq-code-snippet-editor", "aria-label": `${data.label} code editor`, children: ready ? /* @__PURE__ */ jsx49(
25062
+ /* @__PURE__ */ jsx49("div", { className: "squisq-code-snippet-editor", "aria-label": `${data.label} code editor`, children: ready && colorScheme !== null ? /* @__PURE__ */ jsx49(
24989
25063
  Ft,
24990
25064
  {
24991
25065
  path: `inmemory://squisq/code-snippet/${modelInstanceId}/${blockId}.${modelSuffix || "txt"}`,
@@ -25170,27 +25244,16 @@ function replaceCodeSnippetText(editor, blockId, nextText) {
25170
25244
  return true;
25171
25245
  }
25172
25246
 
25173
- // src/fenceWidgets/HostFenceExtension.tsx
25247
+ // src/fenceWidgets/HostFenceExtension.ts
25174
25248
  import { Extension as Extension7 } from "@tiptap/core";
25175
25249
  import { Plugin as Plugin7, PluginKey as PluginKey7 } from "@tiptap/pm/state";
25176
25250
  import { Decoration as Decoration7, DecorationSet as DecorationSet7 } from "@tiptap/pm/view";
25177
25251
  import { createRoot as createRoot5 } from "react-dom/client";
25178
- import { Component, createElement as createElement11, useEffect as useEffect33, useMemo as useMemo32, useState as useState42 } from "react";
25252
+ import { createElement as createElement11 } from "react";
25253
+
25254
+ // src/fenceWidgets/HostFenceWidget.tsx
25255
+ import { Component, useEffect as useEffect34, useMemo as useMemo33, useState as useState43 } from "react";
25179
25256
  import { jsx as jsx50 } from "react/jsx-runtime";
25180
- var HOST_FENCE_KEY = new PluginKey7("squisq-host-fence");
25181
- function fenceLangToken(node2) {
25182
- const lang = node2.attrs.language;
25183
- if (typeof lang !== "string") return "";
25184
- return lang.trim().split(/\s+/, 1)[0]?.toLowerCase() ?? "";
25185
- }
25186
- function findHostFenceBlockPos(editor, blockId) {
25187
- return HOST_FENCE_KEY.getState(editor.state)?.entries.find((e2) => e2.id === blockId)?.pos ?? null;
25188
- }
25189
- function replaceHostFenceText(editor, blockId, next) {
25190
- const pos = findHostFenceBlockPos(editor, blockId);
25191
- if (pos === null) return false;
25192
- return replaceAsciiFenceText(editor, pos, next);
25193
- }
25194
25257
  var HostFenceErrorBoundary = class extends Component {
25195
25258
  constructor() {
25196
25259
  super(...arguments);
@@ -25203,21 +25266,16 @@ var HostFenceErrorBoundary = class extends Component {
25203
25266
  return this.state.failed ? this.props.fallback : this.props.children;
25204
25267
  }
25205
25268
  };
25206
- function HostFenceWidget({
25207
- editor,
25208
- blockId,
25209
- getRenderers,
25210
- getTheme
25211
- }) {
25212
- const [version, setVersion] = useState42(0);
25213
- useEffect33(() => {
25269
+ function HostFenceWidget({ editor, blockId, getRenderers, getTheme }) {
25270
+ const [version, setVersion] = useState43(0);
25271
+ useEffect34(() => {
25214
25272
  const onUpdate = () => setVersion((v2) => v2 + 1);
25215
25273
  editor.on("transaction", onUpdate);
25216
25274
  return () => {
25217
25275
  editor.off("transaction", onUpdate);
25218
25276
  };
25219
25277
  }, [editor]);
25220
- const current = useMemo32(() => {
25278
+ const current = useMemo33(() => {
25221
25279
  const pos = findHostFenceBlockPos(editor, blockId);
25222
25280
  if (pos === null) return null;
25223
25281
  const node2 = editor.state.doc.nodeAt(pos);
@@ -25239,6 +25297,22 @@ function HostFenceWidget({
25239
25297
  }
25240
25298
  }) });
25241
25299
  }
25300
+
25301
+ // src/fenceWidgets/HostFenceExtension.ts
25302
+ var HOST_FENCE_KEY = new PluginKey7("squisq-host-fence");
25303
+ function fenceLangToken(node2) {
25304
+ const lang = node2.attrs.language;
25305
+ if (typeof lang !== "string") return "";
25306
+ return lang.trim().split(/\s+/, 1)[0]?.toLowerCase() ?? "";
25307
+ }
25308
+ function findHostFenceBlockPos(editor, blockId) {
25309
+ return HOST_FENCE_KEY.getState(editor.state)?.entries.find((e2) => e2.id === blockId)?.pos ?? null;
25310
+ }
25311
+ function replaceHostFenceText(editor, blockId, next) {
25312
+ const pos = findHostFenceBlockPos(editor, blockId);
25313
+ if (pos === null) return false;
25314
+ return replaceAsciiFenceText(editor, pos, next);
25315
+ }
25242
25316
  function buildDecorations6(doc, entries, editor, options) {
25243
25317
  const decos = [];
25244
25318
  for (const entry of entries) {
@@ -25344,7 +25418,7 @@ var HostFenceExtension = Extension7.create({
25344
25418
  });
25345
25419
 
25346
25420
  // src/treeview/treeViewData.ts
25347
- import { useEffect as useEffect34, useMemo as useMemo33, useState as useState44 } from "react";
25421
+ import { useEffect as useEffect35, useMemo as useMemo34, useState as useState45 } from "react";
25348
25422
 
25349
25423
  // src/treeview/TreeViewExtension.ts
25350
25424
  import { Extension as Extension8 } from "@tiptap/core";
@@ -25361,7 +25435,7 @@ import {
25361
25435
  } from "@bendyline/squisq/doc";
25362
25436
 
25363
25437
  // src/treeview/TreeOutlineWidget.tsx
25364
- import { useCallback as useCallback36, useRef as useRef35, useState as useState43 } from "react";
25438
+ import { useCallback as useCallback36, useRef as useRef35, useState as useState44 } from "react";
25365
25439
 
25366
25440
  // src/treeview/treeViewCommands.ts
25367
25441
  import { parseTree, renderTree } from "@bendyline/squisq/doc";
@@ -25598,10 +25672,10 @@ function dropPositionForPointer(event) {
25598
25672
  }
25599
25673
  function TreeOutlineWidget({ editor, blockId }) {
25600
25674
  const view = useTreeViewData(editor, blockId);
25601
- const [collapsed, setCollapsed] = useState43(() => /* @__PURE__ */ new Set());
25675
+ const [collapsed, setCollapsed] = useState44(() => /* @__PURE__ */ new Set());
25602
25676
  const activeDragRef = useRef35(null);
25603
- const [draggedId, setDraggedId] = useState43(null);
25604
- const [dropTarget, setDropTarget] = useState43(null);
25677
+ const [draggedId, setDraggedId] = useState44(null);
25678
+ const [dropTarget, setDropTarget] = useState44(null);
25605
25679
  const dispatch = useCallback36(
25606
25680
  (cmd) => applyTreeCommand(editor, blockId, cmd),
25607
25681
  [editor, blockId]
@@ -25748,7 +25822,7 @@ function TreeRowView({
25748
25822
  const hasChildren = node2.children.length > 0;
25749
25823
  const isCollapsed = collapsed.has(node2.id);
25750
25824
  const isDir = node2.isDir || hasChildren;
25751
- const [draft, setDraft] = useState43(node2.label);
25825
+ const [draft, setDraft] = useState44(node2.label);
25752
25826
  const dropPosition = dropTarget?.id === node2.id ? dropTarget.position : null;
25753
25827
  const itemClassName = [
25754
25828
  "squisq-tree-item",
@@ -26052,15 +26126,15 @@ var TreeViewExtension = Extension8.create({
26052
26126
 
26053
26127
  // src/treeview/treeViewData.ts
26054
26128
  function useTreeViewData(editor, blockId) {
26055
- const [version, setVersion] = useState44(0);
26056
- useEffect34(() => {
26129
+ const [version, setVersion] = useState45(0);
26130
+ useEffect35(() => {
26057
26131
  const onUpdate = () => setVersion((v2) => v2 + 1);
26058
26132
  editor.on("transaction", onUpdate);
26059
26133
  return () => {
26060
26134
  editor.off("transaction", onUpdate);
26061
26135
  };
26062
26136
  }, [editor]);
26063
- return useMemo33(() => {
26137
+ return useMemo34(() => {
26064
26138
  const pos = findTreeBlockPos(editor, blockId);
26065
26139
  if (pos === null) return null;
26066
26140
  const node2 = editor.state.doc.nodeAt(pos);
@@ -26079,7 +26153,7 @@ function shouldPasteAsTreeFence(text) {
26079
26153
  }
26080
26154
 
26081
26155
  // src/timeline/timelineData.ts
26082
- import { useEffect as useEffect36, useMemo as useMemo35, useRef as useRef37, useState as useState46 } from "react";
26156
+ import { useEffect as useEffect37, useMemo as useMemo36, useRef as useRef37, useState as useState47 } from "react";
26083
26157
 
26084
26158
  // src/timeline/TimelineViewExtension.ts
26085
26159
  import { Extension as Extension9 } from "@tiptap/core";
@@ -26094,7 +26168,7 @@ import {
26094
26168
  } from "@bendyline/squisq/doc";
26095
26169
 
26096
26170
  // src/timeline/TimelineEditorWidget.tsx
26097
- import { useCallback as useCallback37, useEffect as useEffect35, useMemo as useMemo34, useRef as useRef36, useState as useState45 } from "react";
26171
+ import { useCallback as useCallback37, useEffect as useEffect36, useMemo as useMemo35, useRef as useRef36, useState as useState46 } from "react";
26098
26172
  import {
26099
26173
  asciiTimelineToTemplateData
26100
26174
  } from "@bendyline/squisq/doc";
@@ -26578,13 +26652,13 @@ import { Fragment as Fragment15, jsx as jsx52, jsxs as jsxs40 } from "react/jsx-
26578
26652
  var clamp01 = (value) => Math.max(0, Math.min(1, value));
26579
26653
  function TimelineEditorWidget({ editor, blockId }) {
26580
26654
  const view = useTimelineData(editor, blockId);
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);
26655
+ const [selectedEventId, setSelectedEventId] = useState46(null);
26656
+ const [addingTrackId, setAddingTrackId] = useState46(null);
26657
+ const [editingTrackId, setEditingTrackId] = useState46(null);
26658
+ const [hover, setHover] = useState46(null);
26659
+ const [dragged, setDragged] = useState46(null);
26586
26660
  const suppressClickEventId = useRef36(null);
26587
- const [announcement, setAnnouncement] = useState45("");
26661
+ const [announcement, setAnnouncement] = useState46("");
26588
26662
  const dispatch = useCallback37(
26589
26663
  (command) => {
26590
26664
  const result = applyTimelineCommand(editor, blockId, command);
@@ -26598,7 +26672,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26598
26672
  );
26599
26673
  const sourceText2 = view?.text;
26600
26674
  const sourceTimeline = view?.timeline;
26601
- const sourceSafe = useMemo34(
26675
+ const sourceSafe = useMemo35(
26602
26676
  () => sourceText2 && sourceTimeline ? isTimelineSourceSafeForSemanticEdit(sourceText2, sourceTimeline) : false,
26603
26677
  // `useTimelineData` publishes on every editor transaction so read-only
26604
26678
  // changes are observed. Unrelated transactions retain both primitive/model
@@ -26608,7 +26682,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26608
26682
  );
26609
26683
  const editorEditable = editor.isEditable;
26610
26684
  const editable = editorEditable && sourceSafe;
26611
- const positioned = useMemo34(() => {
26685
+ const positioned = useMemo35(() => {
26612
26686
  if (!view) return [];
26613
26687
  const normalized = asciiTimelineToTemplateData(view.timeline).tracks;
26614
26688
  return view.timeline.tracks.flatMap((track, trackIndex) => {
@@ -26623,17 +26697,17 @@ function TimelineEditorWidget({ editor, blockId }) {
26623
26697
  );
26624
26698
  });
26625
26699
  }, [view]);
26626
- const displayedPositioned = useMemo34(
26700
+ const displayedPositioned = useMemo35(
26627
26701
  () => dragged ? positioned.map(
26628
26702
  (point) => point.event.id === dragged.eventId ? { ...point, position: dragged.position } : point
26629
26703
  ) : positioned,
26630
26704
  [dragged, positioned]
26631
26705
  );
26632
- const positionById = useMemo34(
26706
+ const positionById = useMemo35(
26633
26707
  () => new Map(displayedPositioned.map((point) => [point.event.id, point.position])),
26634
26708
  [displayedPositioned]
26635
26709
  );
26636
- const selected = useMemo34(() => {
26710
+ const selected = useMemo35(() => {
26637
26711
  if (!view || !selectedEventId) return null;
26638
26712
  for (const track of view.timeline.tracks) {
26639
26713
  const event = track.events.find((candidate) => candidate.id === selectedEventId);
@@ -26647,7 +26721,7 @@ function TimelineEditorWidget({ editor, blockId }) {
26647
26721
  }
26648
26722
  return null;
26649
26723
  }, [selectedEventId, view]);
26650
- useEffect35(() => {
26724
+ useEffect36(() => {
26651
26725
  if (!view) return;
26652
26726
  const ids = new Set(
26653
26727
  view.timeline.tracks.flatMap((track) => track.events.map((event) => event.id))
@@ -26655,13 +26729,13 @@ function TimelineEditorWidget({ editor, blockId }) {
26655
26729
  if (selectedEventId && ids.has(selectedEventId)) return;
26656
26730
  setSelectedEventId(view.timeline.tracks[0]?.events[0]?.id ?? null);
26657
26731
  }, [selectedEventId, view]);
26658
- useEffect35(() => {
26732
+ useEffect36(() => {
26659
26733
  if (editable) return;
26660
26734
  setAddingTrackId(null);
26661
26735
  setEditingTrackId(null);
26662
26736
  setHover(null);
26663
26737
  }, [editable]);
26664
- useEffect35(() => {
26738
+ useEffect36(() => {
26665
26739
  if (!editingTrackId || view?.timeline.tracks.some((track) => track.id === editingTrackId)) {
26666
26740
  return;
26667
26741
  }
@@ -27067,8 +27141,8 @@ function InlineTrackLabel({
27067
27141
  onStart,
27068
27142
  onFinish
27069
27143
  }) {
27070
- const [draft, setDraft] = useState45(label);
27071
- useEffect35(() => {
27144
+ const [draft, setDraft] = useState46(label);
27145
+ useEffect36(() => {
27072
27146
  if (editing) setDraft(label);
27073
27147
  }, [editing, label]);
27074
27148
  const commitLabel = () => {
@@ -27125,10 +27199,10 @@ function EventInspector({
27125
27199
  onDelete
27126
27200
  }) {
27127
27201
  const { event } = selected;
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]);
27202
+ const [label, setLabel] = useState46(event.label);
27203
+ const [description, setDescription] = useState46(event.description ?? "");
27204
+ useEffect36(() => setLabel(event.label), [event.label]);
27205
+ useEffect36(() => setDescription(event.description ?? ""), [event.description]);
27132
27206
  const update = (patch) => dispatch(patch);
27133
27207
  const commitLabel = () => {
27134
27208
  const next = label.trim();
@@ -27433,9 +27507,9 @@ var TimelineViewExtension = Extension9.create({
27433
27507
 
27434
27508
  // src/timeline/timelineData.ts
27435
27509
  function useTimelineData(editor, blockId) {
27436
- const [version, setVersion] = useState46(0);
27510
+ const [version, setVersion] = useState47(0);
27437
27511
  const dataCache = useRef37(null);
27438
- useEffect36(() => {
27512
+ useEffect37(() => {
27439
27513
  const onEditorChange = () => setVersion((value) => value + 1);
27440
27514
  editor.on("transaction", onEditorChange);
27441
27515
  editor.on("update", onEditorChange);
@@ -27444,7 +27518,7 @@ function useTimelineData(editor, blockId) {
27444
27518
  editor.off("update", onEditorChange);
27445
27519
  };
27446
27520
  }, [editor]);
27447
- return useMemo35(() => {
27521
+ return useMemo36(() => {
27448
27522
  const pos = findTimelineBlockPos(editor, blockId);
27449
27523
  if (pos === null) return null;
27450
27524
  const node2 = editor.state.doc.nodeAt(pos);
@@ -27470,7 +27544,7 @@ function shouldPasteAsTimelineFence(text) {
27470
27544
  }
27471
27545
 
27472
27546
  // src/BlockPropertiesPopover.tsx
27473
- import { useEffect as useEffect37, useId as useId13, useRef as useRef38, useState as useState47 } from "react";
27547
+ import { useEffect as useEffect38, useId as useId13, useRef as useRef38, useState as useState48 } from "react";
27474
27548
  import { createPortal as createPortal9 } from "react-dom";
27475
27549
  import { jsx as jsx53, jsxs as jsxs41 } from "react/jsx-runtime";
27476
27550
  var TRANSITION_FLYOUT = ".squisq-transition-flyout";
@@ -27486,13 +27560,13 @@ function BlockPropertiesPopover({
27486
27560
  }) {
27487
27561
  const panelRef = useRef38(null);
27488
27562
  const panelId = `squisq-block-props-portal-${useId13().replace(/:/g, "")}`;
27489
- const [inner, setInner] = useState47(blockAttrs);
27490
- const [templateInner, setTemplateInner] = useState47(templateParams);
27491
- const [style, setStyle] = useState47(() => computeStyle(anchorRect));
27492
- useEffect37(() => {
27563
+ const [inner, setInner] = useState48(blockAttrs);
27564
+ const [templateInner, setTemplateInner] = useState48(templateParams);
27565
+ const [style, setStyle] = useState48(() => computeStyle(anchorRect));
27566
+ useEffect38(() => {
27493
27567
  requestAnimationFrame(() => setStyle(computeStyle(anchorRect, panelRef.current)));
27494
27568
  }, [anchorRect]);
27495
- useEffect37(() => {
27569
+ useEffect38(() => {
27496
27570
  const onKey = (e2) => {
27497
27571
  if (e2.key === "Escape") onClose();
27498
27572
  };
@@ -27654,7 +27728,7 @@ function persistFromWrite(bodyMd, state) {
27654
27728
  }
27655
27729
 
27656
27730
  // src/WysiwygEditor.tsx
27657
- import { useCallback as useCallback38, useEffect as useEffect41, useMemo as useMemo36, useRef as useRef40, useState as useState51 } from "react";
27731
+ import { useCallback as useCallback38, useEffect as useEffect42, useMemo as useMemo37, useRef as useRef40, useState as useState52 } from "react";
27658
27732
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
27659
27733
  import { Selection } from "@tiptap/pm/state";
27660
27734
  import StarterKit2 from "@tiptap/starter-kit";
@@ -27890,7 +27964,7 @@ var InlineIcon = Node2.create({
27890
27964
  });
27891
27965
 
27892
27966
  // src/ImageNodeView.tsx
27893
- import { useEffect as useEffect38, useRef as useRef39, useState as useState48 } from "react";
27967
+ import { useEffect as useEffect39, useRef as useRef39, useState as useState49 } from "react";
27894
27968
  import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
27895
27969
  import Image from "@tiptap/extension-image";
27896
27970
 
@@ -27910,16 +27984,16 @@ import { Fragment as Fragment16, jsx as jsx54, jsxs as jsxs42 } from "react/jsx-
27910
27984
  function ImageComponent({ node: node2, selected, editor, updateAttributes }) {
27911
27985
  const { src, alt, title, width } = node2.attrs;
27912
27986
  const { mediaProvider, imageDisplayMode, openImageEdit, mediaRevision } = useEditorContext();
27913
- const [resolvedSrc, setResolvedSrc] = useState48(src);
27914
- const [hovered, setHovered] = useState48(false);
27987
+ const [resolvedSrc, setResolvedSrc] = useState49(src);
27988
+ const [hovered, setHovered] = useState49(false);
27915
27989
  const imgRef = useRef39(null);
27916
- const [previewWidth, setPreviewWidth] = useState48(null);
27990
+ const [previewWidth, setPreviewWidth] = useState49(null);
27917
27991
  const isThumbnail = imageDisplayMode === "thumbnail";
27918
27992
  const isEditable = editor?.isEditable ?? true;
27919
27993
  const normalizedRelativePath = normalizeMalformedAssetUrl(src);
27920
27994
  const isRelative = src && !src.startsWith("blob:") && !src.startsWith("http") && !src.startsWith("data:") && !src.startsWith("/");
27921
27995
  const resolveAs = normalizedRelativePath ?? (isRelative ? src : null);
27922
- useEffect38(() => {
27996
+ useEffect39(() => {
27923
27997
  if (!mediaProvider || !resolveAs) {
27924
27998
  setResolvedSrc(src);
27925
27999
  return;
@@ -28098,15 +28172,15 @@ var ImageWithMediaProvider = Image.extend({
28098
28172
  // src/tiptap/TiptapVideo.tsx
28099
28173
  import { Node as Node3, mergeAttributes as mergeAttributes2 } from "@tiptap/core";
28100
28174
  import { NodeViewWrapper as NodeViewWrapper2, ReactNodeViewRenderer as ReactNodeViewRenderer2 } from "@tiptap/react";
28101
- import { useEffect as useEffect40, useState as useState50 } from "react";
28175
+ import { useEffect as useEffect41, useState as useState51 } from "react";
28102
28176
 
28103
28177
  // src/tiptap/useResolvedMediaSrc.ts
28104
- import { useEffect as useEffect39, useState as useState49 } from "react";
28178
+ import { useEffect as useEffect40, useState as useState50 } from "react";
28105
28179
  function useResolvedMediaSrc(src) {
28106
28180
  const { mediaProvider, mediaRevision } = useEditorContext();
28107
- const [resolved, setResolved] = useState49(src);
28181
+ const [resolved, setResolved] = useState50(src);
28108
28182
  const isRelative = !!src && !src.startsWith("blob:") && !src.startsWith("http:") && !src.startsWith("https:") && !src.startsWith("data:") && !src.startsWith("/");
28109
- useEffect39(() => {
28183
+ useEffect40(() => {
28110
28184
  if (!mediaProvider || !isRelative) {
28111
28185
  setResolved(src);
28112
28186
  return;
@@ -28157,9 +28231,9 @@ function VideoNodeView({ node: node2, updateAttributes, selected }) {
28157
28231
  const placement = normalizeVideoPlacement(rawPlacement);
28158
28232
  const lockToBlock = normalizeLockToBlock(rawLockToBlock);
28159
28233
  const resolvedSrc = useResolvedMediaSrc(src ?? "");
28160
- const [audioOnly, setAudioOnly] = useState50(false);
28234
+ const [audioOnly, setAudioOnly] = useState51(false);
28161
28235
  const resolvedPoster = useResolvedMediaSrc(poster ?? "");
28162
- useEffect40(() => {
28236
+ useEffect41(() => {
28163
28237
  setAudioOnly(false);
28164
28238
  }, [resolvedSrc]);
28165
28239
  const handleLoadedMetadata = (event) => {
@@ -28826,11 +28900,11 @@ function WysiwygEditor({
28826
28900
  mermaidThemeStoreRef.current = createMermaidThemeStore(activeTheme ?? DEFAULT_THEME4);
28827
28901
  }
28828
28902
  const mermaidThemeStore = mermaidThemeStoreRef.current;
28829
- useEffect41(() => {
28903
+ useEffect42(() => {
28830
28904
  mermaidThemeStore.setTheme(activeTheme ?? DEFAULT_THEME4);
28831
28905
  }, [activeTheme, mermaidThemeStore]);
28832
28906
  const { docTemplates, onDocTemplatesChange } = useDocCustomTemplates();
28833
- const [designerState, setDesignerState] = useState51(
28907
+ const [designerState, setDesignerState] = useState52(
28834
28908
  null
28835
28909
  );
28836
28910
  const handleDesignerSave = useCallback38(
@@ -28846,23 +28920,23 @@ function WysiwygEditor({
28846
28920
  [docTemplates, onDocTemplatesChange]
28847
28921
  );
28848
28922
  const mentionProviderRef = useRef40(mentionProvider);
28849
- useEffect41(() => {
28923
+ useEffect42(() => {
28850
28924
  mentionProviderRef.current = mentionProvider;
28851
28925
  }, [mentionProvider]);
28852
28926
  const fenceRenderersRef = useRef40(fenceRenderers);
28853
- useEffect41(() => {
28927
+ useEffect42(() => {
28854
28928
  fenceRenderersRef.current = fenceRenderers;
28855
28929
  }, [fenceRenderers]);
28856
28930
  const activeThemeRef = useRef40(activeTheme);
28857
- useEffect41(() => {
28931
+ useEffect42(() => {
28858
28932
  activeThemeRef.current = activeTheme;
28859
28933
  }, [activeTheme]);
28860
- const resolvedPlaceholder = useMemo36(() => placeholder ?? pickEmptyPrompt(), [placeholder]);
28934
+ const resolvedPlaceholder = useMemo37(() => placeholder ?? pickEmptyPrompt(), [placeholder]);
28861
28935
  const isExternalUpdate = useRef40(false);
28862
28936
  const lastSourceRef = useRef40(editorSource);
28863
28937
  const pendingLocalSourcesRef = useRef40([]);
28864
28938
  const mediaProviderRef = useRef40(mediaProvider);
28865
- useEffect41(() => {
28939
+ useEffect42(() => {
28866
28940
  mediaProviderRef.current = mediaProvider;
28867
28941
  }, [mediaProvider]);
28868
28942
  const frontmatterRef = useRef40(stripFrontmatter(editorSource).frontmatter);
@@ -28879,7 +28953,7 @@ function WysiwygEditor({
28879
28953
  }
28880
28954
  }
28881
28955
  const submitOnEnterRef = useRef40(submitOnEnter);
28882
- useEffect41(() => {
28956
+ useEffect42(() => {
28883
28957
  submitOnEnterRef.current = submitOnEnter;
28884
28958
  }, [submitOnEnter]);
28885
28959
  const editor = useEditor2({
@@ -29067,25 +29141,25 @@ function WysiwygEditor({
29067
29141
  }
29068
29142
  }
29069
29143
  });
29070
- useEffect41(() => {
29144
+ useEffect42(() => {
29071
29145
  if (editor) {
29072
29146
  setTiptapEditor(editor);
29073
29147
  }
29074
29148
  return () => setTiptapEditor(null);
29075
29149
  }, [editor, setTiptapEditor]);
29076
- useEffect41(() => {
29150
+ useEffect42(() => {
29077
29151
  if (editor) editor.setEditable(!readOnly);
29078
29152
  }, [editor, readOnly]);
29079
29153
  const containerRef = useRef40(null);
29080
- const [badgeMenu, setBadgeMenu] = useState51(null);
29081
- const [propsMenu, setPropsMenu] = useState51(null);
29154
+ const [badgeMenu, setBadgeMenu] = useState52(null);
29155
+ const [propsMenu, setPropsMenu] = useState52(null);
29082
29156
  const closeBadgeMenu = useCallback38(() => {
29083
29157
  setBadgeMenu(null);
29084
29158
  requestAnimationFrame(() => {
29085
29159
  if (editor && !editor.isDestroyed) editor.commands.focus();
29086
29160
  });
29087
29161
  }, [editor]);
29088
- useEffect41(() => {
29162
+ useEffect42(() => {
29089
29163
  if (!editor) return;
29090
29164
  const root = containerRef.current;
29091
29165
  if (!root) return;
@@ -29141,7 +29215,7 @@ function WysiwygEditor({
29141
29215
  root.addEventListener("mousedown", onClick);
29142
29216
  return () => root.removeEventListener("mousedown", onClick);
29143
29217
  }, [editor]);
29144
- useEffect41(() => {
29218
+ useEffect42(() => {
29145
29219
  if (!editor) return;
29146
29220
  const pendingIndex = pendingLocalSourcesRef.current.lastIndexOf(editorSource);
29147
29221
  if (pendingIndex >= 0) {
@@ -29173,7 +29247,7 @@ function WysiwygEditor({
29173
29247
  lastSourceRef.current = editorSource;
29174
29248
  isExternalUpdate.current = false;
29175
29249
  }, [editorSource, editor, wrapPolicyEnabled]);
29176
- const badgePreviewSource = useMemo36(() => {
29250
+ const badgePreviewSource = useMemo37(() => {
29177
29251
  if (!badgeMenu) return void 0;
29178
29252
  try {
29179
29253
  const previewDoc = markdownToDoc2(parseMarkdown6(editorSource), { autoTemplates: false });
@@ -29198,7 +29272,7 @@ function WysiwygEditor({
29198
29272
  previewSettings?.activeTheme,
29199
29273
  previewSettings?.activeViewport
29200
29274
  ]);
29201
- const themeStyle = useMemo36(() => {
29275
+ const themeStyle = useMemo37(() => {
29202
29276
  if (!activeTheme) return {};
29203
29277
  const out = {
29204
29278
  "--squisq-block-props-accent": activeTheme.colors.primary
@@ -29398,7 +29472,7 @@ function moveSelectionToDropPoint(view, event) {
29398
29472
  }
29399
29473
 
29400
29474
  // src/InlinePreviewGutter.tsx
29401
- import { useLayoutEffect as useLayoutEffect8, useMemo as useMemo38, useRef as useRef41, useState as useState53 } from "react";
29475
+ import { useLayoutEffect as useLayoutEffect8, useMemo as useMemo39, useRef as useRef41, useState as useState54 } from "react";
29402
29476
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS4 } from "@bendyline/squisq/schemas";
29403
29477
  import {
29404
29478
  flattenBlocks as flattenBlocks4,
@@ -29410,14 +29484,14 @@ import { extractPlainText as extractPlainText3, getChildren } from "@bendyline/s
29410
29484
  import { BlockRenderer as BlockRenderer3, MediaContext as MediaContext4 } from "@bendyline/squisq-react";
29411
29485
 
29412
29486
  // src/useHeadingLayout.ts
29413
- import { useCallback as useCallback39, useEffect as useEffect42, useMemo as useMemo37, useState as useState52 } from "react";
29487
+ import { useCallback as useCallback39, useEffect as useEffect43, useMemo as useMemo38, useState as useState53 } from "react";
29414
29488
  import { flattenBlocks as flattenBlocks3, hasTemplate } from "@bendyline/squisq/doc";
29415
29489
  function useHeadingLayout(refInsideWrapper) {
29416
29490
  const { doc, activeView, monacoEditor, tiptapEditor } = useEditorContext();
29417
- const flatBlocks = useMemo37(() => doc ? flattenBlocks3(doc.blocks) : [], [doc]);
29418
- const [entries, setEntries] = useState52([]);
29419
- const [pageEdges, setPageEdges] = useState52(null);
29420
- useEffect42(() => {
29491
+ const flatBlocks = useMemo38(() => doc ? flattenBlocks3(doc.blocks) : [], [doc]);
29492
+ const [entries, setEntries] = useState53([]);
29493
+ const [pageEdges, setPageEdges] = useState53(null);
29494
+ useEffect43(() => {
29421
29495
  if (activeView !== "wysiwyg") return;
29422
29496
  const node2 = refInsideWrapper.current;
29423
29497
  if (!node2) return;
@@ -29485,7 +29559,7 @@ function useHeadingLayout(refInsideWrapper) {
29485
29559
  window.removeEventListener("resize", recompute);
29486
29560
  };
29487
29561
  }, [activeView, flatBlocks, refInsideWrapper]);
29488
- useEffect42(() => {
29562
+ useEffect43(() => {
29489
29563
  if (activeView !== "raw") return;
29490
29564
  if (!monacoEditor) return;
29491
29565
  const node2 = refInsideWrapper.current;
@@ -29546,7 +29620,7 @@ function useHeadingLayout(refInsideWrapper) {
29546
29620
  window.removeEventListener("resize", recompute);
29547
29621
  };
29548
29622
  }, [activeView, monacoEditor, flatBlocks, refInsideWrapper]);
29549
- useEffect42(() => {
29623
+ useEffect43(() => {
29550
29624
  setEntries([]);
29551
29625
  setPageEdges(null);
29552
29626
  }, [activeView]);
@@ -29778,7 +29852,7 @@ function InlinePreviewGutter({
29778
29852
  const { entries: headingEntries, scrollToBlock } = useHeadingLayout(gutterRef);
29779
29853
  const previewSettings = usePreviewSettingsOptional();
29780
29854
  const activeTheme = previewSettings?.activeTheme ?? DEFAULT_THEME5;
29781
- const items = useMemo38(() => {
29855
+ const items = useMemo39(() => {
29782
29856
  if (!doc || !doc.blocks.length) return [];
29783
29857
  const flat = flattenBlocks4(doc.blocks);
29784
29858
  const totalBlocks = flat.length;
@@ -29835,12 +29909,12 @@ function InlinePreviewGutter({
29835
29909
  });
29836
29910
  return result;
29837
29911
  }, [doc, viewport, activeTheme]);
29838
- const connectorTops = useMemo38(() => {
29912
+ const connectorTops = useMemo39(() => {
29839
29913
  const m = /* @__PURE__ */ new Map();
29840
29914
  headingEntries.forEach((e2) => m.set(e2.block.id, e2.top));
29841
29915
  return m;
29842
29916
  }, [headingEntries]);
29843
- const [positions, setPositions] = useState53(/* @__PURE__ */ new Map());
29917
+ const [positions, setPositions] = useState54(/* @__PURE__ */ new Map());
29844
29918
  useLayoutEffect8(() => {
29845
29919
  if (items.length === 0) {
29846
29920
  setPositions((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
@@ -30023,346 +30097,20 @@ function InlinePreviewGutter({
30023
30097
 
30024
30098
  // src/buildPreviewDoc.ts
30025
30099
  import {
30026
- coerceTemplateParams,
30027
- deriveTemplateInputs as deriveTemplateInputs3,
30028
- flattenRenderableBlocks,
30029
- hasTemplate as hasTemplate2
30100
+ buildPreviewDoc,
30101
+ documentTitleFromFileName
30030
30102
  } from "@bendyline/squisq/doc";
30031
- import { extractPlainText as extractPlainText4, KNOWN_BLOCK_META_KEYS as KNOWN_BLOCK_META_KEYS2 } from "@bendyline/squisq/markdown";
30032
- import { getChildren as getChildren2 } from "@bendyline/squisq/markdown";
30033
- import { iconMarker } from "@bendyline/squisq/icon-marker";
30034
- function extractRichText(node2) {
30035
- if (node2.type === "inlineIcon") {
30036
- const icon = node2;
30037
- return iconMarker(icon.family, icon.name);
30038
- }
30039
- if ("value" in node2 && typeof node2.value === "string") {
30040
- return node2.value;
30041
- }
30042
- const children = getChildren2(node2);
30043
- const separator = node2.type === "list" || node2.type === "listItem" ? "\n" : "";
30044
- return children.map(extractRichText).join(separator);
30045
- }
30046
- function extractBodyText(contents) {
30047
- if (!contents || contents.length === 0) return "";
30048
- const parts = [];
30049
- for (const node2 of contents) {
30050
- if (node2.type === "code" && node2.lang?.trim().toLowerCase() === "mermaid") continue;
30051
- parts.push(extractRichText(node2));
30052
- }
30053
- return parts.join("\n").trim();
30054
- }
30055
- function parseDim2(raw) {
30056
- if (raw === void 0) return void 0;
30057
- const n = parseFloat(raw);
30058
- return Number.isFinite(n) && n > 0 ? n : void 0;
30059
- }
30060
- function extractBlockImages2(contents) {
30061
- if (!contents || contents.length === 0) return [];
30062
- const images = [];
30063
- function walkHtml(node2) {
30064
- if (!node2 || typeof node2 !== "object") return;
30065
- const n = node2;
30066
- if (n.type === "htmlElement" && n.tagName.toLowerCase() === "img") {
30067
- const attrs = n.attributes;
30068
- const src = attrs?.src;
30069
- if (typeof src === "string" && src) {
30070
- images.push({
30071
- src,
30072
- alt: typeof attrs?.alt === "string" ? attrs.alt : "",
30073
- width: parseDim2(attrs?.width),
30074
- height: parseDim2(attrs?.height)
30075
- });
30076
- }
30077
- }
30078
- if (Array.isArray(n.children)) {
30079
- for (const child of n.children) walkHtml(child);
30080
- }
30081
- }
30082
- function walk(node2) {
30083
- if ("type" in node2 && node2.type === "image" && "url" in node2) {
30084
- const img = node2;
30085
- if (img.url) {
30086
- images.push({ src: img.url, alt: img.alt ?? "" });
30087
- }
30088
- }
30089
- if ("type" in node2 && (node2.type === "htmlBlock" || node2.type === "htmlInline")) {
30090
- const html = node2;
30091
- for (const child of html.htmlChildren ?? []) walkHtml(child);
30092
- }
30093
- for (const child of getChildren2(node2)) {
30094
- walk(child);
30095
- }
30096
- }
30097
- for (const node2 of contents) {
30098
- walk(node2);
30099
- }
30100
- return images;
30101
- }
30102
- function collectAllDocImages(blocks) {
30103
- const seen = /* @__PURE__ */ new Set();
30104
- const images = [];
30105
- function walkBlocks(blockList) {
30106
- for (const block of blockList) {
30107
- for (const img of extractBlockImages2(block.contents)) {
30108
- if (!seen.has(img.src)) {
30109
- seen.add(img.src);
30110
- images.push(img);
30111
- }
30112
- }
30113
- if (block.children) {
30114
- walkBlocks(block.children);
30115
- }
30116
- }
30117
- }
30118
- walkBlocks(blocks);
30119
- return images;
30120
- }
30121
- function extractListItems3(contents) {
30122
- if (!contents) return [];
30123
- const items = [];
30124
- for (const node2 of contents) {
30125
- if (node2.type === "list") {
30126
- for (const item of node2.children) {
30127
- const text = extractPlainText4(item).trim();
30128
- if (text) items.push(text);
30129
- }
30130
- }
30131
- }
30132
- return items;
30133
- }
30134
- function getTemplateDefaults2(templateName, headingText2, block) {
30135
- const body = extractBodyText(block.contents);
30136
- switch (templateName) {
30137
- case "statHighlight":
30138
- return deriveTemplateInputs3(templateName, headingText2, block.contents) ?? {
30139
- stat: headingText2,
30140
- description: body || headingText2
30141
- };
30142
- case "quote":
30143
- case "fullBleedQuote":
30144
- case "pullQuote":
30145
- return { quote: body || headingText2 };
30146
- case "factCard":
30147
- return { fact: headingText2, explanation: body || headingText2 };
30148
- case "comparisonBar":
30149
- return { leftLabel: "A", leftValue: 60, rightLabel: "B", rightValue: 40 };
30150
- case "list": {
30151
- const items = extractListItems3(block.contents);
30152
- return { items: items.length > 0 ? items : ["Item 1", "Item 2", "Item 3"] };
30153
- }
30154
- case "definitionCard":
30155
- return { term: headingText2, definition: body || headingText2 };
30156
- case "dateEvent":
30157
- return { date: headingText2, description: body || headingText2 };
30158
- case "leftFeature":
30159
- case "rightFeature": {
30160
- const images = extractBlockImages2(block.contents);
30161
- const img = images[0];
30162
- return {
30163
- imageSrc: img?.src ?? "",
30164
- imageAlt: img?.alt || headingText2,
30165
- imageWidth: img?.width,
30166
- imageHeight: img?.height,
30167
- title: headingText2,
30168
- body: body || headingText2
30169
- };
30170
- }
30171
- default:
30172
- return {};
30173
- }
30174
- }
30175
- function blockToSlide(block, index2, knownTemplates, documentTitle2) {
30176
- const headingText2 = block.sourceHeading ? extractPlainText4(block.sourceHeading) : block.title || documentTitle2 || "";
30177
- const implicitSectionHeader = block.template === "sectionHeader" && block.autoTemplate !== true && !!block.sourceHeading && !block.sourceHeading.templateAnnotation?.template;
30178
- const requestedTemplate = implicitSectionHeader ? "content" : block.template ?? "content";
30179
- const isCustomTemplate = knownTemplates?.has(requestedTemplate) ?? false;
30180
- const recognized = hasTemplate2(requestedTemplate) || isCustomTemplate;
30181
- const template = recognized ? requestedTemplate : "sectionHeader";
30182
- const defaults = getTemplateDefaults2(template, headingText2, block);
30183
- const templateOverrides = omitStringBlockMeta(block.templateOverrides);
30184
- const coercedTemplateOverrides = templateOverrides ? coerceTemplateParams(template, templateOverrides).input : void 0;
30185
- const {
30186
- id: _id,
30187
- startTime: _st,
30188
- duration: _d,
30189
- audioSegment: _as,
30190
- layers: _l,
30191
- transition: _tr,
30192
- template: _t,
30193
- title: _ti,
30194
- children: _c,
30195
- contents: _co,
30196
- sourceHeading: _sh,
30197
- templateOverrides: _to,
30198
- templateData: _td,
30199
- ...extraFields
30200
- } = block;
30201
- return {
30202
- id: block.id,
30203
- template,
30204
- duration: block.duration,
30205
- audioSegment: 0,
30206
- // Respect the block's authored transition (set via the toolbar / on-canvas
30207
- // properties palette → `{…}` block attrs). Only fall back to a default fade
30208
- // for blocks past the first when the author hasn't chosen one; the first
30209
- // block has no previous slide to transition in from.
30210
- transition: block.transition ?? (index2 > 0 ? { type: "fade", duration: 0.5 } : void 0),
30211
- title: headingText2,
30212
- // Preserve body nodes on every slide. Built-in templates ignore this
30213
- // structural field, while the canonical materializer uses it to retain
30214
- // authored rich elements (Mermaid fences today; other media can follow)
30215
- // independently of the selected visual template.
30216
- ...block.contents ? { contents: block.contents } : {},
30217
- // Custom templates additionally consume child blocks through tokens.
30218
- ...isCustomTemplate && block.children ? { children: block.children } : {},
30219
- ...defaults,
30220
- ...extraFields,
30221
- // Structured body data (```json data fences, GFM tables for dataTable)
30222
- // carries typed values; `{[…]}` string overrides win last so an explicit
30223
- // annotation param can still pin any field.
30224
- //
30225
- // Block-meta keys (transition, startTime, duration, …) are the exception:
30226
- // they were already coerced to typed block fields above (e.g.
30227
- // `block.transition` → `{ type, duration, direction }`). Their raw string
30228
- // form also rides along in `templateData`/`templateOverrides` because the
30229
- // author wrote them inside `{[…]}`; left un-stripped, that string would
30230
- // spread back over the typed value here and clobber it — turning
30231
- // `transition=vortex` into the string `"vortex"`, which the player can't
30232
- // animate. Omit them from the content spreads so the typed fields win.
30233
- ...omitBlockMeta(block.templateData),
30234
- ...coercedTemplateOverrides
30235
- };
30236
- }
30237
- var BLOCK_META_KEYS2 = new Set(Object.keys(KNOWN_BLOCK_META_KEYS2));
30238
- function omitBlockMeta(data) {
30239
- if (!data) return data;
30240
- let hit = false;
30241
- const out = {};
30242
- for (const key of Object.keys(data)) {
30243
- if (BLOCK_META_KEYS2.has(key)) {
30244
- hit = true;
30245
- continue;
30246
- }
30247
- out[key] = data[key];
30248
- }
30249
- return hit ? out : data;
30250
- }
30251
- function omitStringBlockMeta(data) {
30252
- if (!data) return data;
30253
- let hit = false;
30254
- const out = {};
30255
- for (const key of Object.keys(data)) {
30256
- if (BLOCK_META_KEYS2.has(key)) {
30257
- hit = true;
30258
- continue;
30259
- }
30260
- out[key] = data[key];
30261
- }
30262
- return hit ? out : data;
30263
- }
30264
- var IMAGE_MOTIONS = [
30265
- "zoomIn",
30266
- "zoomOut",
30267
- "panLeft",
30268
- "panRight"
30269
- ];
30270
- function documentTitleFromFileName(fileName) {
30271
- if (!fileName) return "";
30272
- const base = fileName.split(/[\\/]/).pop() ?? "";
30273
- return base.replace(/\.[^.]+$/, "").trim();
30274
- }
30275
- function resolveDocumentTitle(doc, provided) {
30276
- const frontmatterTitle = doc.frontmatter?.title;
30277
- if (typeof frontmatterTitle === "string" && frontmatterTitle.trim()) {
30278
- return frontmatterTitle.trim();
30279
- }
30280
- return provided?.trim() ?? "";
30281
- }
30282
- function buildPreviewDoc(doc, options) {
30283
- const flat = flattenRenderableBlocks(doc.blocks);
30284
- const allImages = collectAllDocImages(doc.blocks);
30285
- const usedImageSrcs = /* @__PURE__ */ new Set();
30286
- const knownTemplates = doc.customTemplates ? new Set(doc.customTemplates.map((d) => d.name)) : void 0;
30287
- const documentTitle2 = resolveDocumentTitle(doc, options?.documentTitle);
30288
- const slides = [];
30289
- let motionIndex = 0;
30290
- for (let i = 0; i < flat.length; i++) {
30291
- const block = flat[i];
30292
- const blockImages = extractBlockImages2(block.contents);
30293
- const slide = blockToSlide(block, i, knownTemplates, documentTitle2);
30294
- if (blockImages.length > 0 && slide.template === "sectionHeader") {
30295
- const img = blockImages[0];
30296
- usedImageSrcs.add(img.src);
30297
- slide.template = "imageWithCaption";
30298
- slide.imageSrc = img.src;
30299
- slide.imageAlt = img.alt;
30300
- slide.caption = slide.title;
30301
- slide.captionPosition = "bottom";
30302
- slide.ambientMotion = IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length];
30303
- } else if (blockImages.length > 0) {
30304
- const img = blockImages[0];
30305
- usedImageSrcs.add(img.src);
30306
- if (!slide.accentImage) {
30307
- slide.accentImage = {
30308
- src: img.src,
30309
- alt: img.alt,
30310
- position: "left-strip",
30311
- ambientMotion: IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length]
30312
- };
30313
- }
30314
- }
30315
- slides.push(slide);
30316
- }
30317
- const unusedImages = allImages.filter((img) => !usedImageSrcs.has(img.src));
30318
- if (unusedImages.length > 0 && slides.length > 0) {
30319
- const interval = Math.max(2, Math.floor(slides.length / (unusedImages.length + 1)));
30320
- let insertOffset = 0;
30321
- for (let imgIdx = 0; imgIdx < unusedImages.length; imgIdx++) {
30322
- const insertAt = Math.min((imgIdx + 1) * interval + insertOffset, slides.length);
30323
- const img = unusedImages[imgIdx];
30324
- slides.splice(insertAt, 0, {
30325
- id: `img-interleave-${imgIdx}`,
30326
- template: "imageWithCaption",
30327
- duration: 5,
30328
- audioSegment: 0,
30329
- imageSrc: img.src,
30330
- imageAlt: img.alt,
30331
- ambientMotion: IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length],
30332
- transition: { type: "fade", duration: 0.5 }
30333
- });
30334
- insertOffset++;
30335
- }
30336
- }
30337
- let t = 0;
30338
- for (const slide of slides) {
30339
- slide.startTime = t;
30340
- t += slide.duration;
30341
- }
30342
- const audio = doc.audio?.segments?.length > 0 ? doc.audio : {
30343
- segments: t > 0 ? [{ src: "", name: "preview", duration: t, startTime: 0 }] : []
30344
- };
30345
- return {
30346
- // Preserve document-wide capabilities (custom themes, persistent layers,
30347
- // scheduled media, frontmatter, captions, and future schema fields).
30348
- // Preview preparation should replace only the slide/timing projection.
30349
- ...doc,
30350
- duration: t,
30351
- blocks: slides,
30352
- audio
30353
- };
30354
- }
30355
30103
 
30356
30104
  // src/OutlinePanel.tsx
30357
30105
  import {
30358
30106
  useCallback as useCallback40,
30359
- useEffect as useEffect43,
30360
- useMemo as useMemo39,
30107
+ useEffect as useEffect44,
30108
+ useMemo as useMemo40,
30361
30109
  useRef as useRef42,
30362
- useState as useState54
30110
+ useState as useState55
30363
30111
  } from "react";
30364
- import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate3 } from "@bendyline/squisq/doc";
30365
- import { extractPlainText as extractPlainText5 } from "@bendyline/squisq/markdown";
30112
+ import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate2 } from "@bendyline/squisq/doc";
30113
+ import { extractPlainText as extractPlainText4 } from "@bendyline/squisq/markdown";
30366
30114
 
30367
30115
  // src/outlineSource.ts
30368
30116
  import { parseMarkdown as parseMarkdown7 } from "@bendyline/squisq/markdown";
@@ -30462,7 +30210,7 @@ function splitTrailingLineGap(value) {
30462
30210
 
30463
30211
  // src/OutlinePanel.tsx
30464
30212
  import { jsx as jsx59, jsxs as jsxs46 } from "react/jsx-runtime";
30465
- var OUTLINE_RESPONSIVE_WIDTH = "clamp(260px, 30vw, 460px)";
30213
+ var OUTLINE_RESPONSIVE_WIDTH = "clamp(180px, 15vw, 260px)";
30466
30214
  var OUTLINE_DRAG_MIME = "application/x-squisq-outline-section";
30467
30215
  function OutlinePanel({ width, className, readOnly = false }) {
30468
30216
  const {
@@ -30478,9 +30226,9 @@ function OutlinePanel({ width, className, readOnly = false }) {
30478
30226
  const { scrollToBlock } = useHeadingLayout(paneRef);
30479
30227
  const cursorActiveId = useActiveOutlineBlockId();
30480
30228
  const activeDragRef = useRef42(null);
30481
- const [draggedBlockId, setDraggedBlockId] = useState54(null);
30482
- const [dropTarget, setDropTarget] = useState54(null);
30483
- const blockModeActiveId = useMemo39(() => {
30229
+ const [draggedBlockId, setDraggedBlockId] = useState55(null);
30230
+ const [dropTarget, setDropTarget] = useState55(null);
30231
+ const blockModeActiveId = useMemo40(() => {
30484
30232
  if (layoutMode !== "block" || activeBlockStartLine == null || !doc) return null;
30485
30233
  const match = flattenBlocks5(doc.blocks).find(
30486
30234
  (b) => b.sourceHeading?.position?.start.line === activeBlockStartLine
@@ -30625,10 +30373,10 @@ function OutlineNode({
30625
30373
  const heading = block.sourceHeading;
30626
30374
  const depth = heading?.depth ?? 1;
30627
30375
  const headingLine2 = heading?.position?.start.line;
30628
- const text = heading ? extractPlainText5(heading).trim() : "";
30376
+ const text = heading ? extractPlainText4(heading).trim() : "";
30629
30377
  const annotation = heading?.templateAnnotation;
30630
30378
  const tplName = annotation?.template;
30631
- const showChip = tplName && hasTemplate3(tplName);
30379
+ const showChip = tplName && hasTemplate2(tplName);
30632
30380
  const isActive = block.id === activeBlockId;
30633
30381
  const canPromote = !!heading && depth > 1;
30634
30382
  const canDemote = !!heading && depth < 6;
@@ -30745,12 +30493,12 @@ function OutlineNode({
30745
30493
  }
30746
30494
  function useActiveOutlineBlockId() {
30747
30495
  const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
30748
- const flatBlocks = useMemo39(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
30749
- const [activeId, setActiveId] = useState54(null);
30750
- useEffect43(() => {
30496
+ const flatBlocks = useMemo40(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
30497
+ const [activeId, setActiveId] = useState55(null);
30498
+ useEffect44(() => {
30751
30499
  setActiveId(null);
30752
30500
  }, [activeView]);
30753
- useEffect43(() => {
30501
+ useEffect44(() => {
30754
30502
  if (activeView !== "wysiwyg" || !tiptapEditor) return;
30755
30503
  const update = () => {
30756
30504
  const { from } = tiptapEditor.state.selection;
@@ -30772,7 +30520,7 @@ function useActiveOutlineBlockId() {
30772
30520
  tiptapEditor.off("update", update);
30773
30521
  };
30774
30522
  }, [activeView, tiptapEditor, flatBlocks]);
30775
- useEffect43(() => {
30523
+ useEffect44(() => {
30776
30524
  if (activeView !== "raw" || !monacoEditor) return;
30777
30525
  const update = () => {
30778
30526
  const line = monacoEditor.getPosition()?.lineNumber;
@@ -30823,7 +30571,7 @@ function bumpHeadingLevelInSource(source, line, delta) {
30823
30571
  }
30824
30572
 
30825
30573
  // src/codeContext/CodeContextZones.tsx
30826
- import { useCallback as useCallback42, useEffect as useEffect45, useMemo as useMemo41, useRef as useRef44, useState as useState55 } from "react";
30574
+ import { useCallback as useCallback42, useEffect as useEffect46, useMemo as useMemo42, useRef as useRef44, useState as useState56 } from "react";
30827
30575
  import { createPortal as createPortal10 } from "react-dom";
30828
30576
 
30829
30577
  // src/codeContext/diffContextSections.ts
@@ -30947,7 +30695,7 @@ function setOrdinal(zone, ordinal) {
30947
30695
  // src/codeContext/CodeContextSectionView.tsx
30948
30696
  import { parseMarkdown as parseMarkdown8 } from "@bendyline/squisq/markdown";
30949
30697
  import { MarkdownRenderer } from "@bendyline/squisq-react";
30950
- import { useCallback as useCallback41, useEffect as useEffect44, useMemo as useMemo40, useRef as useRef43 } from "react";
30698
+ import { useCallback as useCallback41, useEffect as useEffect45, useMemo as useMemo41, useRef as useRef43 } from "react";
30951
30699
  import { jsx as jsx60, jsxs as jsxs47 } from "react/jsx-runtime";
30952
30700
  function CodeContextSectionView({
30953
30701
  section,
@@ -30959,15 +30707,15 @@ function CodeContextSectionView({
30959
30707
  onMeasure
30960
30708
  }) {
30961
30709
  const rootRef = useRef43(null);
30962
- const stripNodes = useMemo40(
30710
+ const stripNodes = useMemo41(
30963
30711
  () => parseMarkdown8(section.summaryMarkdown).children,
30964
30712
  [section.summaryMarkdown]
30965
30713
  );
30966
- const bodyNodes = useMemo40(
30714
+ const bodyNodes = useMemo41(
30967
30715
  () => expanded && section.markdown ? parseMarkdown8(section.markdown).children : null,
30968
30716
  [expanded, section.markdown]
30969
30717
  );
30970
- useEffect44(() => {
30718
+ useEffect45(() => {
30971
30719
  const el = rootRef.current;
30972
30720
  if (!el || typeof ResizeObserver === "undefined") return;
30973
30721
  const report = () => {
@@ -31039,11 +30787,11 @@ function CodeContextSectionView({
31039
30787
  import { Fragment as Fragment18, jsx as jsx61 } from "react/jsx-runtime";
31040
30788
  function CodeContextZones({ options }) {
31041
30789
  const { monacoEditor } = useEditorContext();
31042
- const [manager, setManager] = useState55(null);
31043
- const [, setZonesVersion] = useState55(0);
31044
- const [expandedById, setExpandedById] = useState55({});
30790
+ const [manager, setManager] = useState56(null);
30791
+ const [, setZonesVersion] = useState56(0);
30792
+ const [expandedById, setExpandedById] = useState56({});
31045
30793
  const seenIds = useRef44(/* @__PURE__ */ new Set());
31046
- useEffect45(() => {
30794
+ useEffect46(() => {
31047
30795
  if (!monacoEditor) return;
31048
30796
  const mgr = new CodeContextZoneManager(monacoEditor);
31049
30797
  const off = mgr.onDidChangeZones(() => setZonesVersion((v2) => v2 + 1));
@@ -31056,7 +30804,7 @@ function CodeContextZones({ options }) {
31056
30804
  }, [monacoEditor]);
31057
30805
  const fileTop = options.fileTop;
31058
30806
  const sections = options.sections;
31059
- const resolved = useMemo41(() => {
30807
+ const resolved = useMemo42(() => {
31060
30808
  const out = [];
31061
30809
  if (fileTop) {
31062
30810
  out.push({ spec: { id: fileTop.id, line: 0, ordinal: 0 }, section: fileTop });
@@ -31066,7 +30814,7 @@ function CodeContextZones({ options }) {
31066
30814
  });
31067
30815
  return out;
31068
30816
  }, [fileTop, sections]);
31069
- useEffect45(() => {
30817
+ useEffect46(() => {
31070
30818
  if (!manager) return;
31071
30819
  manager.sync(resolved.map((r) => r.spec));
31072
30820
  setExpandedById((prev) => {
@@ -31502,7 +31250,7 @@ function placeClipInBlock(source, fromLine, targetHeadingLine, spec, startAt) {
31502
31250
  }
31503
31251
 
31504
31252
  // src/TimelineTrack.tsx
31505
- import { useCallback as useCallback44, useEffect as useEffect48, useMemo as useMemo42, useRef as useRef47, useState as useState58 } from "react";
31253
+ import { useCallback as useCallback44, useEffect as useEffect49, useMemo as useMemo43, useRef as useRef47, useState as useState59 } from "react";
31506
31254
  import {
31507
31255
  resolveMediaSchedule as resolveMediaSchedule2,
31508
31256
  getDocPlaybackDuration,
@@ -31661,7 +31409,7 @@ function resolveBlockVisual(doc, block, theme, viewport) {
31661
31409
  }
31662
31410
 
31663
31411
  // src/useTimelineClock.ts
31664
- import { useCallback as useCallback43, useEffect as useEffect46, useRef as useRef45, useState as useState56 } from "react";
31412
+ import { useCallback as useCallback43, useEffect as useEffect47, useRef as useRef45, useState as useState57 } from "react";
31665
31413
  function advanceTime(prev, dt, total) {
31666
31414
  if (total <= 0) return 0;
31667
31415
  return Math.min(total, Math.max(0, prev + dt));
@@ -31681,8 +31429,8 @@ function playTimelineMediaAt(root, time) {
31681
31429
  });
31682
31430
  }
31683
31431
  function useTimelineClock(total) {
31684
- const [currentTime, setCurrentTime] = useState56(0);
31685
- const [isPlaying, setIsPlaying] = useState56(false);
31432
+ const [currentTime, setCurrentTime] = useState57(0);
31433
+ const [isPlaying, setIsPlaying] = useState57(false);
31686
31434
  const rafRef = useRef45(null);
31687
31435
  const lastRef = useRef45(0);
31688
31436
  const currentTimeRef = useRef45(0);
@@ -31690,10 +31438,10 @@ function useTimelineClock(total) {
31690
31438
  const mediaHostRef = useRef45(null);
31691
31439
  currentTimeRef.current = currentTime;
31692
31440
  isPlayingRef.current = isPlaying;
31693
- useEffect46(() => {
31441
+ useEffect47(() => {
31694
31442
  setCurrentTime((t) => Math.min(t, Math.max(0, total)));
31695
31443
  }, [total]);
31696
- useEffect46(() => {
31444
+ useEffect47(() => {
31697
31445
  if (!isPlaying) return;
31698
31446
  lastRef.current = performance.now();
31699
31447
  const tick = (now) => {
@@ -31755,7 +31503,7 @@ function timelineMediaLabel(src, kind) {
31755
31503
  }
31756
31504
 
31757
31505
  // src/TimelineItemMenu.tsx
31758
- import { useEffect as useEffect47, useLayoutEffect as useLayoutEffect9, useRef as useRef46, useState as useState57 } from "react";
31506
+ import { useEffect as useEffect48, useLayoutEffect as useLayoutEffect9, useRef as useRef46, useState as useState58 } from "react";
31759
31507
  import { createPortal as createPortal11 } from "react-dom";
31760
31508
  import { Fragment as Fragment19, jsx as jsx64, jsxs as jsxs49 } from "react/jsx-runtime";
31761
31509
  function TimelineItemMenu({
@@ -31770,7 +31518,7 @@ function TimelineItemMenu({
31770
31518
  onClose
31771
31519
  }) {
31772
31520
  const panelRef = useRef46(null);
31773
- const [style, setStyle] = useState57(() => menuStyle(anchor));
31521
+ const [style, setStyle] = useState58(() => menuStyle(anchor));
31774
31522
  useLayoutEffect9(() => {
31775
31523
  const panel = panelRef.current;
31776
31524
  if (!panel) return;
@@ -31784,7 +31532,7 @@ function TimelineItemMenu({
31784
31532
  resizeObserver?.disconnect();
31785
31533
  };
31786
31534
  }, [anchor]);
31787
- useEffect47(() => {
31535
+ useEffect48(() => {
31788
31536
  const onKeyDown = (event) => {
31789
31537
  if (event.key !== "Escape") return;
31790
31538
  event.preventDefault();
@@ -31844,12 +31592,12 @@ function BlockMenu({
31844
31592
  onStartTime,
31845
31593
  onTransition
31846
31594
  }) {
31847
- const [explicitDuration, setExplicitDuration] = useState57(target.explicitDuration);
31848
- const [duration, setDuration] = useState57(formatNumber(target.duration));
31849
- const [startTime, setStartTime] = useState57(
31595
+ const [explicitDuration, setExplicitDuration] = useState58(target.explicitDuration);
31596
+ const [duration, setDuration] = useState58(formatNumber(target.duration));
31597
+ const [startTime, setStartTime] = useState58(
31850
31598
  target.startTime == null ? "" : formatNumber(target.startTime)
31851
31599
  );
31852
- const [transition, setTransition] = useState57(target.transition);
31600
+ const [transition, setTransition] = useState58(target.transition);
31853
31601
  const toggleAutotime = (autotimed) => {
31854
31602
  setExplicitDuration(!autotimed);
31855
31603
  if (autotimed) {
@@ -31921,11 +31669,11 @@ function VideoMenu({
31921
31669
  target,
31922
31670
  onPatch
31923
31671
  }) {
31924
- const [placement, setPlacement] = useState57(target.placement);
31925
- const [locked, setLocked] = useState57(target.lockToBlock);
31926
- const [pipSize, setPipSize] = useState57(target.pipSize ?? "");
31927
- const [pipShape, setPipShape] = useState57(target.pipShape ?? "");
31928
- const [pipPosition, setPipPosition] = useState57(target.pipPosition ?? "");
31672
+ const [placement, setPlacement] = useState58(target.placement);
31673
+ const [locked, setLocked] = useState58(target.lockToBlock);
31674
+ const [pipSize, setPipSize] = useState58(target.pipSize ?? "");
31675
+ const [pipShape, setPipShape] = useState58(target.pipShape ?? "");
31676
+ const [pipPosition, setPipPosition] = useState58(target.pipPosition ?? "");
31929
31677
  const placed = placement === "picture-in-picture" || placement === "overlay";
31930
31678
  const placementOptions = [
31931
31679
  target.canUseContentPlacement ? { value: "content", label: "In layout" } : { value: "default", label: "Default" },
@@ -32195,14 +31943,14 @@ function TimelineTrack({
32195
31943
  colorScheme
32196
31944
  } = useEditorContext();
32197
31945
  const doc = docProp ?? contextDoc;
32198
- const [drag, setDrag] = useState58(null);
32199
- const [itemMenu, setItemMenu] = useState58(null);
32200
- const [pxPerSecond, setPxPerSecond] = useState58(DEFAULT_PX_PER_SECOND);
31946
+ const [drag, setDrag] = useState59(null);
31947
+ const [itemMenu, setItemMenu] = useState59(null);
31948
+ const [pxPerSecond, setPxPerSecond] = useState59(DEFAULT_PX_PER_SECOND);
32201
31949
  const scrollRef = useRef47(null);
32202
- const blocks = useMemo42(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
31950
+ const blocks = useMemo43(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
32203
31951
  const previewSettings = usePreviewSettingsOptional();
32204
31952
  const previewTheme = previewSettings?.activeTheme ?? DEFAULT_THEME6;
32205
- const visualByBlock = useMemo42(() => {
31953
+ const visualByBlock = useMemo43(() => {
32206
31954
  const map = /* @__PURE__ */ new Map();
32207
31955
  if (doc) {
32208
31956
  for (const b of blocks) {
@@ -32212,16 +31960,16 @@ function TimelineTrack({
32212
31960
  }
32213
31961
  return map;
32214
31962
  }, [doc, blocks, previewTheme]);
32215
- const derivedClips = useMemo42(
31963
+ const derivedClips = useMemo43(
32216
31964
  () => doc ? resolveMediaSchedule2(doc) : [],
32217
31965
  [doc]
32218
31966
  );
32219
31967
  const clips = schedule ?? derivedClips;
32220
- const playbackClips = useMemo42(
31968
+ const playbackClips = useMemo43(
32221
31969
  () => doc ? collectTimelinePlaybackSchedule(doc, clips) : clips,
32222
31970
  [clips, doc]
32223
31971
  );
32224
- const total = useMemo42(() => doc ? getDocPlaybackDuration(doc) : 0, [doc]);
31972
+ const total = useMemo43(() => doc ? getDocPlaybackDuration(doc) : 0, [doc]);
32225
31973
  const width = Math.max(total * pxPerSecond, 200);
32226
31974
  const internalClock = useTimelineClock(total);
32227
31975
  const activeClock = clock ?? internalClock;
@@ -32230,8 +31978,8 @@ function TimelineTrack({
32230
31978
  setDrag(null);
32231
31979
  play();
32232
31980
  }, [play]);
32233
- const [scrubbing, setScrubbing] = useState58(false);
32234
- useEffect48(() => {
31981
+ const [scrubbing, setScrubbing] = useState59(false);
31982
+ useEffect49(() => {
32235
31983
  if (!scrubbing) return;
32236
31984
  const onMove = (e2) => {
32237
31985
  const scroll = scrollRef.current;
@@ -32248,7 +31996,7 @@ function TimelineTrack({
32248
31996
  window.removeEventListener("pointerup", onUp);
32249
31997
  };
32250
31998
  }, [scrubbing, pxPerSecond, seek]);
32251
- const rawClipById = useMemo42(() => {
31999
+ const rawClipById = useMemo43(() => {
32252
32000
  const map = /* @__PURE__ */ new Map();
32253
32001
  if (doc) {
32254
32002
  for (const b of flattenBlocks6(doc.blocks)) for (const m of b.media ?? []) map.set(m.id, m);
@@ -32269,7 +32017,7 @@ function TimelineTrack({
32269
32017
  [blocks]
32270
32018
  );
32271
32019
  const followedBlockRef = useRef47(null);
32272
- useEffect48(() => {
32020
+ useEffect49(() => {
32273
32021
  if (!isPlaying) {
32274
32022
  followedBlockRef.current = null;
32275
32023
  return;
@@ -32280,7 +32028,7 @@ function TimelineTrack({
32280
32028
  const line = headingLine(block);
32281
32029
  if (line != null) goToBlockByLine(line);
32282
32030
  }, [isPlaying, currentTime, blockAtTime, goToBlockByLine]);
32283
- useEffect48(() => {
32031
+ useEffect49(() => {
32284
32032
  if (!isPlaying) return;
32285
32033
  const scroll = scrollRef.current;
32286
32034
  if (!scroll) return;
@@ -32328,8 +32076,8 @@ function TimelineTrack({
32328
32076
  );
32329
32077
  const zoomIn = useCallback44(() => setPxPerSecond((s) => Math.min(ZOOM_MAX, s * ZOOM_FACTOR)), []);
32330
32078
  const zoomOut = useCallback44(() => setPxPerSecond((s) => Math.max(ZOOM_MIN, s / ZOOM_FACTOR)), []);
32331
- const [viewportWidth, setViewportWidth] = useState58(0);
32332
- useEffect48(() => {
32079
+ const [viewportWidth, setViewportWidth] = useState59(0);
32080
+ useEffect49(() => {
32333
32081
  const el = scrollRef.current;
32334
32082
  if (!el || typeof ResizeObserver === "undefined") return;
32335
32083
  const update = () => setViewportWidth(el.clientWidth);
@@ -32343,7 +32091,7 @@ function TimelineTrack({
32343
32091
  const dragRef = useRef47(null);
32344
32092
  dragRef.current = drag;
32345
32093
  const isDragging = drag != null && !drag.committed;
32346
- useEffect48(() => {
32094
+ useEffect49(() => {
32347
32095
  if (!isDragging) return;
32348
32096
  const onMove = (e2) => {
32349
32097
  const d = dragRef.current;
@@ -32374,7 +32122,7 @@ function TimelineTrack({
32374
32122
  window.removeEventListener("pointerup", onUp);
32375
32123
  };
32376
32124
  }, [isDragging]);
32377
- useEffect48(() => {
32125
+ useEffect49(() => {
32378
32126
  if (dragRef.current?.committed) setDrag(null);
32379
32127
  }, [doc]);
32380
32128
  const beginDrag = useCallback44(
@@ -32910,7 +32658,7 @@ function formatDur(seconds) {
32910
32658
  }
32911
32659
 
32912
32660
  // src/TimelineVideoPanel.tsx
32913
- import { useMemo as useMemo43 } from "react";
32661
+ import { useMemo as useMemo44 } from "react";
32914
32662
  import { MediaClipLayer as MediaClipLayer2 } from "@bendyline/squisq-react";
32915
32663
  import { jsx as jsx66, jsxs as jsxs51 } from "react/jsx-runtime";
32916
32664
  function TimelineVideoPanel({
@@ -32920,7 +32668,7 @@ function TimelineVideoPanel({
32920
32668
  basePath = "/",
32921
32669
  onClose
32922
32670
  }) {
32923
- const videos = useMemo43(() => schedule.filter((clip) => clip.kind === "video"), [schedule]);
32671
+ const videos = useMemo44(() => schedule.filter((clip) => clip.kind === "video"), [schedule]);
32924
32672
  const activeVideos = videos.filter(
32925
32673
  (clip) => currentTime >= clip.absoluteStart && currentTime < clip.absoluteEnd
32926
32674
  );
@@ -32974,12 +32722,12 @@ function formatClock3(seconds) {
32974
32722
  }
32975
32723
 
32976
32724
  // src/TimelineCompositionPanel.tsx
32977
- import { useMemo as useMemo44 } from "react";
32725
+ import { useMemo as useMemo45 } from "react";
32978
32726
  import { getDocPlaybackDuration as getDocPlaybackDuration2, resolveMediaSchedule as resolveMediaSchedule3 } from "@bendyline/squisq/schemas";
32979
32727
  import { DocPlayer } from "@bendyline/squisq-react";
32980
32728
 
32981
32729
  // src/usePreviewProjection.ts
32982
- import { useEffect as useEffect49, useState as useState59 } from "react";
32730
+ import { useEffect as useEffect50, useState as useState60 } from "react";
32983
32731
  import { resolveAudioMapping } from "@bendyline/squisq/doc";
32984
32732
  import { applyTransform } from "@bendyline/squisq/transform";
32985
32733
  function hasEquivalentAudio(left, right) {
@@ -32999,8 +32747,8 @@ function preserveEquivalentAudio(previous, next) {
32999
32747
  };
33000
32748
  }
33001
32749
  function usePreviewProjection(doc, transformStyle, workspaceContainer, documentTitle2) {
33002
- const [projection, setProjection] = useState59(null);
33003
- useEffect49(() => {
32750
+ const [projection, setProjection] = useState60(null);
32751
+ useEffect50(() => {
33004
32752
  if (!doc || !doc.blocks.length) {
33005
32753
  setProjection(null);
33006
32754
  return;
@@ -33066,11 +32814,11 @@ function TimelineCompositionPanel({
33066
32814
  );
33067
32815
  const contentDoc = projection?.contentDoc ?? null;
33068
32816
  const playerDoc = projection?.playerDoc ?? null;
33069
- const totalDuration = useMemo44(
32817
+ const totalDuration = useMemo45(
33070
32818
  () => playerDoc ? getDocPlaybackDuration2(playerDoc) : 0,
33071
32819
  [playerDoc]
33072
32820
  );
33073
- const effectiveVideoPresentation = useMemo44(() => {
32821
+ const effectiveVideoPresentation = useMemo45(() => {
33074
32822
  if (!playerDoc) return activeVideoPresentation;
33075
32823
  const activeVideo = resolveMediaSchedule3(playerDoc).find(
33076
32824
  (clip) => clip.kind === "video" && clock.currentTime >= clip.absoluteStart && clock.currentTime < clip.absoluteEnd
@@ -33079,7 +32827,7 @@ function TimelineCompositionPanel({
33079
32827
  if (activeVideo?.placement === "overlay") return "full-frame";
33080
32828
  return activeVideoPresentation;
33081
32829
  }, [activeVideoPresentation, clock.currentTime, playerDoc]);
33082
- const audioController = useMemo44(
32830
+ const audioController = useMemo45(
33083
32831
  () => ({
33084
32832
  currentTime: clock.currentTime,
33085
32833
  isPlaying: clock.isPlaying,
@@ -33260,7 +33008,7 @@ function TimelineToolbar({
33260
33008
  }
33261
33009
 
33262
33010
  // src/PlainHtmlPreview.tsx
33263
- import { useCallback as useCallback45, useEffect as useEffect50, useMemo as useMemo45, useRef as useRef48, useState as useState60 } from "react";
33011
+ import { useCallback as useCallback45, useEffect as useEffect51, useMemo as useMemo46, useRef as useRef48, useState as useState61 } from "react";
33264
33012
  import { parseMarkdown as parseMarkdown9 } from "@bendyline/squisq/markdown";
33265
33013
 
33266
33014
  // src/utils/collectInlineFontAwesomeCss.ts
@@ -33340,9 +33088,9 @@ function PlainHtmlPreview({
33340
33088
  },
33341
33089
  [onFrameChange]
33342
33090
  );
33343
- const mdDoc = useMemo45(() => parseMarkdown9(markdown), [markdown]);
33344
- const [resolvedImages, setResolvedImages] = useState60(null);
33345
- useEffect50(() => {
33091
+ const mdDoc = useMemo46(() => parseMarkdown9(markdown), [markdown]);
33092
+ const [resolvedImages, setResolvedImages] = useState61(null);
33093
+ useEffect51(() => {
33346
33094
  if (!mediaProvider) {
33347
33095
  setResolvedImages(null);
33348
33096
  return;
@@ -33370,16 +33118,16 @@ function PlainHtmlPreview({
33370
33118
  cancelled = true;
33371
33119
  };
33372
33120
  }, [mdDoc, mediaProvider, mediaRevision]);
33373
- const mergedImages = useMemo45(() => {
33121
+ const mergedImages = useMemo46(() => {
33374
33122
  if (!resolvedImages && !images) return void 0;
33375
33123
  const merged = /* @__PURE__ */ new Map();
33376
33124
  if (resolvedImages) for (const [k2, v2] of resolvedImages) merged.set(k2, v2);
33377
33125
  if (images) for (const [k2, v2] of images) merged.set(k2, v2);
33378
33126
  return merged;
33379
33127
  }, [resolvedImages, images]);
33380
- const iconsCss = useMemo45(() => collectInlineFontAwesomeCss(), []);
33381
- const [renderFn, setRenderFn] = useState60(() => cachedRender);
33382
- useEffect50(() => {
33128
+ const iconsCss = useMemo46(() => collectInlineFontAwesomeCss(), []);
33129
+ const [renderFn, setRenderFn] = useState61(() => cachedRender);
33130
+ useEffect51(() => {
33383
33131
  if (renderFn) return;
33384
33132
  let cancelled = false;
33385
33133
  loadRenderFn().then((fn) => {
@@ -33389,7 +33137,7 @@ function PlainHtmlPreview({
33389
33137
  cancelled = true;
33390
33138
  };
33391
33139
  }, [renderFn]);
33392
- const html = useMemo45(
33140
+ const html = useMemo46(
33393
33141
  () => renderFn ? renderFn(mdDoc, { title, images: mergedImages, theme, iconsCss }) : "",
33394
33142
  [renderFn, mdDoc, title, mergedImages, theme, iconsCss]
33395
33143
  );
@@ -33412,7 +33160,7 @@ function PlainHtmlPreview({
33412
33160
  frameDocument.addEventListener("click", handleClick, true);
33413
33161
  removeFrameLinkHandlerRef.current = () => frameDocument.removeEventListener("click", handleClick, true);
33414
33162
  }, [onLinkClick]);
33415
- useEffect50(() => {
33163
+ useEffect51(() => {
33416
33164
  installFrameLinkHandler();
33417
33165
  return () => removeFrameLinkHandlerRef.current();
33418
33166
  }, [html, installFrameLinkHandler]);
@@ -33508,11 +33256,11 @@ function PlainHtmlPreview({
33508
33256
  style2.remove();
33509
33257
  };
33510
33258
  }, [onCopyCode, showCodeCopyButton]);
33511
- useEffect50(() => {
33259
+ useEffect51(() => {
33512
33260
  installFrameCodeCopyControls();
33513
33261
  return () => removeFrameCodeCopyControlsRef.current();
33514
33262
  }, [html, installFrameCodeCopyControls]);
33515
- useEffect50(() => {
33263
+ useEffect51(() => {
33516
33264
  if (!globalKeyboardShortcuts) return;
33517
33265
  const handleKeyDown = (event) => {
33518
33266
  if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.key !== "ArrowDown" && event.key !== "ArrowUp") {
@@ -33591,7 +33339,7 @@ function collectImageRefs(doc) {
33591
33339
  }
33592
33340
 
33593
33341
  // src/PreviewPanel.tsx
33594
- import { useState as useState63, useEffect as useEffect54, useMemo as useMemo49, useCallback as useCallback49, useRef as useRef52 } from "react";
33342
+ import { useState as useState64, useEffect as useEffect55, useMemo as useMemo50, useCallback as useCallback49, useRef as useRef52 } from "react";
33595
33343
  import { createPortal as createPortal13 } from "react-dom";
33596
33344
  import { DocPlayer as DocPlayer2, LinearDocView as LinearDocView2, useMediaProvider as useMediaProvider2 } from "@bendyline/squisq-react";
33597
33345
  import { resolveTransformStyle as resolveTransformStyle2 } from "@bendyline/squisq/transform";
@@ -33730,12 +33478,12 @@ import {
33730
33478
  createContext as createContext5,
33731
33479
  useCallback as useCallback46,
33732
33480
  useContext as useContext5,
33733
- useEffect as useEffect51,
33481
+ useEffect as useEffect52,
33734
33482
  useId as useId14,
33735
33483
  useLayoutEffect as useLayoutEffect10,
33736
- useMemo as useMemo46,
33484
+ useMemo as useMemo47,
33737
33485
  useRef as useRef49,
33738
- useState as useState61
33486
+ useState as useState62
33739
33487
  } from "react";
33740
33488
  import { createPortal as createPortal12 } from "react-dom";
33741
33489
  import { jsx as jsx70, jsxs as jsxs54 } from "react/jsx-runtime";
@@ -33752,6 +33500,25 @@ function usePresentationModeOptional() {
33752
33500
  }
33753
33501
  var POPUP_WIDTH = 1280;
33754
33502
  var POPUP_HEIGHT = 720;
33503
+ var FULLSCREEN_RELEASE_TIMEOUT_MS = 4e3;
33504
+ function waitForFullscreenRelease(ownerDocument, root, timeoutMs) {
33505
+ if (ownerDocument.fullscreenElement !== root) return Promise.resolve(true);
33506
+ return new Promise((resolve) => {
33507
+ const settle = (released) => {
33508
+ ownerDocument.removeEventListener("fullscreenchange", handleChange);
33509
+ window.clearTimeout(timer);
33510
+ resolve(released);
33511
+ };
33512
+ const handleChange = () => {
33513
+ if (ownerDocument.fullscreenElement !== root) settle(true);
33514
+ };
33515
+ const timer = window.setTimeout(
33516
+ () => settle(ownerDocument.fullscreenElement !== root),
33517
+ timeoutMs
33518
+ );
33519
+ ownerDocument.addEventListener("fullscreenchange", handleChange);
33520
+ });
33521
+ }
33755
33522
  function copyDocumentStyles(source, target) {
33756
33523
  for (const sheet of Array.from(source.styleSheets)) {
33757
33524
  if (sheet.href) {
@@ -33818,10 +33585,10 @@ function PresentationModeProvider({
33818
33585
  const { activeView, colorScheme, doc } = useEditorContext();
33819
33586
  const { activeTheme } = usePreviewSettings();
33820
33587
  const popupNameId = useId14().replace(/[^a-zA-Z0-9_-]/g, "");
33821
- const [selectedTarget, setSelectedTarget] = useState61("control");
33822
- const [activeTarget, setActiveTarget] = useState61(null);
33823
- const [popupRoot, setPopupRoot] = useState61(null);
33824
- const [error, setError] = useState61(null);
33588
+ const [selectedTarget, setSelectedTarget] = useState62("control");
33589
+ const [activeTarget, setActiveTarget] = useState62(null);
33590
+ const [popupRoot, setPopupRoot] = useState62(null);
33591
+ const [error, setError] = useState62(null);
33825
33592
  const activeTargetRef = useRef49(activeTarget);
33826
33593
  activeTargetRef.current = activeTarget;
33827
33594
  const previousActiveTargetRef = useRef49(null);
@@ -33829,7 +33596,7 @@ function PresentationModeProvider({
33829
33596
  const popupRef = useRef49(null);
33830
33597
  const popupCleanupRef = useRef49(null);
33831
33598
  const fullscreenSupported = typeof document !== "undefined" && typeof document.documentElement.requestFullscreen === "function";
33832
- const availableTargets = useMemo46(
33599
+ const availableTargets = useMemo47(
33833
33600
  () => [
33834
33601
  "control",
33835
33602
  ...allowWindow ? ["window"] : [],
@@ -33869,7 +33636,12 @@ function PresentationModeProvider({
33869
33636
  return;
33870
33637
  }
33871
33638
  }
33872
- if (ownerDocument.fullscreenElement === root) {
33639
+ const released = await waitForFullscreenRelease(
33640
+ ownerDocument,
33641
+ root,
33642
+ FULLSCREEN_RELEASE_TIMEOUT_MS
33643
+ );
33644
+ if (!released) {
33873
33645
  setError("Still in full screen. Press Escape to leave it.");
33874
33646
  return;
33875
33647
  }
@@ -33964,12 +33736,12 @@ function PresentationModeProvider({
33964
33736
  },
33965
33737
  [availableTargets, selectedTarget, stop]
33966
33738
  );
33967
- useEffect51(() => {
33739
+ useEffect52(() => {
33968
33740
  if (availableTargets.includes(selectedTarget)) return;
33969
33741
  setSelectedTarget("control");
33970
33742
  if (activeTargetRef.current !== null) void stop();
33971
33743
  }, [availableTargets, selectedTarget, stop]);
33972
- useEffect51(() => {
33744
+ useEffect52(() => {
33973
33745
  const root = rootRef.current;
33974
33746
  const ownerDocument = root?.ownerDocument;
33975
33747
  if (!root || !ownerDocument) return;
@@ -33981,7 +33753,7 @@ function PresentationModeProvider({
33981
33753
  ownerDocument.addEventListener("fullscreenchange", handleFullscreenChange);
33982
33754
  return () => ownerDocument.removeEventListener("fullscreenchange", handleFullscreenChange);
33983
33755
  }, [rootRef]);
33984
- useEffect51(() => {
33756
+ useEffect52(() => {
33985
33757
  const root = rootRef.current;
33986
33758
  if (!root) return;
33987
33759
  if (activeTarget) root.dataset.presentationMode = activeTarget;
@@ -33990,10 +33762,10 @@ function PresentationModeProvider({
33990
33762
  delete root.dataset.presentationMode;
33991
33763
  };
33992
33764
  }, [activeTarget, rootRef]);
33993
- useEffect51(() => {
33765
+ useEffect52(() => {
33994
33766
  if (activeView !== "preview" && activeTargetRef.current !== null) void stop();
33995
33767
  }, [activeView, stop]);
33996
- useEffect51(() => {
33768
+ useEffect52(() => {
33997
33769
  const previous = previousActiveTargetRef.current;
33998
33770
  previousActiveTargetRef.current = activeTarget;
33999
33771
  if (previous === null || activeTarget !== null) return;
@@ -34001,7 +33773,7 @@ function PresentationModeProvider({
34001
33773
  returnFocusRef.current = null;
34002
33774
  if (target?.isConnected) target.focus();
34003
33775
  }, [activeTarget]);
34004
- useEffect51(() => {
33776
+ useEffect52(() => {
34005
33777
  if (activeTarget !== "control") return;
34006
33778
  const ownerDocument = rootRef.current?.ownerDocument;
34007
33779
  if (!ownerDocument) return;
@@ -34013,12 +33785,12 @@ function PresentationModeProvider({
34013
33785
  ownerDocument.addEventListener("keydown", handleKeyDown);
34014
33786
  return () => ownerDocument.removeEventListener("keydown", handleKeyDown);
34015
33787
  }, [activeTarget, rootRef, stop]);
34016
- useEffect51(() => {
33788
+ useEffect52(() => {
34017
33789
  if (!error) return;
34018
33790
  const timer = window.setTimeout(() => setError(null), 6e3);
34019
33791
  return () => window.clearTimeout(timer);
34020
33792
  }, [error]);
34021
- useEffect51(
33793
+ useEffect52(
34022
33794
  () => () => {
34023
33795
  popupCleanupRef.current?.();
34024
33796
  const popup = popupRef.current;
@@ -34031,7 +33803,7 @@ function PresentationModeProvider({
34031
33803
  },
34032
33804
  [rootRef]
34033
33805
  );
34034
- const value = useMemo46(
33806
+ const value = useMemo47(
34035
33807
  () => ({
34036
33808
  selectedTarget,
34037
33809
  activeTarget,
@@ -34121,8 +33893,8 @@ function PresentationModeControl() {
34121
33893
  const { colorScheme } = useEditorContext();
34122
33894
  const triggerRef = useRef49(null);
34123
33895
  const menuRef = useRef49(null);
34124
- const [open, setOpen] = useState61(false);
34125
- const [anchor, setAnchor] = useState61(null);
33896
+ const [open, setOpen] = useState62(false);
33897
+ const [anchor, setAnchor] = useState62(null);
34126
33898
  const options = PRESENTATION_OPTIONS.filter((option) => availableTargets.includes(option.target));
34127
33899
  const selected = options.find((option) => option.target === selectedTarget) ?? PRESENTATION_OPTIONS[0];
34128
33900
  const updatePosition = useCallback46(() => {
@@ -34147,7 +33919,7 @@ function PresentationModeControl() {
34147
33919
  updatePosition();
34148
33920
  setOpen(true);
34149
33921
  }, [updatePosition]);
34150
- useEffect51(() => {
33922
+ useEffect52(() => {
34151
33923
  if (!open) return;
34152
33924
  const handlePointerDown = (event) => {
34153
33925
  const target = event.target;
@@ -34290,10 +34062,10 @@ import {
34290
34062
  createContext as createContext6,
34291
34063
  useCallback as useCallback47,
34292
34064
  useContext as useContext6,
34293
- useEffect as useEffect52,
34294
- useMemo as useMemo47,
34065
+ useEffect as useEffect53,
34066
+ useMemo as useMemo48,
34295
34067
  useRef as useRef50,
34296
- useState as useState62
34068
+ useState as useState63
34297
34069
  } from "react";
34298
34070
  import { jsx as jsx71, jsxs as jsxs55 } from "react/jsx-runtime";
34299
34071
  var PrintModeContext = createContext6(null);
@@ -34308,8 +34080,8 @@ function usePrintModeOptional() {
34308
34080
  function PrintModeProvider({ rootRef, children }) {
34309
34081
  const { activeView } = useEditorContext();
34310
34082
  const { activeTarget: presentationTarget, stop: stopPresentation } = usePresentationMode();
34311
- const [active, setActive] = useState62(false);
34312
- const [slidesPerPage, setSlidesPerPage] = useState62(1);
34083
+ const [active, setActive] = useState63(false);
34084
+ const [slidesPerPage, setSlidesPerPage] = useState63(1);
34313
34085
  const customPrintHandlerRef = useRef50(null);
34314
34086
  const printAncestorsRef = useRef50([]);
34315
34087
  const unmarkPrinting = useCallback47(() => {
@@ -34360,7 +34132,7 @@ function PrintModeProvider({ rootRef, children }) {
34360
34132
  markPrinting();
34361
34133
  ownerWindow.print();
34362
34134
  }, [markPrinting, rootRef]);
34363
- useEffect52(() => {
34135
+ useEffect53(() => {
34364
34136
  const root = rootRef.current;
34365
34137
  if (!root) return;
34366
34138
  if (active) root.dataset.printPreview = "true";
@@ -34369,10 +34141,10 @@ function PrintModeProvider({ rootRef, children }) {
34369
34141
  delete root.dataset.printPreview;
34370
34142
  };
34371
34143
  }, [active, rootRef]);
34372
- useEffect52(() => {
34144
+ useEffect53(() => {
34373
34145
  if (activeView !== "preview" && active) close();
34374
34146
  }, [active, activeView, close]);
34375
- useEffect52(() => {
34147
+ useEffect53(() => {
34376
34148
  if (!active) return;
34377
34149
  const ownerWindow = rootRef.current?.ownerDocument.defaultView;
34378
34150
  const ownerDocument = rootRef.current?.ownerDocument;
@@ -34394,7 +34166,7 @@ function PrintModeProvider({ rootRef, children }) {
34394
34166
  handleAfterPrint();
34395
34167
  };
34396
34168
  }, [active, close, markPrinting, rootRef, unmarkPrinting]);
34397
- const value = useMemo47(
34169
+ const value = useMemo48(
34398
34170
  () => ({
34399
34171
  active,
34400
34172
  slidesPerPage,
@@ -34463,7 +34235,7 @@ function PrintPreviewToolbar() {
34463
34235
  }
34464
34236
 
34465
34237
  // src/print/PrintPreview.tsx
34466
- import { useCallback as useCallback48, useEffect as useEffect53, useMemo as useMemo48, useRef as useRef51 } from "react";
34238
+ import { useCallback as useCallback48, useEffect as useEffect54, useMemo as useMemo49, useRef as useRef51 } from "react";
34467
34239
  import {
34468
34240
  BlockRenderer as BlockRenderer5,
34469
34241
  LinearDocView,
@@ -34502,7 +34274,7 @@ function PrintPreview({
34502
34274
  documentFrameRef.current = frame;
34503
34275
  }, []);
34504
34276
  const { blocks } = useDocPlayback(previewDoc, 0, { viewport, theme });
34505
- const coverBlock = useMemo48(() => {
34277
+ const coverBlock = useMemo49(() => {
34506
34278
  if (!showCover || !previewDoc?.startBlock) return null;
34507
34279
  const context = createTemplateContext2(theme, 0, 1, viewport);
34508
34280
  return {
@@ -34514,7 +34286,7 @@ function PrintPreview({
34514
34286
  };
34515
34287
  }, [previewDoc?.startBlock, showCover, theme, viewport]);
34516
34288
  const isTextDocument = displayMode === "page" || displayMode === "narrate";
34517
- useEffect53(() => {
34289
+ useEffect54(() => {
34518
34290
  if (!isTextDocument) return registerPrintHandler(null);
34519
34291
  return registerPrintHandler(() => {
34520
34292
  const frameWindow = documentFrameRef.current?.contentWindow;
@@ -34641,7 +34413,7 @@ function PreviewPanel({
34641
34413
  } = usePreviewSettings();
34642
34414
  const mainSurfaceRef = useRef52(null);
34643
34415
  const popupSurfaceRef = useRef52(null);
34644
- const [playbackState, setPlaybackState] = useState63(null);
34416
+ const [playbackState, setPlaybackState] = useState64(null);
34645
34417
  const handlePlaybackStateChange = useCallback49((next) => {
34646
34418
  setPlaybackState(next);
34647
34419
  }, []);
@@ -34653,7 +34425,7 @@ function PreviewPanel({
34653
34425
  );
34654
34426
  const previewDoc = previewProjection?.playerDoc ?? null;
34655
34427
  const contentDoc = previewProjection?.contentDoc ?? null;
34656
- const followerAudioController = useMemo49(() => {
34428
+ const followerAudioController = useMemo50(() => {
34657
34429
  if (!playbackState || !previewDoc) return null;
34658
34430
  const noOp = () => Promise.resolve();
34659
34431
  return {
@@ -34672,18 +34444,18 @@ function PreviewPanel({
34672
34444
  restart: noOp
34673
34445
  };
34674
34446
  }, [playbackState, previewDoc]);
34675
- const documentMarkdown = useMemo49(
34447
+ const documentMarkdown = useMemo50(
34676
34448
  () => activeTransformStyle && contentDoc ? buildDocumentPreviewMarkdown(contentDoc) : markdownSource,
34677
34449
  [activeTransformStyle, contentDoc, markdownSource]
34678
34450
  );
34679
34451
  const isDocumentMode = activeDisplayMode === "page";
34680
34452
  const isPageMode = activeDisplayMode === "linear";
34681
34453
  const isNarrateMode = activeDisplayMode === "narrate";
34682
- useEffect54(() => {
34454
+ useEffect55(() => {
34683
34455
  if (presentation?.activeTarget === "window") return;
34684
34456
  setPlaybackState(null);
34685
34457
  }, [presentation?.activeTarget]);
34686
- useEffect54(() => {
34458
+ useEffect55(() => {
34687
34459
  if (presentation?.activeTarget !== "window" || !presentation.popupRoot) return;
34688
34460
  const mainRoot = mainSurfaceRef.current;
34689
34461
  const followerRoot = popupSurfaceRef.current;
@@ -34917,7 +34689,7 @@ function PreviewPanel({
34917
34689
  }
34918
34690
 
34919
34691
  // src/MediaBin.tsx
34920
- import { useState as useState64, useEffect as useEffect55, useRef as useRef53, useCallback as useCallback50 } from "react";
34692
+ import { useState as useState65, useEffect as useEffect56, useRef as useRef53, useCallback as useCallback50 } from "react";
34921
34693
  import { jsx as jsx74, jsxs as jsxs58 } from "react/jsx-runtime";
34922
34694
  function formatSize(bytes) {
34923
34695
  if (bytes < 1024) return `${bytes} B`;
@@ -34982,12 +34754,12 @@ function MediaBin({
34982
34754
  isRecorderOpen = false,
34983
34755
  allowBinaryDownloads = true
34984
34756
  }) {
34985
- const [entries, setEntries] = useState64([]);
34986
- const [thumbUrls, setThumbUrls] = useState64({});
34987
- const [loading, setLoading] = useState64(false);
34988
- const [isDropActive, setIsDropActive] = useState64(false);
34989
- const [downloadingPath, setDownloadingPath] = useState64(null);
34990
- const [contextMenu, setContextMenu] = useState64(null);
34757
+ const [entries, setEntries] = useState65([]);
34758
+ const [thumbUrls, setThumbUrls] = useState65({});
34759
+ const [loading, setLoading] = useState65(false);
34760
+ const [isDropActive, setIsDropActive] = useState65(false);
34761
+ const [downloadingPath, setDownloadingPath] = useState65(null);
34762
+ const [contextMenu, setContextMenu] = useState65(null);
34991
34763
  const fileInputRef = useRef53(null);
34992
34764
  const contextMenuRef = useRef53(null);
34993
34765
  const dropDepthRef = useRef53(0);
@@ -35009,7 +34781,7 @@ function MediaBin({
35009
34781
  },
35010
34782
  [onCountChange]
35011
34783
  );
35012
- useEffect55(() => {
34784
+ useEffect56(() => {
35013
34785
  if (!contextMenu) return;
35014
34786
  const handlePointerDown = (event) => {
35015
34787
  if (contextMenuRef.current?.contains(event.target)) return;
@@ -35030,7 +34802,7 @@ function MediaBin({
35030
34802
  window.removeEventListener("resize", close);
35031
34803
  };
35032
34804
  }, [contextMenu]);
35033
- useEffect55(() => {
34805
+ useEffect56(() => {
35034
34806
  if (!mediaProvider) {
35035
34807
  setEntries([]);
35036
34808
  setThumbUrls({});
@@ -35372,7 +35144,7 @@ ${formatSize(entry.size)}`,
35372
35144
  }
35373
35145
 
35374
35146
  // src/DropZoneOverlay.tsx
35375
- import { useState as useState65 } from "react";
35147
+ import { useState as useState66 } from "react";
35376
35148
  import { Fragment as Fragment21, jsx as jsx75, jsxs as jsxs59 } from "react/jsx-runtime";
35377
35149
  function DropZoneOverlay({
35378
35150
  dragContentType,
@@ -35429,7 +35201,7 @@ function DropZone({
35429
35201
  disabled,
35430
35202
  variant
35431
35203
  }) {
35432
- const [isHovering, setIsHovering] = useState65(false);
35204
+ const [isHovering, setIsHovering] = useState66(false);
35433
35205
  const props = zoneProps(target);
35434
35206
  return /* @__PURE__ */ jsxs59(
35435
35207
  "div",
@@ -35473,7 +35245,7 @@ function DropZone({
35473
35245
  }
35474
35246
 
35475
35247
  // src/Tooltip.tsx
35476
- import { useEffect as useEffect56, useLayoutEffect as useLayoutEffect11, useRef as useRef54, useState as useState66 } from "react";
35248
+ import { useEffect as useEffect57, useLayoutEffect as useLayoutEffect11, useRef as useRef54, useState as useState67 } from "react";
35477
35249
  import { createPortal as createPortal14 } from "react-dom";
35478
35250
 
35479
35251
  // src/tooltipPlacement.ts
@@ -35489,7 +35261,7 @@ function clampTooltipLeft(anchorX, tooltipWidth, viewportWidth, edgePadding = ED
35489
35261
  import { jsx as jsx76 } from "react/jsx-runtime";
35490
35262
  var SHOW_DELAY_MS = 180;
35491
35263
  function TooltipLayer() {
35492
- const [state, setState3] = useState66(null);
35264
+ const [state, setState3] = useState67(null);
35493
35265
  const tooltipRef = useRef54(null);
35494
35266
  const timerRef = useRef54(null);
35495
35267
  const currentTargetRef = useRef54(null);
@@ -35505,7 +35277,7 @@ function TooltipLayer() {
35505
35277
  node2.style.left = `${left}px`;
35506
35278
  node2.style.visibility = "visible";
35507
35279
  }, [state]);
35508
- useEffect56(() => {
35280
+ useEffect57(() => {
35509
35281
  const clearTimer = () => {
35510
35282
  if (timerRef.current) {
35511
35283
  clearTimeout(timerRef.current);
@@ -35591,10 +35363,10 @@ function TooltipLayer() {
35591
35363
  }
35592
35364
 
35593
35365
  // src/EditorShell.tsx
35594
- import { useEffect as useEffect57, useRef as useRef55, useState as useState67, useCallback as useCallback51, useMemo as useMemo51 } from "react";
35366
+ import { useEffect as useEffect58, useRef as useRef55, useState as useState68, useCallback as useCallback51, useMemo as useMemo52 } from "react";
35595
35367
 
35596
35368
  // src/BlockPreviewPanel.tsx
35597
- import { useMemo as useMemo50 } from "react";
35369
+ import { useMemo as useMemo51 } from "react";
35598
35370
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS7 } from "@bendyline/squisq/schemas";
35599
35371
  import { flattenBlocks as flattenBlocks7, DEFAULT_THEME as DEFAULT_THEME7 } from "@bendyline/squisq/doc";
35600
35372
  import { jsx as jsx77 } from "react/jsx-runtime";
@@ -35603,13 +35375,13 @@ function BlockPreviewPanel({ basePath = "/" }) {
35603
35375
  const previewSettings = usePreviewSettingsOptional();
35604
35376
  const theme = previewSettings?.activeTheme ?? DEFAULT_THEME7;
35605
35377
  const viewport = previewSettings?.activeViewport ?? VIEWPORT_PRESETS7.landscape;
35606
- const block = useMemo50(() => {
35378
+ const block = useMemo51(() => {
35607
35379
  if (!doc) return null;
35608
35380
  const blocks = flattenBlocks7(doc.blocks);
35609
35381
  if (blocks.length === 0) return null;
35610
35382
  return blocks.find((b) => b.sourceHeading?.position?.start.line === activeBlockStartLine) ?? blocks[0];
35611
35383
  }, [doc, activeBlockStartLine]);
35612
- const visual = useMemo50(
35384
+ const visual = useMemo51(
35613
35385
  () => doc && block ? resolveBlockVisual(doc, block, theme, viewport) : null,
35614
35386
  [doc, block, theme, viewport]
35615
35387
  );
@@ -35947,7 +35719,7 @@ function EditorShell({
35947
35719
  themeOverride = null
35948
35720
  }) {
35949
35721
  const effectiveContainer = workspaceContainer ?? null;
35950
- const effectiveMediaProvider = useMemo51(() => {
35722
+ const effectiveMediaProvider = useMemo52(() => {
35951
35723
  if (mediaProvider !== void 0) return mediaProvider;
35952
35724
  if (effectiveContainer) return createMediaProviderFromContainer(effectiveContainer);
35953
35725
  return void 0;
@@ -36149,7 +35921,7 @@ function EditorShellInner({
36149
35921
  workspaceContainer
36150
35922
  );
36151
35923
  const timelineDoc = timelineProjection?.contentDoc ?? doc;
36152
- const timelineRawSchedule = useMemo51(
35924
+ const timelineRawSchedule = useMemo52(
36153
35925
  () => timelineDoc ? resolveMediaSchedule4(timelineDoc) : [],
36154
35926
  [timelineDoc]
36155
35927
  );
@@ -36158,19 +35930,19 @@ function EditorShellInner({
36158
35930
  basePath,
36159
35931
  mediaProvider ?? null
36160
35932
  );
36161
- const timelineDuration = useMemo51(
35933
+ const timelineDuration = useMemo52(
36162
35934
  () => timelineDoc ? getDocPlaybackDuration3(timelineDoc, {
36163
35935
  intrinsicDuration: (clip) => timelineClipDurations.get(clip.src)
36164
35936
  }) : 0,
36165
35937
  [timelineDoc, timelineClipDurations]
36166
35938
  );
36167
- const timelineSchedule = useMemo51(
35939
+ const timelineSchedule = useMemo52(
36168
35940
  () => timelineDoc ? resolveMediaSchedule4(timelineDoc, {
36169
35941
  intrinsicDuration: (clip) => timelineClipDurations.get(clip.src)
36170
35942
  }) : [],
36171
35943
  [timelineDoc, timelineClipDurations]
36172
35944
  );
36173
- const timelineVideoSchedule = useMemo51(
35945
+ const timelineVideoSchedule = useMemo52(
36174
35946
  () => timelineDoc ? [
36175
35947
  ...timelineSchedule.filter((clip) => clip.kind === "video"),
36176
35948
  ...collectEmbeddedVideoSchedule(timelineDoc)
@@ -36179,15 +35951,15 @@ function EditorShellInner({
36179
35951
  );
36180
35952
  const timelineClock = useTimelineClock(isTimelineMode ? timelineDuration : 0);
36181
35953
  const hasTimelineVideo = timelineVideoSchedule.length > 0;
36182
- const [timelineVideoVisible, setTimelineVideoVisible] = useState67(false);
36183
- const [timelineCompositionVisible, setTimelineCompositionVisible] = useState67(false);
35954
+ const [timelineVideoVisible, setTimelineVideoVisible] = useState68(false);
35955
+ const [timelineCompositionVisible, setTimelineCompositionVisible] = useState68(false);
36184
35956
  const timelinePreviewCount = Number(timelineVideoVisible) + Number(timelineCompositionVisible);
36185
- const [showFiles, setShowFiles] = useState67(false);
36186
- const [mediaRefreshKey, setMediaRefreshKey] = useState67(0);
36187
- const [mediaCount, setMediaCount] = useState67(0);
36188
- const [mediaBinRecorderOpen, setMediaBinRecorderOpen] = useState67(false);
35957
+ const [showFiles, setShowFiles] = useState68(false);
35958
+ const [mediaRefreshKey, setMediaRefreshKey] = useState68(0);
35959
+ const [mediaCount, setMediaCount] = useState68(0);
35960
+ const [mediaBinRecorderOpen, setMediaBinRecorderOpen] = useState68(false);
36189
35961
  const mediaListRefreshKey = mediaRefreshKey + mediaRevision;
36190
- const usedMediaPaths = useMemo51(
35962
+ const usedMediaPaths = useMemo52(
36191
35963
  () => collectMediaReferencesFromMarkdown(markdownSource),
36192
35964
  [markdownSource]
36193
35965
  );
@@ -36197,13 +35969,13 @@ function EditorShellInner({
36197
35969
  }
36198
35970
  const imageEditFallbackContainer = imageEditFallbackContainerRef.current;
36199
35971
  const isDark = colorScheme === "dark";
36200
- useEffect57(() => {
35972
+ useEffect58(() => {
36201
35973
  if (!isTimelineMode || !hasTimelineVideo) setTimelineVideoVisible(false);
36202
35974
  }, [isTimelineMode, hasTimelineVideo]);
36203
- useEffect57(() => {
35975
+ useEffect58(() => {
36204
35976
  if (!isTimelineMode || !doc?.blocks.length) setTimelineCompositionVisible(false);
36205
35977
  }, [isTimelineMode, doc]);
36206
- useEffect57(() => {
35978
+ useEffect58(() => {
36207
35979
  if (!mediaProvider) {
36208
35980
  setMediaCount(0);
36209
35981
  return;
@@ -36312,7 +36084,7 @@ ${snippet}` : snippet);
36312
36084
  onDrop: handleFileDrop,
36313
36085
  enabled: !readOnly
36314
36086
  });
36315
- useEffect57(() => {
36087
+ useEffect58(() => {
36316
36088
  onChange?.(markdownSource);
36317
36089
  }, [markdownSource, onChange]);
36318
36090
  const handleShellKeyDown = useCallback51(
@@ -36667,7 +36439,7 @@ function ImageEditModal({
36667
36439
  useModalDialog({ rootRef: modalRef, dialogRef: surfaceRef, onClose });
36668
36440
  const extension = relativePath.split(/[?#]/, 1)[0]?.split(".").pop()?.toLowerCase();
36669
36441
  const saveFormat = extension === "png" ? "png" : extension === "jpg" || extension === "jpeg" ? "jpeg" : extension === "webp" ? "webp" : null;
36670
- const sidecar = useMemo51(() => {
36442
+ const sidecar = useMemo52(() => {
36671
36443
  const sanitized = relativePath.replace(/[^a-zA-Z0-9._-]+/g, "_");
36672
36444
  let hash = 2166136261;
36673
36445
  for (let i = 0; i < relativePath.length; i++) {
@@ -36678,9 +36450,9 @@ function ImageEditModal({
36678
36450
  const parent = container ?? new MemoryContentContainer();
36679
36451
  return scopeContainer(parent, `.imageEdits/${scopedName}`);
36680
36452
  }, [container, relativePath]);
36681
- const [initialSrc, setInitialSrc] = useState67(null);
36682
- const [resolveError, setResolveError] = useState67(null);
36683
- useEffect57(() => {
36453
+ const [initialSrc, setInitialSrc] = useState68(null);
36454
+ const [resolveError, setResolveError] = useState68(null);
36455
+ useEffect58(() => {
36684
36456
  let cancelled = false;
36685
36457
  setInitialSrc(null);
36686
36458
  setResolveError(null);
@@ -36885,6 +36657,10 @@ export {
36885
36657
  renderMermaidDiagram,
36886
36658
  inspectMermaidSource,
36887
36659
  mermaidErrorMessage,
36660
+ mermaidSurfaceScheme,
36661
+ adaptThemeToSurface,
36662
+ resolveMermaidSurfaceTheme,
36663
+ useMermaidSurfaceTheme,
36888
36664
  MermaidDiagramCanvas,
36889
36665
  MermaidShapePalette,
36890
36666
  useMermaidDiagramData,
@@ -36941,8 +36717,8 @@ export {
36941
36717
  persistFromWrite,
36942
36718
  WysiwygEditor,
36943
36719
  InlinePreviewGutter,
36944
- documentTitleFromFileName,
36945
36720
  buildPreviewDoc,
36721
+ documentTitleFromFileName,
36946
36722
  OutlinePanel,
36947
36723
  CodeContextZones,
36948
36724
  BlockCardView,