@bendyline/squisq-editor-react 1.5.2 → 1.5.3

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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/EditorShell.tsx
2
- import { useEffect as useEffect31, useRef as useRef26, useState as useState33, useCallback as useCallback23, useMemo as useMemo16 } from "react";
2
+ import { useEffect as useEffect32, useRef as useRef26, useState as useState34, useCallback as useCallback23, useMemo as useMemo16 } from "react";
3
3
 
4
4
  // src/EditorContext.tsx
5
5
  import {
@@ -1694,12 +1694,83 @@ function EditorProvider({
1694
1694
  }
1695
1695
 
1696
1696
  // src/Toolbar.tsx
1697
- import { useCallback as useCallback11, useEffect as useEffect12, useMemo as useMemo6, useReducer, useRef as useRef11, useState as useState12 } from "react";
1697
+ import { useCallback as useCallback11, useEffect as useEffect13, useMemo as useMemo6, useReducer, useRef as useRef11, useState as useState13 } from "react";
1698
1698
 
1699
1699
  // src/VersionHistoryPanel.tsx
1700
- import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState3 } from "react";
1700
+ import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
1701
1701
  import { DiffEditor } from "@monaco-editor/react";
1702
+
1703
+ // src/useMonacoLoader.ts
1704
+ import { useEffect as useEffect3, useState as useState3 } from "react";
1705
+ import { loader } from "@monaco-editor/react";
1706
+ var monacoPromise = null;
1707
+ var monacoNamespace = null;
1708
+ function useMonacoLoader() {
1709
+ const [state, setState] = useState3(() => ({
1710
+ monaco: monacoNamespace,
1711
+ ready: monacoNamespace !== null
1712
+ }));
1713
+ useEffect3(() => {
1714
+ if (state.ready) return;
1715
+ if (!monacoPromise) {
1716
+ monacoPromise = import("monaco-editor/esm/vs/editor/editor.api.js").then((m) => {
1717
+ loader.config({ monaco: m });
1718
+ monacoNamespace = m;
1719
+ return m;
1720
+ });
1721
+ }
1722
+ let cancelled = false;
1723
+ void monacoPromise.then((m) => {
1724
+ if (cancelled) return;
1725
+ setState({ monaco: m, ready: true });
1726
+ });
1727
+ return () => {
1728
+ cancelled = true;
1729
+ };
1730
+ }, [state.ready]);
1731
+ return state;
1732
+ }
1733
+
1734
+ // src/VersionHistoryPanel.tsx
1702
1735
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1736
+ var lazyLoadingStyle = {
1737
+ display: "flex",
1738
+ alignItems: "center",
1739
+ justifyContent: "center",
1740
+ width: "100%",
1741
+ height: "100%",
1742
+ color: "var(--squisq-editor-muted-foreground, #6a6258)",
1743
+ fontSize: 12
1744
+ };
1745
+ function LazyDiffEditor({ original, modified, theme }) {
1746
+ const { ready } = useMonacoLoader();
1747
+ if (!ready) {
1748
+ return /* @__PURE__ */ jsx3("div", { style: lazyLoadingStyle, children: "Loading diff\u2026" });
1749
+ }
1750
+ return /* @__PURE__ */ jsx3(
1751
+ DiffEditor,
1752
+ {
1753
+ original,
1754
+ modified,
1755
+ language: "markdown",
1756
+ theme,
1757
+ options: {
1758
+ readOnly: true,
1759
+ renderSideBySide: true,
1760
+ minimap: { enabled: false },
1761
+ scrollBeyondLastLine: false,
1762
+ wordWrap: "on",
1763
+ automaticLayout: true,
1764
+ fontSize: 12,
1765
+ lineNumbers: "off",
1766
+ glyphMargin: false,
1767
+ folding: false,
1768
+ overviewRulerLanes: 0,
1769
+ renderOverviewRuler: false
1770
+ }
1771
+ }
1772
+ );
1773
+ }
1703
1774
  var initialState = {
1704
1775
  loading: false,
1705
1776
  versions: [],
@@ -1720,8 +1791,8 @@ function formatBytes(n) {
1720
1791
  }
1721
1792
  function VersionHistoryPanel() {
1722
1793
  const { versioning, replaceAll, markdownSource, theme } = useEditorContext();
1723
- const [open, setOpen] = useState3(false);
1724
- const [state, setState] = useState3(initialState);
1794
+ const [open, setOpen] = useState4(false);
1795
+ const [state, setState] = useState4(initialState);
1725
1796
  const containerRef = useRef3(null);
1726
1797
  const refresh = useCallback2(async () => {
1727
1798
  if (!versioning) return;
@@ -1736,7 +1807,7 @@ function VersionHistoryPanel() {
1736
1807
  setState((s) => ({ ...s, loading: false, error: message }));
1737
1808
  }
1738
1809
  }, [versioning]);
1739
- useEffect3(() => {
1810
+ useEffect4(() => {
1740
1811
  if (open) {
1741
1812
  setState((s) => ({ ...s, currentStamp: /* @__PURE__ */ new Date() }));
1742
1813
  void refresh();
@@ -1744,7 +1815,7 @@ function VersionHistoryPanel() {
1744
1815
  setState((s) => ({ ...s, selected: null, pendingRevert: null }));
1745
1816
  }
1746
1817
  }, [open, refresh]);
1747
- useEffect3(() => {
1818
+ useEffect4(() => {
1748
1819
  if (!open) return;
1749
1820
  const handler = (e2) => {
1750
1821
  if (containerRef.current && !containerRef.current.contains(e2.target)) {
@@ -1851,26 +1922,11 @@ function VersionHistoryPanel() {
1851
1922
  /* @__PURE__ */ jsx3("span", { className: "squisq-version-history-diff-label", children: /* @__PURE__ */ jsx3("strong", { children: "Current" }) })
1852
1923
  ] }),
1853
1924
  /* @__PURE__ */ jsx3("div", { className: "squisq-version-history-diff-body", children: /* @__PURE__ */ jsx3(
1854
- DiffEditor,
1925
+ LazyDiffEditor,
1855
1926
  {
1856
1927
  original: state.selected.content,
1857
1928
  modified: markdownSource,
1858
- language: "markdown",
1859
- theme: diffTheme,
1860
- options: {
1861
- readOnly: true,
1862
- renderSideBySide: true,
1863
- minimap: { enabled: false },
1864
- scrollBeyondLastLine: false,
1865
- wordWrap: "on",
1866
- automaticLayout: true,
1867
- fontSize: 12,
1868
- lineNumbers: "off",
1869
- glyphMargin: false,
1870
- folding: false,
1871
- overviewRulerLanes: 0,
1872
- renderOverviewRuler: false
1873
- }
1929
+ theme: diffTheme
1874
1930
  }
1875
1931
  ) })
1876
1932
  ] }),
@@ -1969,14 +2025,14 @@ function VersionHistoryPanel() {
1969
2025
  import { useCallback as useCallback6 } from "react";
1970
2026
 
1971
2027
  // src/recorder/RecorderPanel.tsx
1972
- import { useCallback as useCallback5, useState as useState6 } from "react";
2028
+ import { useCallback as useCallback5, useState as useState7 } from "react";
1973
2029
  import { createPortal as createPortal2 } from "react-dom";
1974
2030
 
1975
2031
  // src/recorder/RecorderModal.tsx
1976
- import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef5, useState as useState5 } from "react";
2032
+ import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef5, useState as useState6 } from "react";
1977
2033
 
1978
2034
  // src/recorder/hooks/useMediaRecorder.ts
1979
- import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
2035
+ import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
1980
2036
 
1981
2037
  // src/recorder/formats.ts
1982
2038
  var AUDIO_CANDIDATES = [
@@ -2170,12 +2226,12 @@ function getCaptureKind(source) {
2170
2226
  return captureKindFor(source);
2171
2227
  }
2172
2228
  function useMediaRecorder(options) {
2173
- const [state, setState] = useState4("idle");
2174
- const [stream, setStream] = useState4(null);
2175
- const [blob, setBlob] = useState4(null);
2176
- const [format, setFormat] = useState4(null);
2177
- const [durationMs, setDurationMs] = useState4(0);
2178
- const [error, setError] = useState4(null);
2229
+ const [state, setState] = useState5("idle");
2230
+ const [stream, setStream] = useState5(null);
2231
+ const [blob, setBlob] = useState5(null);
2232
+ const [format, setFormat] = useState5(null);
2233
+ const [durationMs, setDurationMs] = useState5(0);
2234
+ const [error, setError] = useState5(null);
2179
2235
  const recorderRef = useRef4(null);
2180
2236
  const chunksRef = useRef4([]);
2181
2237
  const disposeStreamRef = useRef4(null);
@@ -2334,7 +2390,8 @@ function useMediaRecorder(options) {
2334
2390
  }
2335
2391
  });
2336
2392
  }, [blob, clearTicker]);
2337
- useEffect4(() => {
2393
+ useEffect5(() => {
2394
+ const pendingResolvers = stopResolversRef.current;
2338
2395
  return () => {
2339
2396
  const rec = recorderRef.current;
2340
2397
  if (rec && rec.state !== "inactive") {
@@ -2345,7 +2402,7 @@ function useMediaRecorder(options) {
2345
2402
  }
2346
2403
  releaseStream();
2347
2404
  clearTicker();
2348
- stopResolversRef.current.splice(0).forEach((resolve) => resolve(null));
2405
+ pendingResolvers.splice(0).forEach((resolve) => resolve(null));
2349
2406
  };
2350
2407
  }, [releaseStream, clearTicker]);
2351
2408
  return {
@@ -2366,9 +2423,9 @@ function useMediaRecorder(options) {
2366
2423
  }
2367
2424
 
2368
2425
  // src/recorder/hooks/useStreamPreview.ts
2369
- import { useEffect as useEffect5 } from "react";
2426
+ import { useEffect as useEffect6 } from "react";
2370
2427
  function useStreamPreview(ref, stream) {
2371
- useEffect5(() => {
2428
+ useEffect6(() => {
2372
2429
  const el = ref.current;
2373
2430
  if (!el) return;
2374
2431
  el.muted = true;
@@ -2572,20 +2629,20 @@ function RecorderModal({
2572
2629
  onClose,
2573
2630
  onSave
2574
2631
  }) {
2575
- const [source, setSource] = useState5(initialMode);
2576
- const [sourceText, setSourceText] = useState5("");
2577
- const [basename, setBasename] = useState5("");
2578
- const [includeSystemAudio, setIncludeSystemAudio] = useState5(false);
2579
- const [isSaving, setIsSaving] = useState5(false);
2580
- const [saveError, setSaveError] = useState5(null);
2581
- const [playbackUrl, setPlaybackUrl] = useState5(null);
2632
+ const [source, setSource] = useState6(initialMode);
2633
+ const [sourceText, setSourceText] = useState6("");
2634
+ const [basename, setBasename] = useState6("");
2635
+ const [includeSystemAudio, setIncludeSystemAudio] = useState6(false);
2636
+ const [isSaving, setIsSaving] = useState6(false);
2637
+ const [saveError, setSaveError] = useState6(null);
2638
+ const [playbackUrl, setPlaybackUrl] = useState6(null);
2582
2639
  const previewRef = useRef5(null);
2583
2640
  const recorder = useMediaRecorder({
2584
2641
  source,
2585
2642
  systemAudio: source === "screen" || source === "screen+mic" ? includeSystemAudio : false
2586
2643
  });
2587
2644
  useStreamPreview(previewRef, recorder.state === "stopped" ? null : recorder.stream);
2588
- useEffect6(() => {
2645
+ useEffect7(() => {
2589
2646
  if (!recorder.blob) {
2590
2647
  setPlaybackUrl(null);
2591
2648
  return;
@@ -2597,7 +2654,7 @@ function RecorderModal({
2597
2654
  };
2598
2655
  }, [recorder.blob]);
2599
2656
  const previousSourceRef = useRef5(source);
2600
- useEffect6(() => {
2657
+ useEffect7(() => {
2601
2658
  if (previousSourceRef.current !== source) {
2602
2659
  previousSourceRef.current = source;
2603
2660
  recorder.cancel();
@@ -2852,7 +2909,7 @@ function RecorderPanel({
2852
2909
  tooltip = "Record media",
2853
2910
  className
2854
2911
  }) {
2855
- const [open, setOpen] = useState6(false);
2912
+ const [open, setOpen] = useState7(false);
2856
2913
  const handleClose = useCallback5(() => setOpen(false), []);
2857
2914
  return /* @__PURE__ */ jsxs4(Fragment2, { children: [
2858
2915
  /* @__PURE__ */ jsx5(
@@ -2992,7 +3049,7 @@ ${videoTag}` : videoTag);
2992
3049
  }
2993
3050
 
2994
3051
  // src/ViewMenuPanel.tsx
2995
- import { useCallback as useCallback7, useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react";
3052
+ import { useCallback as useCallback7, useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
2996
3053
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2997
3054
  function ViewMenuPanel() {
2998
3055
  const {
@@ -3007,9 +3064,9 @@ function ViewMenuPanel() {
3007
3064
  themeInheritance,
3008
3065
  setThemeInheritance
3009
3066
  } = useEditorContext();
3010
- const [open, setOpen] = useState7(false);
3067
+ const [open, setOpen] = useState8(false);
3011
3068
  const containerRef = useRef6(null);
3012
- useEffect7(() => {
3069
+ useEffect8(() => {
3013
3070
  if (!open) return;
3014
3071
  const handler = (e2) => {
3015
3072
  if (containerRef.current && !containerRef.current.contains(e2.target)) {
@@ -3212,7 +3269,7 @@ function findBlockSliceByHeadingIndex(source, headingIndex) {
3212
3269
  }
3213
3270
 
3214
3271
  // src/LinkDialog.tsx
3215
- import { useCallback as useCallback8, useEffect as useEffect8, useRef as useRef7, useState as useState8 } from "react";
3272
+ import { useCallback as useCallback8, useEffect as useEffect9, useRef as useRef7, useState as useState9 } from "react";
3216
3273
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
3217
3274
  function LinkDialog({
3218
3275
  mode,
@@ -3222,21 +3279,21 @@ function LinkDialog({
3222
3279
  onClose,
3223
3280
  documentLinkProvider
3224
3281
  }) {
3225
- const [text, setText] = useState8(initialText);
3226
- const [url, setUrl] = useState8(initialUrl);
3227
- const [tab, setTab] = useState8("url");
3228
- const [docQuery, setDocQuery] = useState8("");
3229
- const [docResults, setDocResults] = useState8([]);
3230
- const [docLoading, setDocLoading] = useState8(false);
3282
+ const [text, setText] = useState9(initialText);
3283
+ const [url, setUrl] = useState9(initialUrl);
3284
+ const [tab, setTab] = useState9("url");
3285
+ const [docQuery, setDocQuery] = useState9("");
3286
+ const [docResults, setDocResults] = useState9([]);
3287
+ const [docLoading, setDocLoading] = useState9(false);
3231
3288
  const textRef = useRef7(null);
3232
3289
  const urlRef = useRef7(null);
3233
3290
  const docSearchRef = useRef7(null);
3234
- useEffect8(() => {
3291
+ useEffect9(() => {
3235
3292
  const target = initialText ? urlRef.current : textRef.current;
3236
3293
  target?.focus();
3237
3294
  target?.select();
3238
3295
  }, [initialText]);
3239
- useEffect8(() => {
3296
+ useEffect9(() => {
3240
3297
  if (!documentLinkProvider || tab !== "documents") return;
3241
3298
  let cancelled = false;
3242
3299
  setDocLoading(true);
@@ -3255,14 +3312,14 @@ function LinkDialog({
3255
3312
  cancelled = true;
3256
3313
  };
3257
3314
  }, [docQuery, documentLinkProvider, tab]);
3258
- useEffect8(() => {
3315
+ useEffect9(() => {
3259
3316
  if (tab === "documents") {
3260
3317
  const t = setTimeout(() => docSearchRef.current?.focus(), 0);
3261
3318
  return () => clearTimeout(t);
3262
3319
  }
3263
3320
  return void 0;
3264
3321
  }, [tab]);
3265
- useEffect8(() => {
3322
+ useEffect9(() => {
3266
3323
  const onKey = (e2) => {
3267
3324
  if (e2.key === "Escape") {
3268
3325
  e2.stopPropagation();
@@ -3425,7 +3482,7 @@ function LinkDialog({
3425
3482
  }
3426
3483
 
3427
3484
  // src/DocumentSettingsDialog.tsx
3428
- import { useCallback as useCallback10, useEffect as useEffect10, useMemo as useMemo4, useRef as useRef9, useState as useState10 } from "react";
3485
+ import { useCallback as useCallback10, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef9, useState as useState11 } from "react";
3429
3486
  import {
3430
3487
  inferDocumentTitle,
3431
3488
  parseMarkdown as parseMarkdown3,
@@ -3434,7 +3491,7 @@ import {
3434
3491
  import { getTransformStyleSummaries } from "@bendyline/squisq/transform";
3435
3492
 
3436
3493
  // src/ThemePicker.tsx
3437
- import { useCallback as useCallback9, useEffect as useEffect9, useMemo as useMemo3, useRef as useRef8, useState as useState9 } from "react";
3494
+ import { useCallback as useCallback9, useEffect as useEffect10, useMemo as useMemo3, useRef as useRef8, useState as useState10 } from "react";
3438
3495
  import { createPortal as createPortal3 } from "react-dom";
3439
3496
  import {
3440
3497
  getThemeSummaries,
@@ -3489,8 +3546,8 @@ function ThemePicker({
3489
3546
  variant = "compact",
3490
3547
  ariaLabel = "Theme"
3491
3548
  }) {
3492
- const [open, setOpen] = useState9(false);
3493
- const [popoverStyle, setPopoverStyle] = useState9({});
3549
+ const [open, setOpen] = useState10(false);
3550
+ const [popoverStyle, setPopoverStyle] = useState10({});
3494
3551
  const triggerRef = useRef8(null);
3495
3552
  const selectedEntry = useMemo3(() => {
3496
3553
  if (!value) return null;
@@ -3536,7 +3593,7 @@ function ThemePicker({
3536
3593
  if (!open) updatePosition();
3537
3594
  setOpen((v) => !v);
3538
3595
  };
3539
- useEffect9(() => {
3596
+ useEffect10(() => {
3540
3597
  if (!open) return;
3541
3598
  const onDown = (e2) => {
3542
3599
  const target = e2.target;
@@ -3702,16 +3759,16 @@ function DocumentSettingsDialog({
3702
3759
  const currentTheme = readFm(frontmatter, FM.theme.canonical, FM.theme.legacy);
3703
3760
  const currentTransform = readFm(frontmatter, FM.transform.canonical, FM.transform.legacy);
3704
3761
  const currentCaptions = readFm(frontmatter, FM.captions.canonical, FM.captions.legacy);
3705
- const [title, setTitle] = useState10(currentTitle);
3706
- const [theme, setTheme] = useState10(currentTheme);
3707
- const [transform, setTransform] = useState10(currentTransform);
3708
- const [captions, setCaptions] = useState10(currentCaptions);
3762
+ const [title, setTitle] = useState11(currentTitle);
3763
+ const [theme, setTheme] = useState11(currentTheme);
3764
+ const [transform, setTransform] = useState11(currentTransform);
3765
+ const [captions, setCaptions] = useState11(currentCaptions);
3709
3766
  const titleRef = useRef9(null);
3710
- useEffect10(() => {
3767
+ useEffect11(() => {
3711
3768
  titleRef.current?.focus();
3712
3769
  titleRef.current?.select();
3713
3770
  }, []);
3714
- useEffect10(() => {
3771
+ useEffect11(() => {
3715
3772
  const onKey = (e2) => {
3716
3773
  if (e2.key === "Escape") onClose();
3717
3774
  };
@@ -3863,7 +3920,7 @@ function DocumentSettingsDialog({
3863
3920
  }
3864
3921
 
3865
3922
  // src/EmojiPicker.tsx
3866
- import { useEffect as useEffect11, useMemo as useMemo5, useRef as useRef10, useState as useState11 } from "react";
3923
+ import { useEffect as useEffect12, useMemo as useMemo5, useRef as useRef10, useState as useState12 } from "react";
3867
3924
 
3868
3925
  // src/emojiData.ts
3869
3926
  import { ICONS } from "@bendyline/squisq/icons";
@@ -5172,11 +5229,11 @@ function EmojiPicker({
5172
5229
  theme = "light"
5173
5230
  }) {
5174
5231
  const palette = theme === "dark" ? DARK_PALETTE : LIGHT_PALETTE;
5175
- const [activeCategory, setActiveCategory] = useState11(PICKER_CATEGORIES[0].id);
5176
- const [query, setQuery] = useState11("");
5232
+ const [activeCategory, setActiveCategory] = useState12(PICKER_CATEGORIES[0].id);
5233
+ const [query, setQuery] = useState12("");
5177
5234
  const popoverRef = useRef10(null);
5178
5235
  const searchInputRef = useRef10(null);
5179
- useEffect11(() => {
5236
+ useEffect12(() => {
5180
5237
  if (open) {
5181
5238
  const t = setTimeout(() => searchInputRef.current?.focus(), 0);
5182
5239
  return () => clearTimeout(t);
@@ -5185,7 +5242,7 @@ function EmojiPicker({
5185
5242
  setActiveCategory(PICKER_CATEGORIES[0].id);
5186
5243
  return void 0;
5187
5244
  }, [open]);
5188
- useEffect11(() => {
5245
+ useEffect12(() => {
5189
5246
  if (!open) return;
5190
5247
  const onPointerDown = (e2) => {
5191
5248
  const target = e2.target;
@@ -5586,9 +5643,9 @@ function Toolbar({
5586
5643
  });
5587
5644
  const showViewTabs = visibleViews.length > 1;
5588
5645
  const imageInputRef = useRef11(null);
5589
- const [linkDialog, setLinkDialog] = useState12(null);
5646
+ const [linkDialog, setLinkDialog] = useState13(null);
5590
5647
  const emojiButtonRef = useRef11(null);
5591
- const [emojiPickerAnchor, setEmojiPickerAnchor] = useState12(null);
5648
+ const [emojiPickerAnchor, setEmojiPickerAnchor] = useState13(null);
5592
5649
  const openEmojiPicker = useCallback11(() => {
5593
5650
  const btn = emojiButtonRef.current;
5594
5651
  if (!btn) return;
@@ -5609,22 +5666,22 @@ function Toolbar({
5609
5666
  setEmojiPickerAnchor({ top, left });
5610
5667
  }, []);
5611
5668
  const closeEmojiPicker = useCallback11(() => setEmojiPickerAnchor(null), []);
5612
- const [isNarrow, setIsNarrow] = useState12(
5669
+ const [isNarrow, setIsNarrow] = useState13(
5613
5670
  () => typeof window !== "undefined" && window.matchMedia("(max-width: 768px)").matches
5614
5671
  );
5615
- useEffect12(() => {
5672
+ useEffect13(() => {
5616
5673
  const mq = window.matchMedia("(max-width: 768px)");
5617
5674
  const handler = (e2) => setIsNarrow(e2.matches);
5618
5675
  mq.addEventListener("change", handler);
5619
5676
  return () => mq.removeEventListener("change", handler);
5620
5677
  }, []);
5621
5678
  const actionsRef = useRef11(null);
5622
- const [measuredOverflowIndex, setMeasuredOverflowIndex] = useState12(null);
5623
- const [showOverflow, setShowOverflow] = useState12(false);
5679
+ const [measuredOverflowIndex, setMeasuredOverflowIndex] = useState13(null);
5680
+ const [showOverflow, setShowOverflow] = useState13(false);
5624
5681
  const overflowRef = useRef11(null);
5625
- const [showDocSettings, setShowDocSettings] = useState12(false);
5682
+ const [showDocSettings, setShowDocSettings] = useState13(false);
5626
5683
  const overflowIndex = isNarrow ? 0 : measuredOverflowIndex;
5627
- useEffect12(() => {
5684
+ useEffect13(() => {
5628
5685
  if (isNarrow) return;
5629
5686
  const container = actionsRef.current;
5630
5687
  if (!container) return;
@@ -5648,7 +5705,7 @@ function Toolbar({
5648
5705
  measure();
5649
5706
  return () => ro.disconnect();
5650
5707
  }, [activeView, isNarrow]);
5651
- useEffect12(() => {
5708
+ useEffect13(() => {
5652
5709
  if (!showOverflow) return;
5653
5710
  const handleClick = (e2) => {
5654
5711
  if (overflowRef.current && !overflowRef.current.contains(e2.target)) {
@@ -5658,8 +5715,8 @@ function Toolbar({
5658
5715
  document.addEventListener("mousedown", handleClick);
5659
5716
  return () => document.removeEventListener("mousedown", handleClick);
5660
5717
  }, [showOverflow]);
5661
- const [overflowPlacement, setOverflowPlacement] = useState12("down");
5662
- useEffect12(() => {
5718
+ const [overflowPlacement, setOverflowPlacement] = useState13("down");
5719
+ useEffect13(() => {
5663
5720
  if (!showOverflow || !overflowRef.current) return;
5664
5721
  const trigger = overflowRef.current.querySelector(
5665
5722
  ".squisq-toolbar-overflow-trigger"
@@ -5676,7 +5733,7 @@ function Toolbar({
5676
5733
  }
5677
5734
  }, [showOverflow]);
5678
5735
  const [, forceUpdate] = useReducer((c) => c + 1, 0);
5679
- useEffect12(() => {
5736
+ useEffect13(() => {
5680
5737
  if (!tiptapEditor) return;
5681
5738
  tiptapEditor.on("transaction", forceUpdate);
5682
5739
  return () => {
@@ -6027,7 +6084,7 @@ function Toolbar({
6027
6084
  },
6028
6085
  [activeView, tiptapEditor, monacoEditor, markdownSource, setMarkdownSource, closeEmojiPicker]
6029
6086
  );
6030
- useEffect12(() => {
6087
+ useEffect13(() => {
6031
6088
  const onKeyDown = (e2) => {
6032
6089
  if (!(e2.ctrlKey || e2.metaKey) || e2.altKey || e2.shiftKey) return;
6033
6090
  if (e2.key.toLowerCase() !== "k") return;
@@ -6129,9 +6186,9 @@ function Toolbar({
6129
6186
  const isInTable = isWysiwyg ? tiptapEditor.isActive("table") : false;
6130
6187
  const wysiwygTemplate = isWysiwyg ? tiptapEditor.isActive("heading") ? tiptapEditor.getAttributes("heading")?.dataTemplate ?? "" : null : null;
6131
6188
  const isRawView = activeView === "raw";
6132
- const [rawTemplate, setRawTemplate] = useState12(null);
6133
- const [rawHeadingLine, setRawHeadingLine] = useState12(null);
6134
- useEffect12(() => {
6189
+ const [rawTemplate, setRawTemplate] = useState13(null);
6190
+ const [rawHeadingLine, setRawHeadingLine] = useState13(null);
6191
+ useEffect13(() => {
6135
6192
  if (!isRawView || !monacoEditor) {
6136
6193
  setRawTemplate(null);
6137
6194
  setRawHeadingLine(null);
@@ -6169,8 +6226,8 @@ function Toolbar({
6169
6226
  contentSub.dispose();
6170
6227
  };
6171
6228
  }, [isRawView, monacoEditor]);
6172
- const [wysiwygHeadingIndex, setWysiwygHeadingIndex] = useState12(null);
6173
- useEffect12(() => {
6229
+ const [wysiwygHeadingIndex, setWysiwygHeadingIndex] = useState13(null);
6230
+ useEffect13(() => {
6174
6231
  if (!isWysiwyg || !tiptapEditor) {
6175
6232
  setWysiwygHeadingIndex(null);
6176
6233
  return;
@@ -6764,11 +6821,8 @@ function StatusBar({ className }) {
6764
6821
  }
6765
6822
 
6766
6823
  // src/RawEditor.tsx
6767
- import { useRef as useRef12, useCallback as useCallback12, useEffect as useEffect13 } from "react";
6768
- import Editor, {
6769
- loader
6770
- } from "@monaco-editor/react";
6771
- import * as monaco from "monaco-editor";
6824
+ import { useRef as useRef12, useCallback as useCallback12, useEffect as useEffect14 } from "react";
6825
+ import Editor from "@monaco-editor/react";
6772
6826
  import { getAvailableTemplates } from "@bendyline/squisq/doc";
6773
6827
  import { suggestIcons, resolveIcon as resolveIcon2, iconGlyph } from "@bendyline/squisq/icons";
6774
6828
 
@@ -6787,7 +6841,6 @@ function parseSquisqMediaPayload(raw) {
6787
6841
 
6788
6842
  // src/RawEditor.tsx
6789
6843
  import { jsx as jsx14 } from "react/jsx-runtime";
6790
- loader.config({ monaco });
6791
6844
  var SQUISQ_LIGHT_GUTTER = "#dcd8d0";
6792
6845
  var SQUISQ_DARK_GUTTER = "#0f1219";
6793
6846
  var SQUISQ_LIGHT_SEAM = "#b0a99a";
@@ -6806,6 +6859,7 @@ function RawEditor({
6806
6859
  readOnly = false
6807
6860
  }) {
6808
6861
  const { markdownSource, setMarkdownSource, setMonacoEditor, language, mentionProvider } = useEditorContext();
6862
+ const { monaco: monacoNs, ready: monacoReady } = useMonacoLoader();
6809
6863
  const editorRef = useRef12(null);
6810
6864
  const isExternalUpdate = useRef12(false);
6811
6865
  const completionDisposable = useRef12(null);
@@ -6815,15 +6869,15 @@ function RawEditor({
6815
6869
  const dropCleanupRef = useRef12(null);
6816
6870
  const keyDisposable = useRef12(null);
6817
6871
  const submitOnEnterRef = useRef12(submitOnEnter);
6818
- useEffect13(() => {
6872
+ useEffect14(() => {
6819
6873
  submitOnEnterRef.current = submitOnEnter;
6820
6874
  }, [submitOnEnter]);
6821
6875
  const mentionProviderRef = useRef12(mentionProvider);
6822
- useEffect13(() => {
6876
+ useEffect14(() => {
6823
6877
  mentionProviderRef.current = mentionProvider;
6824
6878
  }, [mentionProvider]);
6825
- const handleBeforeMount = useCallback12((monaco2) => {
6826
- monaco2.editor.defineTheme("squisq-light", {
6879
+ const handleBeforeMount = useCallback12((monaco) => {
6880
+ monaco.editor.defineTheme("squisq-light", {
6827
6881
  base: "vs",
6828
6882
  inherit: true,
6829
6883
  rules: [],
@@ -6834,7 +6888,7 @@ function RawEditor({
6834
6888
  "minimap.background": SQUISQ_LIGHT_GUTTER
6835
6889
  }
6836
6890
  });
6837
- monaco2.editor.defineTheme("squisq-dark", {
6891
+ monaco.editor.defineTheme("squisq-dark", {
6838
6892
  base: "vs-dark",
6839
6893
  inherit: true,
6840
6894
  rules: [],
@@ -6847,7 +6901,7 @@ function RawEditor({
6847
6901
  });
6848
6902
  }, []);
6849
6903
  const handleMount = useCallback12(
6850
- (editor, monaco2) => {
6904
+ (editor, monaco) => {
6851
6905
  editorRef.current = editor;
6852
6906
  setMonacoEditor(editor);
6853
6907
  editor.focus();
@@ -6859,7 +6913,7 @@ function RawEditor({
6859
6913
  iconCompletionDisposable.current = null;
6860
6914
  if (language === "markdown") {
6861
6915
  const templates = getAvailableTemplates();
6862
- completionDisposable.current = monaco2.languages.registerCompletionItemProvider("markdown", {
6916
+ completionDisposable.current = monaco.languages.registerCompletionItemProvider("markdown", {
6863
6917
  triggerCharacters: ["["],
6864
6918
  provideCompletionItems(model, position) {
6865
6919
  const lineContent = model.getLineContent(position.lineNumber);
@@ -6871,7 +6925,7 @@ function RawEditor({
6871
6925
  const closingMatch = textAfterCursor.match(/^\]\}/);
6872
6926
  const suffix = closingMatch ? "" : "]}";
6873
6927
  const startCol = bracketIdx + 3;
6874
- const range = new monaco2.Range(
6928
+ const range = new monaco.Range(
6875
6929
  position.lineNumber,
6876
6930
  startCol,
6877
6931
  position.lineNumber,
@@ -6880,7 +6934,7 @@ function RawEditor({
6880
6934
  const suggestions = templates.map((name) => ({
6881
6935
  label: name,
6882
6936
  filterText: name,
6883
- kind: monaco2.languages.CompletionItemKind.Value,
6937
+ kind: monaco.languages.CompletionItemKind.Value,
6884
6938
  insertText: name + suffix,
6885
6939
  range,
6886
6940
  detail: "Block template",
@@ -6889,7 +6943,7 @@ function RawEditor({
6889
6943
  return { suggestions };
6890
6944
  }
6891
6945
  });
6892
- mentionCompletionDisposable.current = monaco2.languages.registerCompletionItemProvider(
6946
+ mentionCompletionDisposable.current = monaco.languages.registerCompletionItemProvider(
6893
6947
  "markdown",
6894
6948
  {
6895
6949
  triggerCharacters: ["@"],
@@ -6913,7 +6967,7 @@ function RawEditor({
6913
6967
  } catch {
6914
6968
  return { suggestions: [] };
6915
6969
  }
6916
- const range = new monaco2.Range(
6970
+ const range = new monaco.Range(
6917
6971
  position.lineNumber,
6918
6972
  atIdx + 1,
6919
6973
  position.lineNumber,
@@ -6922,7 +6976,7 @@ function RawEditor({
6922
6976
  return {
6923
6977
  suggestions: candidates.map((c) => ({
6924
6978
  label: `@${c.label}`,
6925
- kind: monaco2.languages.CompletionItemKind.User,
6979
+ kind: monaco.languages.CompletionItemKind.User,
6926
6980
  insertText: `@[${c.label}](${c.scheme}:${c.id}) `,
6927
6981
  range,
6928
6982
  ...c.description ? { detail: c.description } : {},
@@ -6932,7 +6986,7 @@ function RawEditor({
6932
6986
  }
6933
6987
  }
6934
6988
  );
6935
- iconCompletionDisposable.current = monaco2.languages.registerCompletionItemProvider(
6989
+ iconCompletionDisposable.current = monaco.languages.registerCompletionItemProvider(
6936
6990
  "markdown",
6937
6991
  {
6938
6992
  triggerCharacters: ["["],
@@ -6950,7 +7004,7 @@ function RawEditor({
6950
7004
  const query = between.toLowerCase();
6951
7005
  const closingMatch = textAfterCursor.match(/^\]\}/);
6952
7006
  const suffix = closingMatch ? "" : "]}";
6953
- const range = new monaco2.Range(
7007
+ const range = new monaco.Range(
6954
7008
  position.lineNumber,
6955
7009
  bracketIdx + 3,
6956
7010
  // after `{[`
@@ -6972,7 +7026,7 @@ function RawEditor({
6972
7026
  // `filterText` excludes the glyph + spacing so Monaco
6973
7027
  // filters against the actual icon name only.
6974
7028
  filterText: m.token,
6975
- kind: monaco2.languages.CompletionItemKind.Constant,
7029
+ kind: monaco.languages.CompletionItemKind.Constant,
6976
7030
  insertText: `${m.token}${suffix}`,
6977
7031
  range,
6978
7032
  detail: m.entry.label,
@@ -6995,7 +7049,7 @@ function RawEditor({
6995
7049
  }
6996
7050
  keyDisposable.current?.dispose();
6997
7051
  keyDisposable.current = editor.onKeyDown((e2) => {
6998
- if (e2.keyCode !== monaco2.KeyCode.Enter) return;
7052
+ if (e2.keyCode !== monaco.KeyCode.Enter) return;
6999
7053
  if (!submitOnEnterRef.current) return;
7000
7054
  if (e2.metaKey || e2.ctrlKey || e2.shiftKey || e2.altKey) return;
7001
7055
  e2.preventDefault();
@@ -7026,7 +7080,7 @@ function RawEditor({
7026
7080
  const markdown = `![${payload.alt}](${payload.name})`;
7027
7081
  editor.executeEdits("squisq-media-drop", [
7028
7082
  {
7029
- range: new monaco2.Range(
7083
+ range: new monaco.Range(
7030
7084
  position.lineNumber,
7031
7085
  position.column,
7032
7086
  position.lineNumber,
@@ -7048,7 +7102,7 @@ function RawEditor({
7048
7102
  },
7049
7103
  [setMonacoEditor, language]
7050
7104
  );
7051
- useEffect13(() => {
7105
+ useEffect14(() => {
7052
7106
  return () => {
7053
7107
  setMonacoEditor(null);
7054
7108
  completionDisposable.current?.dispose();
@@ -7074,7 +7128,7 @@ function RawEditor({
7074
7128
  },
7075
7129
  [setMarkdownSource]
7076
7130
  );
7077
- useEffect13(() => {
7131
+ useEffect14(() => {
7078
7132
  const editor = editorRef.current;
7079
7133
  if (editor) {
7080
7134
  const currentValue = editor.getValue();
@@ -7085,9 +7139,9 @@ function RawEditor({
7085
7139
  }
7086
7140
  }
7087
7141
  }, [markdownSource]);
7088
- useEffect13(() => {
7142
+ useEffect14(() => {
7089
7143
  const editor = editorRef.current;
7090
- if (!editor) return;
7144
+ if (!editor || !monacoNs) return;
7091
7145
  if (language !== "markdown") return;
7092
7146
  const model = editor.getModel();
7093
7147
  if (!model) return;
@@ -7105,7 +7159,7 @@ function RawEditor({
7105
7159
  if (!glyph) continue;
7106
7160
  const col = match.index + 1;
7107
7161
  decorations.push({
7108
- range: new monaco.Range(line, col, line, col),
7162
+ range: new monacoNs.Range(line, col, line, col),
7109
7163
  options: {
7110
7164
  before: {
7111
7165
  content: glyph,
@@ -7120,8 +7174,28 @@ function RawEditor({
7120
7174
  } else {
7121
7175
  iconGlyphDecorations.current.set(decorations);
7122
7176
  }
7123
- }, [markdownSource, language]);
7177
+ }, [markdownSource, language, monacoNs]);
7124
7178
  const effectiveTheme = SQUISQ_THEMES[theme] ?? theme;
7179
+ if (!monacoReady) {
7180
+ return /* @__PURE__ */ jsx14(
7181
+ "div",
7182
+ {
7183
+ className,
7184
+ style: {
7185
+ width: "100%",
7186
+ height: "100%",
7187
+ display: "flex",
7188
+ alignItems: "center",
7189
+ justifyContent: "center",
7190
+ color: "var(--squisq-editor-muted-foreground, #6a6258)",
7191
+ fontSize: 13
7192
+ },
7193
+ "data-testid": "raw-editor",
7194
+ "data-monaco-loading": true,
7195
+ children: "Loading editor\u2026"
7196
+ }
7197
+ );
7198
+ }
7125
7199
  return /* @__PURE__ */ jsx14("div", { className, style: { width: "100%", height: "100%" }, "data-testid": "raw-editor", children: /* @__PURE__ */ jsx14(
7126
7200
  Editor,
7127
7201
  {
@@ -7167,7 +7241,7 @@ function RawEditor({
7167
7241
  }
7168
7242
 
7169
7243
  // src/WysiwygEditor.tsx
7170
- import { useEffect as useEffect17, useMemo as useMemo9, useRef as useRef15, useState as useState16 } from "react";
7244
+ import { useEffect as useEffect18, useMemo as useMemo9, useRef as useRef15, useState as useState17 } from "react";
7171
7245
  import { useEditor, EditorContent } from "@tiptap/react";
7172
7246
  import StarterKit from "@tiptap/starter-kit";
7173
7247
  import Table from "@tiptap/extension-table";
@@ -9515,7 +9589,7 @@ var InlineIcon = Node.create({
9515
9589
  });
9516
9590
 
9517
9591
  // src/ImageNodeView.tsx
9518
- import { useEffect as useEffect14, useRef as useRef13, useState as useState13 } from "react";
9592
+ import { useEffect as useEffect15, useRef as useRef13, useState as useState14 } from "react";
9519
9593
  import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
9520
9594
  import Image2 from "@tiptap/extension-image";
9521
9595
 
@@ -9535,16 +9609,16 @@ import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-r
9535
9609
  function ImageComponent({ node, selected, editor, updateAttributes: updateAttributes2 }) {
9536
9610
  const { src, alt, title, width } = node.attrs;
9537
9611
  const { mediaProvider, imageDisplayMode, openImageEdit, mediaRevision } = useEditorContext();
9538
- const [resolvedSrc, setResolvedSrc] = useState13(src);
9539
- const [hovered, setHovered] = useState13(false);
9612
+ const [resolvedSrc, setResolvedSrc] = useState14(src);
9613
+ const [hovered, setHovered] = useState14(false);
9540
9614
  const imgRef = useRef13(null);
9541
- const [previewWidth, setPreviewWidth] = useState13(null);
9615
+ const [previewWidth, setPreviewWidth] = useState14(null);
9542
9616
  const isThumbnail = imageDisplayMode === "thumbnail";
9543
9617
  const isEditable = editor?.isEditable ?? true;
9544
9618
  const normalizedRelativePath = normalizeMalformedAssetUrl(src);
9545
9619
  const isRelative = src && !src.startsWith("blob:") && !src.startsWith("http") && !src.startsWith("data:") && !src.startsWith("/");
9546
9620
  const resolveAs = normalizedRelativePath ?? (isRelative ? src : null);
9547
- useEffect14(() => {
9621
+ useEffect15(() => {
9548
9622
  if (!mediaProvider || !resolveAs) {
9549
9623
  setResolvedSrc(src);
9550
9624
  return;
@@ -9724,12 +9798,12 @@ var ImageWithMediaProvider = Image2.extend({
9724
9798
  import { NodeViewWrapper as NodeViewWrapper2, ReactNodeViewRenderer as ReactNodeViewRenderer2 } from "@tiptap/react";
9725
9799
 
9726
9800
  // src/tiptap/useResolvedMediaSrc.ts
9727
- import { useEffect as useEffect15, useState as useState14 } from "react";
9801
+ import { useEffect as useEffect16, useState as useState15 } from "react";
9728
9802
  function useResolvedMediaSrc(src) {
9729
9803
  const { mediaProvider, mediaRevision } = useEditorContext();
9730
- const [resolved, setResolved] = useState14(src);
9804
+ const [resolved, setResolved] = useState15(src);
9731
9805
  const isRelative = !!src && !src.startsWith("blob:") && !src.startsWith("http:") && !src.startsWith("https:") && !src.startsWith("data:") && !src.startsWith("/");
9732
- useEffect15(() => {
9806
+ useEffect16(() => {
9733
9807
  if (!mediaProvider || !isRelative) {
9734
9808
  setResolved(src);
9735
9809
  return;
@@ -10124,9 +10198,9 @@ import {
10124
10198
  createContext as createContext2,
10125
10199
  useCallback as useCallback13,
10126
10200
  useContext as useContext2,
10127
- useState as useState15,
10201
+ useState as useState16,
10128
10202
  useMemo as useMemo8,
10129
- useEffect as useEffect16,
10203
+ useEffect as useEffect17,
10130
10204
  useRef as useRef14
10131
10205
  } from "react";
10132
10206
  import { VIEWPORT_PRESETS, getThemeSummaries as getThemeSummaries2, resolveTheme as resolveTheme2 } from "@bendyline/squisq/schemas";
@@ -10223,13 +10297,13 @@ function PreviewSettingsProvider({
10223
10297
  () => resolveRenderAs(frontmatter?.["document-render-as"]),
10224
10298
  [frontmatter]
10225
10299
  );
10226
- const [selectedPreset, setSelectedPreset] = useState15(null);
10227
- useEffect16(() => setSelectedPreset(null), [fmPreset]);
10300
+ const [selectedPreset, setSelectedPreset] = useState16(null);
10301
+ useEffect17(() => setSelectedPreset(null), [fmPreset]);
10228
10302
  const activePreset = selectedPreset ?? fmPreset ?? "landscape";
10229
10303
  const activeViewport = VIEWPORT_PRESETS[activePreset];
10230
10304
  const fmMode = useMemo8(() => resolveDisplayMode(frontmatter?.["display-mode"]), [frontmatter]);
10231
- const [selectedDisplayMode, setSelectedDisplayMode] = useState15(null);
10232
- useEffect16(() => setSelectedDisplayMode(null), [fmMode]);
10305
+ const [selectedDisplayMode, setSelectedDisplayMode] = useState16(null);
10306
+ useEffect17(() => setSelectedDisplayMode(null), [fmMode]);
10233
10307
  const activeDisplayMode = selectedDisplayMode ?? fmMode ?? "video";
10234
10308
  const fmTheme = useMemo8(
10235
10309
  () => resolveFrontmatterTheme(
@@ -10237,8 +10311,8 @@ function PreviewSettingsProvider({
10237
10311
  ),
10238
10312
  [frontmatter]
10239
10313
  );
10240
- const [selectedThemeId, setSelectedThemeId] = useState15(null);
10241
- useEffect16(() => setSelectedThemeId(null), [fmTheme]);
10314
+ const [selectedThemeId, setSelectedThemeId] = useState16(null);
10315
+ useEffect17(() => setSelectedThemeId(null), [fmTheme]);
10242
10316
  const resolvedThemeId = selectedThemeId ?? fmTheme ?? "standard";
10243
10317
  const resolvedTheme = useMemo8(() => resolveTheme2(resolvedThemeId), [resolvedThemeId]);
10244
10318
  const activeThemeId = themeOverride?.id ?? resolvedThemeId;
@@ -10256,8 +10330,8 @@ function PreviewSettingsProvider({
10256
10330
  ),
10257
10331
  [frontmatter]
10258
10332
  );
10259
- const [selectedTransformStyle, setSelectedTransformStyle] = useState15(null);
10260
- useEffect16(() => setSelectedTransformStyle(null), [fmTransform]);
10333
+ const [selectedTransformStyle, setSelectedTransformStyle] = useState16(null);
10334
+ useEffect17(() => setSelectedTransformStyle(null), [fmTransform]);
10261
10335
  const activeTransformStyle = selectedTransformStyle ?? fmTransform ?? "";
10262
10336
  const handleSetTransformStyle = useCallback13(
10263
10337
  (id) => {
@@ -10274,8 +10348,8 @@ function PreviewSettingsProvider({
10274
10348
  ),
10275
10349
  [frontmatter]
10276
10350
  );
10277
- const [selectedCaptionStyle, setSelectedCaptionStyle] = useState15(null);
10278
- useEffect16(() => setSelectedCaptionStyle(null), [fmCaption]);
10351
+ const [selectedCaptionStyle, setSelectedCaptionStyle] = useState16(null);
10352
+ useEffect17(() => setSelectedCaptionStyle(null), [fmCaption]);
10279
10353
  const activeCaptionStyle = selectedCaptionStyle ?? fmCaption ?? "standard";
10280
10354
  const handleSetCaptionStyle = useCallback13(
10281
10355
  (style) => {
@@ -10349,10 +10423,10 @@ var selectStyle = {
10349
10423
  cursor: "pointer"
10350
10424
  };
10351
10425
  function useIsNarrow(breakpoint = 600) {
10352
- const [narrow, setNarrow] = useState15(
10426
+ const [narrow, setNarrow] = useState16(
10353
10427
  () => typeof window !== "undefined" && window.innerWidth <= breakpoint
10354
10428
  );
10355
- useEffect16(() => {
10429
+ useEffect17(() => {
10356
10430
  const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
10357
10431
  const handler = (e2) => setNarrow(e2.matches);
10358
10432
  mq.addEventListener("change", handler);
@@ -10363,9 +10437,9 @@ function useIsNarrow(breakpoint = 600) {
10363
10437
  function PreviewToolbarControls() {
10364
10438
  const s = usePreviewSettings();
10365
10439
  const isNarrow = useIsNarrow(768);
10366
- const [popoverOpen, setPopoverOpen] = useState15(false);
10440
+ const [popoverOpen, setPopoverOpen] = useState16(false);
10367
10441
  const popoverRef = useRef14(null);
10368
- useEffect16(() => {
10442
+ useEffect17(() => {
10369
10443
  if (!popoverOpen) return;
10370
10444
  const handler = (e2) => {
10371
10445
  if (popoverRef.current && !popoverRef.current.contains(e2.target)) {
@@ -10524,19 +10598,19 @@ function WysiwygEditor({
10524
10598
  themeInheritance
10525
10599
  } = useEditorContext();
10526
10600
  const mentionProviderRef = useRef15(mentionProvider);
10527
- useEffect17(() => {
10601
+ useEffect18(() => {
10528
10602
  mentionProviderRef.current = mentionProvider;
10529
10603
  }, [mentionProvider]);
10530
10604
  const resolvedPlaceholder = useMemo9(() => placeholder ?? pickEmptyPrompt(), [placeholder]);
10531
10605
  const isExternalUpdate = useRef15(false);
10532
10606
  const lastSourceRef = useRef15(markdownSource);
10533
10607
  const mediaProviderRef = useRef15(mediaProvider);
10534
- useEffect17(() => {
10608
+ useEffect18(() => {
10535
10609
  mediaProviderRef.current = mediaProvider;
10536
10610
  }, [mediaProvider]);
10537
10611
  const frontmatterRef = useRef15(stripFrontmatter(markdownSource).frontmatter);
10538
10612
  const submitOnEnterRef = useRef15(submitOnEnter);
10539
- useEffect17(() => {
10613
+ useEffect18(() => {
10540
10614
  submitOnEnterRef.current = submitOnEnter;
10541
10615
  }, [submitOnEnter]);
10542
10616
  const editor = useEditor({
@@ -10673,18 +10747,18 @@ function WysiwygEditor({
10673
10747
  }
10674
10748
  }
10675
10749
  });
10676
- useEffect17(() => {
10750
+ useEffect18(() => {
10677
10751
  if (editor) {
10678
10752
  setTiptapEditor(editor);
10679
10753
  }
10680
10754
  return () => setTiptapEditor(null);
10681
10755
  }, [editor, setTiptapEditor]);
10682
- useEffect17(() => {
10756
+ useEffect18(() => {
10683
10757
  if (editor) editor.setEditable(!readOnly);
10684
10758
  }, [editor, readOnly]);
10685
10759
  const containerRef = useRef15(null);
10686
- const [badgeMenu, setBadgeMenu] = useState16(null);
10687
- useEffect17(() => {
10760
+ const [badgeMenu, setBadgeMenu] = useState17(null);
10761
+ useEffect18(() => {
10688
10762
  if (!editor) return;
10689
10763
  const root = containerRef.current;
10690
10764
  if (!root) return;
@@ -10727,7 +10801,7 @@ function WysiwygEditor({
10727
10801
  root.addEventListener("mousedown", onClick);
10728
10802
  return () => root.removeEventListener("mousedown", onClick);
10729
10803
  }, [editor]);
10730
- useEffect17(() => {
10804
+ useEffect18(() => {
10731
10805
  if (!editor) return;
10732
10806
  if (markdownSource !== lastSourceRef.current) {
10733
10807
  isExternalUpdate.current = true;
@@ -10896,7 +10970,7 @@ function extFromMime(mime) {
10896
10970
  }
10897
10971
 
10898
10972
  // src/InlinePreviewGutter.tsx
10899
- import { useLayoutEffect, useMemo as useMemo11, useRef as useRef16, useState as useState18 } from "react";
10973
+ import { useLayoutEffect, useMemo as useMemo11, useRef as useRef16, useState as useState19 } from "react";
10900
10974
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS2 } from "@bendyline/squisq/schemas";
10901
10975
  import {
10902
10976
  flattenBlocks as flattenBlocks2,
@@ -10908,14 +10982,14 @@ import { extractPlainText, getChildren } from "@bendyline/squisq/markdown";
10908
10982
  import { BlockRenderer, MediaContext } from "@bendyline/squisq-react";
10909
10983
 
10910
10984
  // src/useHeadingLayout.ts
10911
- import { useCallback as useCallback14, useEffect as useEffect18, useMemo as useMemo10, useState as useState17 } from "react";
10985
+ import { useCallback as useCallback14, useEffect as useEffect19, useMemo as useMemo10, useState as useState18 } from "react";
10912
10986
  import { flattenBlocks, hasTemplate } from "@bendyline/squisq/doc";
10913
10987
  function useHeadingLayout(refInsideWrapper) {
10914
10988
  const { doc, activeView, monacoEditor, tiptapEditor } = useEditorContext();
10915
10989
  const flatBlocks = useMemo10(() => doc ? flattenBlocks(doc.blocks) : [], [doc]);
10916
- const [entries, setEntries] = useState17([]);
10917
- const [pageEdges, setPageEdges] = useState17(null);
10918
- useEffect18(() => {
10990
+ const [entries, setEntries] = useState18([]);
10991
+ const [pageEdges, setPageEdges] = useState18(null);
10992
+ useEffect19(() => {
10919
10993
  if (activeView !== "wysiwyg") return;
10920
10994
  const node = refInsideWrapper.current;
10921
10995
  if (!node) return;
@@ -10983,7 +11057,7 @@ function useHeadingLayout(refInsideWrapper) {
10983
11057
  window.removeEventListener("resize", recompute);
10984
11058
  };
10985
11059
  }, [activeView, flatBlocks, refInsideWrapper]);
10986
- useEffect18(() => {
11060
+ useEffect19(() => {
10987
11061
  if (activeView !== "raw") return;
10988
11062
  if (!monacoEditor) return;
10989
11063
  const node = refInsideWrapper.current;
@@ -11044,7 +11118,7 @@ function useHeadingLayout(refInsideWrapper) {
11044
11118
  window.removeEventListener("resize", recompute);
11045
11119
  };
11046
11120
  }, [activeView, monacoEditor, flatBlocks, refInsideWrapper]);
11047
- useEffect18(() => {
11121
+ useEffect19(() => {
11048
11122
  setEntries([]);
11049
11123
  setPageEdges(null);
11050
11124
  }, [activeView]);
@@ -11332,7 +11406,7 @@ function InlinePreviewGutter({
11332
11406
  headingEntries.forEach((e2) => m.set(e2.block.id, e2.top));
11333
11407
  return m;
11334
11408
  }, [headingEntries]);
11335
- const [positions, setPositions] = useState18(/* @__PURE__ */ new Map());
11409
+ const [positions, setPositions] = useState19(/* @__PURE__ */ new Map());
11336
11410
  useLayoutEffect(() => {
11337
11411
  if (items.length === 0) {
11338
11412
  setPositions((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
@@ -11520,7 +11594,7 @@ function InlinePreviewGutter({
11520
11594
  }
11521
11595
 
11522
11596
  // src/OutlinePanel.tsx
11523
- import { useCallback as useCallback15, useEffect as useEffect19, useMemo as useMemo12, useRef as useRef17, useState as useState19 } from "react";
11597
+ import { useCallback as useCallback15, useEffect as useEffect20, useMemo as useMemo12, useRef as useRef17, useState as useState20 } from "react";
11524
11598
  import { flattenBlocks as flattenBlocks3, hasTemplate as hasTemplate3 } from "@bendyline/squisq/doc";
11525
11599
  import { extractPlainText as extractPlainText2 } from "@bendyline/squisq/markdown";
11526
11600
  import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -11660,11 +11734,11 @@ function OutlineNode({
11660
11734
  function useActiveOutlineBlockId() {
11661
11735
  const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
11662
11736
  const flatBlocks = useMemo12(() => doc ? flattenBlocks3(doc.blocks) : [], [doc]);
11663
- const [activeId, setActiveId] = useState19(null);
11664
- useEffect19(() => {
11737
+ const [activeId, setActiveId] = useState20(null);
11738
+ useEffect20(() => {
11665
11739
  setActiveId(null);
11666
11740
  }, [activeView]);
11667
- useEffect19(() => {
11741
+ useEffect20(() => {
11668
11742
  if (activeView !== "wysiwyg" || !tiptapEditor) return;
11669
11743
  const update = () => {
11670
11744
  const { from } = tiptapEditor.state.selection;
@@ -11686,7 +11760,7 @@ function useActiveOutlineBlockId() {
11686
11760
  tiptapEditor.off("update", update);
11687
11761
  };
11688
11762
  }, [activeView, tiptapEditor, flatBlocks]);
11689
- useEffect19(() => {
11763
+ useEffect20(() => {
11690
11764
  if (activeView !== "raw" || !monacoEditor) return;
11691
11765
  const update = () => {
11692
11766
  const line = monacoEditor.getPosition()?.lineNumber;
@@ -11730,7 +11804,7 @@ function bumpHeadingLevelInSource(source, line, delta) {
11730
11804
  }
11731
11805
 
11732
11806
  // src/PreviewPanel.tsx
11733
- import { useState as useState21, useEffect as useEffect21 } from "react";
11807
+ import { useState as useState22, useEffect as useEffect22 } from "react";
11734
11808
  import { DocPlayer, LinearDocView, useMediaProvider } from "@bendyline/squisq-react";
11735
11809
  import { applyTransform } from "@bendyline/squisq/transform";
11736
11810
  import { resolveAudioMapping } from "@bendyline/squisq/doc";
@@ -11974,7 +12048,7 @@ function buildPreviewDoc(doc) {
11974
12048
  }
11975
12049
 
11976
12050
  // src/PlainHtmlPreview.tsx
11977
- import { useEffect as useEffect20, useMemo as useMemo13, useState as useState20 } from "react";
12051
+ import { useEffect as useEffect21, useMemo as useMemo13, useState as useState21 } from "react";
11978
12052
  import { parseMarkdown as parseMarkdown4 } from "@bendyline/squisq/markdown";
11979
12053
  import { markdownDocToPlainHtml } from "@bendyline/squisq-formats/html";
11980
12054
 
@@ -12029,8 +12103,8 @@ function PlainHtmlPreview({
12029
12103
  style
12030
12104
  }) {
12031
12105
  const mdDoc = useMemo13(() => parseMarkdown4(markdown), [markdown]);
12032
- const [resolvedImages, setResolvedImages] = useState20(null);
12033
- useEffect20(() => {
12106
+ const [resolvedImages, setResolvedImages] = useState21(null);
12107
+ useEffect21(() => {
12034
12108
  if (!mediaProvider) {
12035
12109
  setResolvedImages(null);
12036
12110
  return;
@@ -12131,8 +12205,8 @@ function PreviewPanel({ basePath = "/", className, workspaceContainer }) {
12131
12205
  activeTransformStyle,
12132
12206
  activeCaptionStyle
12133
12207
  } = usePreviewSettings();
12134
- const [previewDoc, setPreviewDoc] = useState21(null);
12135
- useEffect21(() => {
12208
+ const [previewDoc, setPreviewDoc] = useState22(null);
12209
+ useEffect22(() => {
12136
12210
  if (!doc || !doc.blocks.length) {
12137
12211
  setPreviewDoc(null);
12138
12212
  return;
@@ -12231,7 +12305,7 @@ function PreviewPanel({ basePath = "/", className, workspaceContainer }) {
12231
12305
  }
12232
12306
 
12233
12307
  // src/ImageViewer.tsx
12234
- import { useCallback as useCallback16, useEffect as useEffect22, useRef as useRef18, useState as useState22 } from "react";
12308
+ import { useCallback as useCallback16, useEffect as useEffect23, useRef as useRef18, useState as useState23 } from "react";
12235
12309
  import { Fragment as Fragment9, jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
12236
12310
  var MIN_ZOOM = 0.1;
12237
12311
  var MAX_ZOOM = 16;
@@ -12239,12 +12313,12 @@ var ZOOM_STEP = 1.25;
12239
12313
  function ImageViewer({ src, alt = "", className, theme = "light" }) {
12240
12314
  const imgRef = useRef18(null);
12241
12315
  const stageRef = useRef18(null);
12242
- const [naturalSize, setNaturalSize] = useState22(null);
12243
- const [fitZoom, setFitZoom] = useState22(1);
12244
- const [state, setState] = useState22({ mode: "fit" });
12245
- const [pan, setPan] = useState22({ x: 0, y: 0 });
12246
- const [error, setError] = useState22(null);
12247
- useEffect22(() => {
12316
+ const [naturalSize, setNaturalSize] = useState23(null);
12317
+ const [fitZoom, setFitZoom] = useState23(1);
12318
+ const [state, setState] = useState23({ mode: "fit" });
12319
+ const [pan, setPan] = useState23({ x: 0, y: 0 });
12320
+ const [error, setError] = useState23(null);
12321
+ useEffect23(() => {
12248
12322
  setNaturalSize(null);
12249
12323
  setState({ mode: "fit" });
12250
12324
  setPan({ x: 0, y: 0 });
@@ -12258,7 +12332,7 @@ function ImageViewer({ src, alt = "", className, theme = "light" }) {
12258
12332
  const fit = Math.min(clientWidth / naturalSize.w, clientHeight / naturalSize.h, 1);
12259
12333
  setFitZoom(fit > 0 ? fit : 1);
12260
12334
  }, [naturalSize]);
12261
- useEffect22(() => {
12335
+ useEffect23(() => {
12262
12336
  recomputeFitZoom();
12263
12337
  if (typeof ResizeObserver === "undefined") return;
12264
12338
  const stage = stageRef.current;
@@ -12301,7 +12375,7 @@ function ImageViewer({ src, alt = "", className, theme = "light" }) {
12301
12375
  },
12302
12376
  [effectiveZoom, fitZoom, pan.x, pan.y]
12303
12377
  );
12304
- useEffect22(() => {
12378
+ useEffect23(() => {
12305
12379
  const onMove = (e2) => {
12306
12380
  const drag = dragRef.current;
12307
12381
  if (!drag) return;
@@ -12412,19 +12486,19 @@ function ImageViewer({ src, alt = "", className, theme = "light" }) {
12412
12486
  }
12413
12487
 
12414
12488
  // src/ImageEditor.tsx
12415
- import { useCallback as useCallback20, useState as useState28 } from "react";
12489
+ import { useCallback as useCallback20, useState as useState29 } from "react";
12416
12490
  import { exportImageEditDoc as exportImageEditDoc2 } from "@bendyline/squisq/imageEdit";
12417
12491
 
12418
12492
  // src/imageEditor/CanvasSurface.tsx
12419
- import { useCallback as useCallback17, useEffect as useEffect24, useRef as useRef19, useState as useState24 } from "react";
12493
+ import { useCallback as useCallback17, useEffect as useEffect25, useRef as useRef19, useState as useState25 } from "react";
12420
12494
 
12421
12495
  // src/imageEditor/layers/EditorImageLayer.tsx
12422
- import { useEffect as useEffect23, useState as useState23 } from "react";
12496
+ import { useEffect as useEffect24, useState as useState24 } from "react";
12423
12497
  import { jsx as jsx25 } from "react/jsx-runtime";
12424
12498
  function EditorImageLayer({ layer, canvas, resolveAssetUrl }) {
12425
- const [href, setHref] = useState23(null);
12499
+ const [href, setHref] = useState24(null);
12426
12500
  const src = layer.content.src;
12427
- useEffect23(() => {
12501
+ useEffect24(() => {
12428
12502
  let cancelled = false;
12429
12503
  resolveAssetUrl(src).then((url) => {
12430
12504
  if (!cancelled) setHref(url);
@@ -12605,8 +12679,8 @@ function CanvasSurface({
12605
12679
  }) {
12606
12680
  const svgRef = useRef19(null);
12607
12681
  const dragRef = useRef19(null);
12608
- const [, forceRender] = useState24(0);
12609
- const [cropDrag, setCropDrag] = useState24(null);
12682
+ const [, forceRender] = useState25(0);
12683
+ const [cropDrag, setCropDrag] = useState25(null);
12610
12684
  const toCanvas = useCallback17(
12611
12685
  (clientX, clientY) => {
12612
12686
  const svg = svgRef.current;
@@ -12679,7 +12753,7 @@ function CanvasSurface({
12679
12753
  },
12680
12754
  [tool, dispatch, toCanvas, onCreateTextAt, onCreateShapeAt]
12681
12755
  );
12682
- useEffect24(() => {
12756
+ useEffect25(() => {
12683
12757
  function onMove(e2) {
12684
12758
  const drag = dragRef.current;
12685
12759
  if (drag) {
@@ -12896,7 +12970,7 @@ function measureTextLayerBox(layer, fallback) {
12896
12970
  }
12897
12971
 
12898
12972
  // src/imageEditor/ImageVersionHistoryDropdown.tsx
12899
- import { useCallback as useCallback18, useEffect as useEffect25, useRef as useRef20, useState as useState25 } from "react";
12973
+ import { useCallback as useCallback18, useEffect as useEffect26, useRef as useRef20, useState as useState26 } from "react";
12900
12974
  import {
12901
12975
  exportImageEditDoc
12902
12976
  } from "@bendyline/squisq/imageEdit";
@@ -12908,15 +12982,15 @@ function ImageVersionHistoryDropdown({
12908
12982
  onRevert,
12909
12983
  refreshKey
12910
12984
  }) {
12911
- const [open, setOpen] = useState25(false);
12912
- const [versions, setVersions] = useState25([]);
12913
- const [loading, setLoading] = useState25(false);
12914
- const [busyTimestamp, setBusyTimestamp] = useState25(null);
12915
- const [meta, setMeta2] = useState25({});
12985
+ const [open, setOpen] = useState26(false);
12986
+ const [versions, setVersions] = useState26([]);
12987
+ const [loading, setLoading] = useState26(false);
12988
+ const [busyTimestamp, setBusyTimestamp] = useState26(null);
12989
+ const [meta, setMeta2] = useState26({});
12916
12990
  const popoverRef = useRef20(null);
12917
12991
  const triggerRef = useRef20(null);
12918
12992
  const urlsRef = useRef20(/* @__PURE__ */ new Set());
12919
- useEffect25(() => {
12993
+ useEffect26(() => {
12920
12994
  if (!open) return;
12921
12995
  let cancelled = false;
12922
12996
  setLoading(true);
@@ -12934,7 +13008,7 @@ function ImageVersionHistoryDropdown({
12934
13008
  cancelled = true;
12935
13009
  };
12936
13010
  }, [open, versioning, refreshKey]);
12937
- useEffect25(() => {
13011
+ useEffect26(() => {
12938
13012
  if (!open) return;
12939
13013
  if (versions.length === 0) return;
12940
13014
  let cancelled = false;
@@ -12971,19 +13045,19 @@ function ImageVersionHistoryDropdown({
12971
13045
  cancelled = true;
12972
13046
  };
12973
13047
  }, [open, versions, versioning, container, meta]);
12974
- useEffect25(() => {
13048
+ useEffect26(() => {
12975
13049
  const urls = urlsRef.current;
12976
13050
  return () => {
12977
13051
  for (const url of urls) URL.revokeObjectURL(url);
12978
13052
  urls.clear();
12979
13053
  };
12980
13054
  }, []);
12981
- useEffect25(() => {
13055
+ useEffect26(() => {
12982
13056
  for (const url of urlsRef.current) URL.revokeObjectURL(url);
12983
13057
  urlsRef.current.clear();
12984
13058
  setMeta2({});
12985
13059
  }, [refreshKey]);
12986
- useEffect25(() => {
13060
+ useEffect26(() => {
12987
13061
  if (!open) return;
12988
13062
  function onDocClick(e2) {
12989
13063
  const t = e2.target;
@@ -13720,7 +13794,7 @@ function normalizeColor(v) {
13720
13794
  }
13721
13795
 
13722
13796
  // src/imageEditor/Toolbar.tsx
13723
- import { useRef as useRef21, useState as useState26, useEffect as useEffect26 } from "react";
13797
+ import { useRef as useRef21, useState as useState27, useEffect as useEffect27 } from "react";
13724
13798
  import { jsx as jsx34, jsxs as jsxs25 } from "react/jsx-runtime";
13725
13799
  var TOOLS = [
13726
13800
  { id: "select", icon: /* @__PURE__ */ jsx34(CursorIcon, {}), title: "Select / move (V)" },
@@ -13829,10 +13903,10 @@ function Toolbar2({
13829
13903
  ] });
13830
13904
  }
13831
13905
  function ExportDropdown({ onExport }) {
13832
- const [open, setOpen] = useState26(false);
13906
+ const [open, setOpen] = useState27(false);
13833
13907
  const wrapRef = useRef21(null);
13834
13908
  const triggerRef = useRef21(null);
13835
- useEffect26(() => {
13909
+ useEffect27(() => {
13836
13910
  if (!open) return;
13837
13911
  function onDocClick(e2) {
13838
13912
  const t = e2.target;
@@ -13907,7 +13981,7 @@ function probeDims(file) {
13907
13981
  }
13908
13982
 
13909
13983
  // src/imageEditor/useImageEditor.ts
13910
- import { useCallback as useCallback19, useEffect as useEffect27, useMemo as useMemo14, useReducer as useReducer2, useRef as useRef22, useState as useState27 } from "react";
13984
+ import { useCallback as useCallback19, useEffect as useEffect28, useMemo as useMemo14, useReducer as useReducer2, useRef as useRef22, useState as useState28 } from "react";
13911
13985
  import {
13912
13986
  IMAGE_EDIT_ASSETS_PREFIX,
13913
13987
  IMAGE_EDIT_STATE_FILENAME,
@@ -14012,10 +14086,10 @@ function useImageEditor(options) {
14012
14086
  },
14013
14087
  null
14014
14088
  );
14015
- const [ready, setReady] = useState27(false);
14016
- const [error, setError] = useState27(null);
14089
+ const [ready, setReady] = useState28(false);
14090
+ const [error, setError] = useState28(null);
14017
14091
  const seededOnLoadRef = useRef22(false);
14018
- useEffect27(() => {
14092
+ useEffect28(() => {
14019
14093
  let cancelled = false;
14020
14094
  setReady(false);
14021
14095
  setError(null);
@@ -14047,7 +14121,7 @@ function useImageEditor(options) {
14047
14121
  const persistTimerRef = useRef22(null);
14048
14122
  const docRef = useRef22(null);
14049
14123
  docRef.current = state?.doc ?? null;
14050
- useEffect27(() => {
14124
+ useEffect28(() => {
14051
14125
  if (!state?.dirty) return;
14052
14126
  if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
14053
14127
  persistTimerRef.current = setTimeout(() => {
@@ -14078,7 +14152,7 @@ function useImageEditor(options) {
14078
14152
  () => allowVersioning ? new ImageEditVersionManager(container, { stateFilename }) : null,
14079
14153
  [allowVersioning, container, stateFilename]
14080
14154
  );
14081
- useEffect27(() => {
14155
+ useEffect28(() => {
14082
14156
  if (!versioning) return;
14083
14157
  if (!ready) return;
14084
14158
  if (!seededOnLoadRef.current) return;
@@ -14090,7 +14164,7 @@ function useImageEditor(options) {
14090
14164
  );
14091
14165
  });
14092
14166
  }, [versioning, ready]);
14093
- useEffect27(() => {
14167
+ useEffect28(() => {
14094
14168
  if (!versioning) return;
14095
14169
  if (versioningAutoSaveIdleMs <= 0) return;
14096
14170
  if (!state?.doc) return;
@@ -14120,7 +14194,7 @@ function useImageEditor(options) {
14120
14194
  },
14121
14195
  [container]
14122
14196
  );
14123
- useEffect27(() => {
14197
+ useEffect28(() => {
14124
14198
  const cache = urlCacheRef.current;
14125
14199
  return () => {
14126
14200
  for (const url of cache.values()) URL.revokeObjectURL(url);
@@ -14275,7 +14349,7 @@ function ImageEditor(props) {
14275
14349
  allowVersioning,
14276
14350
  versioningAutoSaveIdleMs
14277
14351
  });
14278
- const [historyRefreshKey, setHistoryRefreshKey] = useState28(0);
14352
+ const [historyRefreshKey, setHistoryRefreshKey] = useState29(0);
14279
14353
  const handleExport = useCallback20(
14280
14354
  async (format) => {
14281
14355
  if (!state) return;
@@ -14475,7 +14549,7 @@ function ImageEditor(props) {
14475
14549
  }
14476
14550
 
14477
14551
  // src/MediaBin.tsx
14478
- import { useState as useState29, useEffect as useEffect28, useRef as useRef23, useCallback as useCallback21 } from "react";
14552
+ import { useState as useState30, useEffect as useEffect29, useRef as useRef23, useCallback as useCallback21 } from "react";
14479
14553
  import { jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
14480
14554
  function formatSize(bytes) {
14481
14555
  if (bytes < 1024) return `${bytes} B`;
@@ -14494,11 +14568,11 @@ function isImageMime(mimeType) {
14494
14568
  return mimeType.startsWith("image/");
14495
14569
  }
14496
14570
  function MediaBin({ mediaProvider, isDark, refreshKey, onMediaUploaded }) {
14497
- const [entries, setEntries] = useState29([]);
14498
- const [thumbUrls, setThumbUrls] = useState29({});
14499
- const [loading, setLoading] = useState29(false);
14571
+ const [entries, setEntries] = useState30([]);
14572
+ const [thumbUrls, setThumbUrls] = useState30({});
14573
+ const [loading, setLoading] = useState30(false);
14500
14574
  const fileInputRef = useRef23(null);
14501
- useEffect28(() => {
14575
+ useEffect29(() => {
14502
14576
  if (!mediaProvider) {
14503
14577
  setEntries([]);
14504
14578
  setThumbUrls({});
@@ -14666,7 +14740,7 @@ ${formatSize(entry.size)}`,
14666
14740
  }
14667
14741
 
14668
14742
  // src/DropZoneOverlay.tsx
14669
- import { useState as useState30 } from "react";
14743
+ import { useState as useState31 } from "react";
14670
14744
  import { Fragment as Fragment11, jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
14671
14745
  function DropZoneOverlay({
14672
14746
  dragContentType,
@@ -14723,7 +14797,7 @@ function DropZone({
14723
14797
  disabled,
14724
14798
  variant
14725
14799
  }) {
14726
- const [isHovering, setIsHovering] = useState30(false);
14800
+ const [isHovering, setIsHovering] = useState31(false);
14727
14801
  const props = zoneProps(target);
14728
14802
  return /* @__PURE__ */ jsxs28(
14729
14803
  "div",
@@ -14767,16 +14841,16 @@ function DropZone({
14767
14841
  }
14768
14842
 
14769
14843
  // src/Tooltip.tsx
14770
- import { useEffect as useEffect29, useRef as useRef24, useState as useState31 } from "react";
14844
+ import { useEffect as useEffect30, useRef as useRef24, useState as useState32 } from "react";
14771
14845
  import { createPortal as createPortal5 } from "react-dom";
14772
14846
  import { jsx as jsx38 } from "react/jsx-runtime";
14773
14847
  var SHOW_DELAY_MS = 180;
14774
14848
  function TooltipLayer() {
14775
- const [state, setState] = useState31(null);
14849
+ const [state, setState] = useState32(null);
14776
14850
  const timerRef = useRef24(null);
14777
14851
  const currentTargetRef = useRef24(null);
14778
14852
  const visibleRef = useRef24(false);
14779
- useEffect29(() => {
14853
+ useEffect30(() => {
14780
14854
  const clearTimer = () => {
14781
14855
  if (timerRef.current) {
14782
14856
  clearTimeout(timerRef.current);
@@ -14860,7 +14934,7 @@ function TooltipLayer() {
14860
14934
  }
14861
14935
 
14862
14936
  // src/hooks/useFileDrop.ts
14863
- import { useCallback as useCallback22, useEffect as useEffect30, useRef as useRef25, useState as useState32 } from "react";
14937
+ import { useCallback as useCallback22, useEffect as useEffect31, useRef as useRef25, useState as useState33 } from "react";
14864
14938
  var MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
14865
14939
  "png",
14866
14940
  "jpg",
@@ -14920,11 +14994,11 @@ function classifyDataTransferItems(items) {
14920
14994
  return null;
14921
14995
  }
14922
14996
  function useFileDrop({ onDrop, enabled = true }) {
14923
- const [isDragging, setIsDragging] = useState32(false);
14924
- const [dragContentType, setDragContentType] = useState32(null);
14997
+ const [isDragging, setIsDragging] = useState33(false);
14998
+ const [dragContentType, setDragContentType] = useState33(null);
14925
14999
  const dragCounterRef = useRef25(0);
14926
15000
  const inPageDragRef = useRef25(false);
14927
- useEffect30(() => {
15001
+ useEffect31(() => {
14928
15002
  if (!enabled) return;
14929
15003
  const onStart = () => {
14930
15004
  inPageDragRef.current = true;
@@ -15278,8 +15352,8 @@ function EditorShellInner({
15278
15352
  const isCodeMode = editorMode === "code";
15279
15353
  const isImageMode = editorMode === "image";
15280
15354
  const isMarkdownMode = editorMode === "markdown";
15281
- const [showFiles, setShowFiles] = useState33(false);
15282
- const [mediaRefreshKey, setMediaRefreshKey] = useState33(0);
15355
+ const [showFiles, setShowFiles] = useState34(false);
15356
+ const [mediaRefreshKey, setMediaRefreshKey] = useState34(0);
15283
15357
  const imageEditFallbackContainerRef = useRef26(null);
15284
15358
  if (imageEditFallbackContainerRef.current === null) {
15285
15359
  imageEditFallbackContainerRef.current = new MemoryContentContainer();
@@ -15351,10 +15425,10 @@ ${snippet}` : snippet);
15351
15425
  const { isDragging, dragContentType, containerProps, zoneProps } = useFileDrop({
15352
15426
  onDrop: handleFileDrop
15353
15427
  });
15354
- useEffect31(() => {
15428
+ useEffect32(() => {
15355
15429
  onChange?.(markdownSource);
15356
15430
  }, [markdownSource, onChange]);
15357
- useEffect31(() => {
15431
+ useEffect32(() => {
15358
15432
  const handler = (e2) => {
15359
15433
  if (e2.ctrlKey || e2.metaKey) {
15360
15434
  switch (e2.key) {
@@ -15561,9 +15635,9 @@ function ImageEditModal({
15561
15635
  const parent = container ?? new MemoryContentContainer();
15562
15636
  return scopeContainer(parent, `.imageEdits/${sanitized}`);
15563
15637
  }, [container, relativePath]);
15564
- const [initialSrc, setInitialSrc] = useState33(null);
15565
- const [resolveError, setResolveError] = useState33(null);
15566
- useEffect31(() => {
15638
+ const [initialSrc, setInitialSrc] = useState34(null);
15639
+ const [resolveError, setResolveError] = useState34(null);
15640
+ useEffect32(() => {
15567
15641
  let cancelled = false;
15568
15642
  mediaProvider.resolveUrl(relativePath).then(
15569
15643
  (url) => {
@@ -15591,7 +15665,7 @@ function ImageEditModal({
15591
15665
  },
15592
15666
  [mediaProvider, relativePath, onSaved]
15593
15667
  );
15594
- useEffect31(() => {
15668
+ useEffect32(() => {
15595
15669
  const handler = (e2) => {
15596
15670
  if (e2.key === "Escape") onClose();
15597
15671
  };
@@ -15685,7 +15759,7 @@ function ViewSwitcher({ className }) {
15685
15759
  }
15686
15760
 
15687
15761
  // src/ThemeCustomizerPanel.tsx
15688
- import { useCallback as useCallback24, useEffect as useEffect32, useMemo as useMemo17, useRef as useRef27, useState as useState34 } from "react";
15762
+ import { useCallback as useCallback24, useEffect as useEffect33, useMemo as useMemo17, useRef as useRef27, useState as useState35 } from "react";
15689
15763
  import {
15690
15764
  AVAILABLE_FONT_STACKS,
15691
15765
  compileTheme,
@@ -15833,18 +15907,18 @@ function ThemeCustomizerPanel({
15833
15907
  onSave,
15834
15908
  onReset
15835
15909
  }) {
15836
- const [open, setOpen] = useState34(false);
15837
- const [draft, setDraft] = useState34(() => themeToDraft(value));
15910
+ const [open, setOpen] = useState35(false);
15911
+ const [draft, setDraft] = useState35(() => themeToDraft(value));
15838
15912
  const containerRef = useRef27(null);
15839
15913
  const externalIdRef = useRef27(value?.id ?? null);
15840
- useEffect32(() => {
15914
+ useEffect33(() => {
15841
15915
  const incomingId = value?.id ?? null;
15842
15916
  if (incomingId !== externalIdRef.current) {
15843
15917
  externalIdRef.current = incomingId;
15844
15918
  setDraft(themeToDraft(value));
15845
15919
  }
15846
15920
  }, [value]);
15847
- useEffect32(() => {
15921
+ useEffect33(() => {
15848
15922
  if (!open) return;
15849
15923
  const handler = (e2) => {
15850
15924
  if (containerRef.current && !containerRef.current.contains(e2.target)) {
@@ -16226,13 +16300,13 @@ import {
16226
16300
  } from "@bendyline/squisq/jsonForm";
16227
16301
 
16228
16302
  // src/jsonEditor/editors.tsx
16229
- import { useEffect as useEffect34, useId, useRef as useRef29, useState as useState35 } from "react";
16303
+ import { useEffect as useEffect35, useId, useRef as useRef29, useState as useState36 } from "react";
16230
16304
  import {
16231
16305
  arrayItemKind
16232
16306
  } from "@bendyline/squisq/jsonForm";
16233
16307
 
16234
16308
  // src/jsonEditor/EmbeddedRichTextField.tsx
16235
- import { useEffect as useEffect33, useRef as useRef28 } from "react";
16309
+ import { useEffect as useEffect34, useRef as useRef28 } from "react";
16236
16310
  import { useEditor as useEditor3, EditorContent as EditorContent2 } from "@tiptap/react";
16237
16311
  import StarterKit2 from "@tiptap/starter-kit";
16238
16312
  import Table2 from "@tiptap/extension-table";
@@ -16275,7 +16349,7 @@ function EmbeddedRichTextField(props) {
16275
16349
  }
16276
16350
  }
16277
16351
  });
16278
- useEffect33(() => {
16352
+ useEffect34(() => {
16279
16353
  if (!editor) return;
16280
16354
  if (value === lastValueRef.current) return;
16281
16355
  isExternalUpdate.current = true;
@@ -16286,7 +16360,7 @@ function EmbeddedRichTextField(props) {
16286
16360
  isExternalUpdate.current = false;
16287
16361
  }
16288
16362
  }, [editor, value]);
16289
- useEffect33(() => {
16363
+ useEffect34(() => {
16290
16364
  if (editor) editor.setEditable(!readOnly);
16291
16365
  }, [editor, readOnly]);
16292
16366
  const cls = "squisq-jf-richtext" + (className ? ` ${className}` : "");
@@ -16321,7 +16395,7 @@ function TextEditor({ value, schema, pointer, disabled }) {
16321
16395
  function MultilineEditor({ value, schema, pointer, disabled }) {
16322
16396
  const { setAtPath } = useJsonEditor();
16323
16397
  const ref = useRef29(null);
16324
- useEffect34(() => {
16398
+ useEffect35(() => {
16325
16399
  const ta = ref.current;
16326
16400
  if (!ta) return;
16327
16401
  ta.style.height = "auto";
@@ -16601,7 +16675,7 @@ function ChipBinEditor({ value, schema, pointer, disabled }) {
16601
16675
  };
16602
16676
  const labels = itemSchema.squisq?.enumLabels;
16603
16677
  const enumOpts = itemSchema.enum;
16604
- const [draft, setDraft] = useState35("");
16678
+ const [draft, setDraft] = useState36("");
16605
16679
  const remove = (index) => {
16606
16680
  const next = items.slice();
16607
16681
  next.splice(index, 1);
@@ -16801,8 +16875,8 @@ function defaultForSchema(schema) {
16801
16875
  function TabsEditor({ value, schema, pointer, disabled }) {
16802
16876
  const branches = schema.oneOf ?? schema.anyOf ?? [];
16803
16877
  const initial = pickMatchingBranch(branches, value);
16804
- const [active, setActive] = useState35(initial);
16805
- useEffect34(() => {
16878
+ const [active, setActive] = useState36(initial);
16879
+ useEffect35(() => {
16806
16880
  setActive(pickMatchingBranch(branches, value));
16807
16881
  }, [value]);
16808
16882
  const branch = branches[active];
@@ -16982,7 +17056,7 @@ function JsonEditor(props) {
16982
17056
  }
16983
17057
 
16984
17058
  // src/recorder/RecorderButton.tsx
16985
- import { useCallback as useCallback25, useState as useState36 } from "react";
17059
+ import { useCallback as useCallback25, useState as useState37 } from "react";
16986
17060
  import { createPortal as createPortal6 } from "react-dom";
16987
17061
  import { Fragment as Fragment14, jsx as jsx47, jsxs as jsxs34 } from "react/jsx-runtime";
16988
17062
  function RecorderButton({
@@ -16994,7 +17068,7 @@ function RecorderButton({
16994
17068
  style,
16995
17069
  disabled
16996
17070
  }) {
16997
- const [open, setOpen] = useState36(false);
17071
+ const [open, setOpen] = useState37(false);
16998
17072
  const handleOpen = useCallback25(() => setOpen(true), []);
16999
17073
  const handleClose = useCallback25(() => setOpen(false), []);
17000
17074
  const handleSave = useCallback25(