@bendyline/squisq-editor-react 2.12.5 → 2.12.7

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/README.md CHANGED
@@ -95,7 +95,8 @@ and block-at-a-time / timeline editing primitives (`useBlockNavigator`,
95
95
  boundary and `{study=multiple-choice-flashcard}` makes child one the question,
96
96
  child two the default correct answer, and remaining children distractors.
97
97
  - **Panels** — `outline` (heading outline pane) and `inlinePreview` (per-block
98
- SVG preview gutter, `inlinePreviewWidth` default 320).
98
+ SVG preview gutter, `inlinePreviewWidth` default 320). Block previews include
99
+ ordinary sections and heading-less introductory text; template tags are optional.
99
100
  - **Code & image modes** — pass `fileName` / `language` to get a Monaco-only
100
101
  code editor, or `imageSrc` (+ `imageMode: 'edit'`) for the image surface.
101
102
  `.jsonc` files, `language="jsonc"`, and fenced `jsonc` snippets use JSON
@@ -1780,13 +1780,15 @@ import {
1780
1780
 
1781
1781
  // src/resolveBlockVisual.ts
1782
1782
  import { materializeBlockLayers } from "@bendyline/squisq/doc";
1783
- function resolveBlockVisual(doc, block, theme, viewport) {
1783
+ function resolveBlockVisual(doc, block, theme, viewport, position = {
1784
+ blockIndex: 0,
1785
+ totalBlocks: 1
1786
+ }) {
1784
1787
  try {
1785
1788
  const slide = buildPreviewDoc({ ...doc, blocks: [block] }).blocks[0];
1786
1789
  if (!slide) return null;
1787
1790
  const ctx = {
1788
- blockIndex: 0,
1789
- totalBlocks: 1,
1791
+ ...position,
1790
1792
  theme,
1791
1793
  viewport,
1792
1794
  customTemplates: doc.customTemplates
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RecorderModal
3
- } from "./chunk-TCGWKYME.js";
3
+ } from "./chunk-LXGQA2SY.js";
4
4
 
5
5
  // src/recorder/RecorderButton.tsx
6
6
  import { useCallback, useState } from "react";
@@ -49,7 +49,7 @@ import {
49
49
  documentTitleFromFileName,
50
50
  resolveBlockVisual,
51
51
  useModalDialog
52
- } from "./chunk-TCGWKYME.js";
52
+ } from "./chunk-LXGQA2SY.js";
53
53
  import {
54
54
  Icon
55
55
  } from "./chunk-UYB5CPRE.js";
@@ -35541,15 +35541,8 @@ function moveSelectionToDropPoint(view, event) {
35541
35541
  // src/InlinePreviewGutter.tsx
35542
35542
  import { useLayoutEffect as useLayoutEffect13, useMemo as useMemo43, useRef as useRef49, useState as useState68 } from "react";
35543
35543
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS5 } from "@bendyline/squisq/schemas";
35544
- import {
35545
- flattenBlocks as flattenBlocks4,
35546
- materializeBlockLayers as materializeBlockLayers2,
35547
- coerceTemplateParams as coerceTemplateParams2,
35548
- DEFAULT_THEME as DEFAULT_THEME5,
35549
- deriveTemplateInputs as deriveTemplateInputs2,
35550
- extractBodyPlainText as extractBodyPlainText2
35551
- } from "@bendyline/squisq/doc";
35552
- import { extractPlainText as extractPlainText3, getChildren } from "@bendyline/squisq/markdown";
35544
+ import { flattenRenderableBlocks, DEFAULT_THEME as DEFAULT_THEME5 } from "@bendyline/squisq/doc";
35545
+ import { extractPlainText as extractPlainText3 } from "@bendyline/squisq/markdown";
35553
35546
  import { BlockRenderer as BlockRenderer3, MediaContext as MediaContext4 } from "@bendyline/squisq-react";
35554
35547
 
35555
35548
  // src/useHeadingLayout.ts
@@ -35572,17 +35565,17 @@ function useHeadingLayout(refInsideWrapper) {
35572
35565
  const recompute = () => {
35573
35566
  cancelAnimationFrame(raf);
35574
35567
  raf = requestAnimationFrame(() => {
35575
- const headings = Array.from(
35576
- wysiwygContainer.querySelectorAll("h1, h2, h3, h4, h5, h6")
35577
- );
35568
+ const anchors = blockAnchors(flatBlocks, wysiwygContainer);
35578
35569
  const wrapperRect = wrapper.getBoundingClientRect();
35579
35570
  const editorRect = wysiwygContainer.getBoundingClientRect();
35580
35571
  const next = [];
35581
35572
  flatBlocks.forEach((block, i) => {
35582
- const h2 = headings[i];
35573
+ const h2 = anchors[i];
35583
35574
  if (!h2) return;
35584
35575
  const top = h2.getBoundingClientRect().top - wrapperRect.top;
35585
- const nextH = headings[i + 1];
35576
+ let nextIndex = i + 1;
35577
+ while (nextIndex < anchors.length && !anchors[nextIndex]) nextIndex++;
35578
+ const nextH = anchors[nextIndex];
35586
35579
  const bottom = nextH ? nextH.getBoundingClientRect().top - wrapperRect.top : editorRect.bottom - wrapperRect.top;
35587
35580
  next.push({
35588
35581
  block,
@@ -35648,11 +35641,11 @@ function useHeadingLayout(refInsideWrapper) {
35648
35641
  const layoutInfo = monacoEditor.getLayoutInfo();
35649
35642
  const next = [];
35650
35643
  flatBlocks.forEach((block, i) => {
35651
- const line = block.sourceHeading?.position?.start.line;
35644
+ const line = blockStartLine(block);
35652
35645
  if (typeof line !== "number") return;
35653
35646
  const lineTop = monacoEditor.getTopForLineNumber(line) - scrollTop + monacoTop;
35654
35647
  const nextBlock = flatBlocks[i + 1];
35655
- const nextLine = nextBlock?.sourceHeading?.position?.start.line;
35648
+ const nextLine = nextBlock ? blockStartLine(nextBlock) : void 0;
35656
35649
  const bottom = typeof nextLine === "number" ? monacoEditor.getTopForLineNumber(nextLine) - scrollTop + monacoTop : monacoTop + layoutInfo.height;
35657
35650
  const tplName = block.sourceHeading?.templateAnnotation?.template;
35658
35651
  next.push({
@@ -35700,10 +35693,10 @@ function useHeadingLayout(refInsideWrapper) {
35700
35693
  const wrapper = node2 ? findWrapper(node2) : null;
35701
35694
  const wysiwygContainer = wrapper?.querySelector(".squisq-wysiwyg-container");
35702
35695
  if (!wysiwygContainer) return;
35703
- const headings = wysiwygContainer.querySelectorAll("h1, h2, h3, h4, h5, h6");
35704
35696
  const index2 = flatBlocks.findIndex((b) => b.id === block.id);
35705
- if (index2 < 0 || index2 >= headings.length) return;
35706
- headings[index2].scrollIntoView({ behavior: "smooth", block: "start" });
35697
+ const anchor = blockAnchors(flatBlocks, wysiwygContainer)[index2];
35698
+ if (!anchor) return;
35699
+ anchor.scrollIntoView({ behavior: "smooth", block: "start" });
35707
35700
  if (tiptapEditor) {
35708
35701
  try {
35709
35702
  tiptapEditor.chain().focus().run();
@@ -35713,7 +35706,7 @@ function useHeadingLayout(refInsideWrapper) {
35713
35706
  return;
35714
35707
  }
35715
35708
  if (activeView === "raw" && monacoEditor) {
35716
- const line = block.sourceHeading?.position?.start.line;
35709
+ const line = blockStartLine(block);
35717
35710
  if (typeof line !== "number") return;
35718
35711
  monacoEditor.revealLineInCenter(line);
35719
35712
  monacoEditor.setPosition({ lineNumber: line, column: 1 });
@@ -35729,6 +35722,23 @@ function useHeadingLayout(refInsideWrapper) {
35729
35722
  ready: entries.length > 0 || pageEdges != null
35730
35723
  };
35731
35724
  }
35725
+ function blockAnchors(blocks, container) {
35726
+ const surface = container.querySelector(".squisq-wysiwyg-editor");
35727
+ const headings = (surface ?? container).querySelectorAll(
35728
+ ":scope > h1, :scope > h2, :scope > h3, :scope > h4, :scope > h5, :scope > h6"
35729
+ );
35730
+ let headingIndex = 0;
35731
+ return blocks.map((block, index2) => {
35732
+ if (block.sourceHeading) return headings[headingIndex++] ?? null;
35733
+ if (index2 === 0 && block.contents?.length) {
35734
+ return (surface ?? container).firstElementChild;
35735
+ }
35736
+ return null;
35737
+ });
35738
+ }
35739
+ function blockStartLine(block) {
35740
+ return block.sourceHeading?.position?.start.line ?? block.contents?.[0]?.position?.start.line;
35741
+ }
35732
35742
  function findWrapper(node2) {
35733
35743
  let cur = node2.parentElement;
35734
35744
  while (cur) {
@@ -35842,154 +35852,6 @@ function usePreviewProjection(doc, transformStyle, workspaceContainer, documentT
35842
35852
 
35843
35853
  // src/InlinePreviewGutter.tsx
35844
35854
  import { Fragment as Fragment23, jsx as jsx71, jsxs as jsxs57 } from "react/jsx-runtime";
35845
- function isAnnotated(block) {
35846
- const annotation = block.sourceHeading?.templateAnnotation;
35847
- if (!annotation) return false;
35848
- return !!annotation.template;
35849
- }
35850
- function extractListItems2(contents) {
35851
- if (!contents) return [];
35852
- const items = [];
35853
- for (const node2 of contents) {
35854
- if (node2.type === "list") {
35855
- for (const item of node2.children) {
35856
- const text = extractPlainText3(item).trim();
35857
- if (text) items.push(text);
35858
- }
35859
- }
35860
- }
35861
- return items;
35862
- }
35863
- function parseDim(raw) {
35864
- if (raw === void 0) return void 0;
35865
- const n = parseFloat(raw);
35866
- return Number.isFinite(n) && n > 0 ? n : void 0;
35867
- }
35868
- function extractBlockImages(contents) {
35869
- if (!contents || contents.length === 0) return [];
35870
- const images = [];
35871
- function walkHtml(node2) {
35872
- if (node2.type === "htmlElement" && node2.tagName === "img") {
35873
- const src = node2.attributes?.src;
35874
- if (src) {
35875
- images.push({
35876
- src,
35877
- alt: node2.attributes?.alt ?? "",
35878
- width: parseDim(node2.attributes?.width),
35879
- height: parseDim(node2.attributes?.height)
35880
- });
35881
- }
35882
- }
35883
- if (Array.isArray(node2.children)) {
35884
- for (const child of node2.children) {
35885
- walkHtml(child);
35886
- }
35887
- }
35888
- }
35889
- function walk(node2) {
35890
- if ("type" in node2 && node2.type === "image" && "url" in node2) {
35891
- const img = node2;
35892
- if (img.url) images.push({ src: img.url, alt: img.alt ?? "" });
35893
- }
35894
- if ("type" in node2 && node2.type === "htmlBlock") {
35895
- const block = node2;
35896
- for (const child of block.htmlChildren ?? []) {
35897
- walkHtml(child);
35898
- }
35899
- }
35900
- for (const child of getChildren(node2)) walk(child);
35901
- }
35902
- for (const node2 of contents) walk(node2);
35903
- return images;
35904
- }
35905
- function collectImagesDeep(block) {
35906
- const images = [];
35907
- const seen = /* @__PURE__ */ new Set();
35908
- function visit(b) {
35909
- for (const img of extractBlockImages(b.contents)) {
35910
- if (seen.has(img.src)) continue;
35911
- seen.add(img.src);
35912
- images.push(img);
35913
- }
35914
- for (const child of b.children ?? []) visit(child);
35915
- }
35916
- visit(block);
35917
- return images;
35918
- }
35919
- function extractTableData(contents) {
35920
- if (!contents) return null;
35921
- for (const node2 of contents) {
35922
- if (node2.type === "table") {
35923
- const table = node2;
35924
- const [headerRow, ...bodyRows] = table.children;
35925
- if (!headerRow) return null;
35926
- const headers = headerRow.children.map((cell) => extractPlainText3(cell).trim());
35927
- const rows = bodyRows.map((row) => row.children.map((cell) => extractPlainText3(cell).trim()));
35928
- return { headers, rows, align: table.align };
35929
- }
35930
- }
35931
- return null;
35932
- }
35933
- function getTemplateDefaults(templateName, headingText2, bodyText, contents, images = []) {
35934
- switch (templateName) {
35935
- case "statHighlight":
35936
- return deriveTemplateInputs2(templateName, headingText2, contents, { placeholders: true }) ?? {
35937
- stat: headingText2,
35938
- description: bodyText || headingText2
35939
- };
35940
- case "quote":
35941
- case "fullBleedQuote":
35942
- case "pullQuote":
35943
- return { quote: bodyText || headingText2 };
35944
- case "factCard":
35945
- return { fact: headingText2, explanation: bodyText || headingText2 };
35946
- case "comparisonBar":
35947
- return { leftLabel: "A", leftValue: 60, rightLabel: "B", rightValue: 40 };
35948
- case "list": {
35949
- const items = extractListItems2(contents);
35950
- return { items: items.length > 0 ? items : ["Item 1", "Item 2", "Item 3"] };
35951
- }
35952
- case "definitionCard":
35953
- return { term: headingText2, definition: bodyText || headingText2 };
35954
- case "dateEvent":
35955
- return { date: headingText2, description: bodyText || headingText2 };
35956
- case "dataTable": {
35957
- const tableData = extractTableData(contents);
35958
- return tableData ?? { headers: ["Column"], rows: [["Data"]] };
35959
- }
35960
- case "imageWithCaption": {
35961
- const first = images[0];
35962
- return {
35963
- imageSrc: first?.src ?? "",
35964
- imageAlt: first?.alt ?? headingText2,
35965
- caption: bodyText || headingText2,
35966
- captionPosition: "bottom"
35967
- };
35968
- }
35969
- case "leftFeature":
35970
- case "rightFeature": {
35971
- const first = images[0];
35972
- return {
35973
- imageSrc: first?.src ?? "",
35974
- imageAlt: first?.alt ?? headingText2,
35975
- imageWidth: first?.width,
35976
- imageHeight: first?.height,
35977
- title: headingText2,
35978
- body: bodyText
35979
- };
35980
- }
35981
- case "videoWithCaption": {
35982
- const first = images[0];
35983
- return {
35984
- videoSrc: first?.src ?? "",
35985
- caption: bodyText || headingText2,
35986
- captionPosition: "bottom"
35987
- };
35988
- }
35989
- default:
35990
- return {};
35991
- }
35992
- }
35993
35855
  var BAR_RIGHT_OFFSET = 14;
35994
35856
  var CARD_LABEL_OFFSET = 16;
35995
35857
  var EXTENT_TOP_PAD = CARD_LABEL_OFFSET;
@@ -36011,65 +35873,21 @@ function InlinePreviewGutter({
36011
35873
  const activeTheme = previewSettings?.activeTheme ?? DEFAULT_THEME5;
36012
35874
  const items = useMemo43(() => {
36013
35875
  if (!previewDoc || !previewDoc.blocks.length) return [];
36014
- const flat = flattenBlocks4(previewDoc.blocks);
36015
- const totalBlocks = flat.length;
35876
+ const flat = flattenRenderableBlocks(previewDoc.blocks);
36016
35877
  const result = [];
36017
35878
  flat.forEach((block, index2) => {
36018
- if (!isAnnotated(block)) return;
36019
- const annotation = block.sourceHeading.templateAnnotation;
36020
- const template = annotation.template;
36021
- const headingText2 = block.sourceHeading ? extractPlainText3(block.sourceHeading) : "";
36022
- const bodyText = extractBodyPlainText2(block.contents);
36023
- const templateBlock = {
36024
- id: block.id,
36025
- template,
36026
- startTime: 0,
36027
- duration: 1,
36028
- audioSegment: 0,
36029
- title: headingText2,
36030
- contents: block.contents,
36031
- children: block.children,
36032
- ...getTemplateDefaults(
36033
- template,
36034
- headingText2,
36035
- bodyText,
36036
- block.contents,
36037
- collectImagesDeep(block)
36038
- ),
36039
- // Async sidecar resolution stores its bounded table window here.
36040
- // Forward it before authored params/overrides so document-mode cards
36041
- // render the same CSV/XLSX data as block and full-preview modes.
36042
- ...block.templateData,
36043
- // Authored `{[…]}` params are raw strings. Coerce them per the
36044
- // template's input descriptors, as the full preview does, or a
36045
- // template with structured inputs renders nothing — twoColumn needs
36046
- // `left="Web|Start in a browser"` as `{ label, sublabel }`.
36047
- ...coerceTemplateParams2(template, { ...annotation.params, ...block.templateOverrides }).input
36048
- };
36049
- const ctx = {
35879
+ const visual = resolveBlockVisual(previewDoc, block, activeTheme, viewport, {
36050
35880
  blockIndex: index2,
36051
- totalBlocks,
36052
- theme: activeTheme,
36053
- viewport,
36054
- customTemplates: previewDoc.customTemplates
36055
- };
36056
- try {
36057
- const { layers } = materializeBlockLayers2(templateBlock, ctx);
36058
- const visualBlock = {
36059
- ...block,
36060
- layers,
36061
- template
36062
- };
36063
- result.push({
36064
- id: block.id,
36065
- template,
36066
- headingText: headingText2,
36067
- block: visualBlock
36068
- });
36069
- } catch (err) {
36070
- const message = err instanceof Error ? err.message : String(err);
36071
- console.warn(`[InlinePreviewGutter] Skipped block "${block.id}" (${template}): ${message}`);
36072
- }
35881
+ totalBlocks: flat.length
35882
+ });
35883
+ if (!visual) return;
35884
+ result.push({
35885
+ id: block.id,
35886
+ template: visual.template ?? "content",
35887
+ headingText: block.sourceHeading ? extractPlainText3(block.sourceHeading) : "",
35888
+ block: visual,
35889
+ sourceBlock: block
35890
+ });
36073
35891
  });
36074
35892
  return result;
36075
35893
  }, [previewDoc, viewport, activeTheme]);
@@ -36222,7 +36040,7 @@ function InlinePreviewGutter({
36222
36040
  right: 12,
36223
36041
  visibility: hidden ? "hidden" : "visible"
36224
36042
  },
36225
- onClick: () => scrollToBlock(item.block),
36043
+ onClick: () => scrollToBlock(item.sourceBlock),
36226
36044
  children: [
36227
36045
  /* @__PURE__ */ jsxs57("div", { className: "squisq-inline-preview-card-label", children: [
36228
36046
  /* @__PURE__ */ jsx71("span", { className: "squisq-inline-preview-card-template", children: templateLabel(item.template) }),
@@ -36242,6 +36060,7 @@ function InlinePreviewGutter({
36242
36060
  BlockRenderer3,
36243
36061
  {
36244
36062
  block: item.block,
36063
+ buildPlayback: "all",
36245
36064
  blockTime: 0,
36246
36065
  basePath,
36247
36066
  viewport
@@ -36268,7 +36087,7 @@ import {
36268
36087
  useRef as useRef50,
36269
36088
  useState as useState69
36270
36089
  } from "react";
36271
- import { flattenBlocks as flattenBlocks5, hasTemplate as hasTemplate2 } from "@bendyline/squisq/doc";
36090
+ import { flattenBlocks as flattenBlocks4, hasTemplate as hasTemplate2 } from "@bendyline/squisq/doc";
36272
36091
  import { extractPlainText as extractPlainText4 } from "@bendyline/squisq/markdown";
36273
36092
 
36274
36093
  // src/outlineSource.ts
@@ -36420,7 +36239,7 @@ function OutlinePanel({ width, className, readOnly = false }) {
36420
36239
  };
36421
36240
  const blockModeActiveId = useMemo44(() => {
36422
36241
  if (layoutMode !== "block" || activeBlockStartLine == null || !doc) return null;
36423
- const match = flattenBlocks5(doc.blocks).find(
36242
+ const match = flattenBlocks4(doc.blocks).find(
36424
36243
  (b) => b.sourceHeading?.position?.start.line === activeBlockStartLine
36425
36244
  );
36426
36245
  return match?.id ?? null;
@@ -36441,7 +36260,7 @@ function OutlinePanel({ width, className, readOnly = false }) {
36441
36260
  const wysiwygContainer = wrapper?.querySelector(".squisq-wysiwyg-container");
36442
36261
  if (!wysiwygContainer) return;
36443
36262
  const headings = wysiwygContainer.querySelectorAll("h1, h2, h3, h4, h5, h6");
36444
- const blocks = current.doc ? flattenBlocks5(current.doc.blocks) : [];
36263
+ const blocks = current.doc ? flattenBlocks4(current.doc.blocks) : [];
36445
36264
  const index2 = blocks.findIndex((candidate) => candidate.id === block.id);
36446
36265
  if (index2 < 0 || index2 >= headings.length) return;
36447
36266
  headings[index2].scrollIntoView({ behavior: "smooth", block: "start" });
@@ -36718,7 +36537,7 @@ function OutlineNode({
36718
36537
  }
36719
36538
  function useActiveOutlineBlockId() {
36720
36539
  const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
36721
- const flatBlocks = useMemo44(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
36540
+ const flatBlocks = useMemo44(() => doc ? flattenBlocks4(doc.blocks) : [], [doc]);
36722
36541
  const flatBlocksRef = useRef50(flatBlocks);
36723
36542
  flatBlocksRef.current = flatBlocks;
36724
36543
  const headingLocations = flatBlocks.map((block) => `${block.id}:${block.sourceHeading?.position?.start.line ?? ""}`).join("\0");
@@ -36796,7 +36615,7 @@ function sameOutlineStructure(previous, next) {
36796
36615
  return true;
36797
36616
  }
36798
36617
  function findLiveBlock(doc, blockId) {
36799
- return doc ? flattenBlocks5(doc.blocks).find((block) => block.id === blockId) ?? null : null;
36618
+ return doc ? flattenBlocks4(doc.blocks).find((block) => block.id === blockId) ?? null : null;
36800
36619
  }
36801
36620
  function findEditorWrapper(node2) {
36802
36621
  let current = node2.parentElement;
@@ -37550,7 +37369,7 @@ import {
37550
37369
  getDocPlaybackDuration,
37551
37370
  VIEWPORT_PRESETS as VIEWPORT_PRESETS6
37552
37371
  } from "@bendyline/squisq/schemas";
37553
- import { flattenBlocks as flattenBlocks6, DEFAULT_THEME as DEFAULT_THEME6, getPinnedBlockMeta } from "@bendyline/squisq/doc";
37372
+ import { flattenBlocks as flattenBlocks5, DEFAULT_THEME as DEFAULT_THEME6, getPinnedBlockMeta } from "@bendyline/squisq/doc";
37554
37373
  import { createMediaTimeMap } from "@bendyline/squisq/mediaEdit";
37555
37374
  import { useProcessedAudio as useProcessedAudio2 } from "@bendyline/squisq-video-react/media-edit";
37556
37375
  import { MediaClipLayer, MediaContext as MediaContext5 } from "@bendyline/squisq-react";
@@ -38148,7 +37967,7 @@ function TimelineTrack({
38148
37967
  const [itemMenu, setItemMenu] = useState73(null);
38149
37968
  const [pxPerSecond, setPxPerSecond] = useState73(DEFAULT_PX_PER_SECOND);
38150
37969
  const scrollRef = useRef55(null);
38151
- const blocks = useMemo47(() => doc ? flattenBlocks6(doc.blocks) : [], [doc]);
37970
+ const blocks = useMemo47(() => doc ? flattenBlocks5(doc.blocks) : [], [doc]);
38152
37971
  const previewSettings = usePreviewSettingsOptional();
38153
37972
  const previewTheme = previewSettings?.activeTheme ?? DEFAULT_THEME6;
38154
37973
  const visualByBlock = useMemo47(() => {
@@ -38200,7 +38019,7 @@ function TimelineTrack({
38200
38019
  const rawClipById = useMemo47(() => {
38201
38020
  const map = /* @__PURE__ */ new Map();
38202
38021
  if (doc) {
38203
- for (const b of flattenBlocks6(doc.blocks)) for (const m of b.media ?? []) map.set(m.id, m);
38022
+ for (const b of flattenBlocks5(doc.blocks)) for (const m of b.media ?? []) map.set(m.id, m);
38204
38023
  for (const m of doc.documentMedia ?? []) map.set(m.id, m);
38205
38024
  }
38206
38025
  return map;
@@ -41954,7 +41773,7 @@ import { useEffect as useEffect72, useRef as useRef67, useState as useState86, u
41954
41773
  // src/BlockPreviewPanel.tsx
41955
41774
  import { useMemo as useMemo56 } from "react";
41956
41775
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS7 } from "@bendyline/squisq/schemas";
41957
- import { flattenBlocks as flattenBlocks7, DEFAULT_THEME as DEFAULT_THEME7 } from "@bendyline/squisq/doc";
41776
+ import { flattenBlocks as flattenBlocks6, DEFAULT_THEME as DEFAULT_THEME7 } from "@bendyline/squisq/doc";
41958
41777
  import { jsx as jsx90 } from "react/jsx-runtime";
41959
41778
  function BlockPreviewPanel({ basePath = "/" }) {
41960
41779
  const { doc, activeBlockStartLine, mediaProvider, workspaceContainer, fileName, mediaRevision } = useEditorContext();
@@ -41965,7 +41784,7 @@ function BlockPreviewPanel({ basePath = "/" }) {
41965
41784
  const previewDoc = projection?.contentDoc ?? doc;
41966
41785
  const block = useMemo56(() => {
41967
41786
  if (!previewDoc) return null;
41968
- const blocks = flattenBlocks7(previewDoc.blocks);
41787
+ const blocks = flattenBlocks6(previewDoc.blocks);
41969
41788
  if (blocks.length === 0) return null;
41970
41789
  return blocks.find((b) => b.sourceHeading?.position?.start.line === activeBlockStartLine) ?? blocks[0];
41971
41790
  }, [previewDoc, activeBlockStartLine]);
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CodeContext, E as EditorHostMode, S as SceneTextChannel, a as CalcEngineFactory, b as EditorView$1, c as CsvSourceMeta, X as XlsxSourceMeta, F as FormulaEditRecord } from './shell-D9E73nri.js';
2
- export { A as ApplySourceEditsOptions, B as BlockInsertionBuilder, d as BlockInsertionContext, e as BlockPlacement, f as BlockRange, g as BlockSlice, h as BlockTagVisibility, i as CodeContextSection, j as CoverImageSaveOutput, D as DashboardImageSaveOutput, k as DocumentLinkCandidate, l as DocumentLinkProvider, m as EditorActions, n as EditorColorScheme, o as EditorContextMenuContext, p as EditorContextMenuItem, q as EditorContextMenuItemVisibility, r as EditorContextMenuProvider, s as EditorContextMenuProviderProps, t as EditorContextValue, u as EditorInsertMenuItem, v as EditorMode, w as EditorProvider, x as EditorProviderProps, y as EditorSelectionInfo, z as EditorShell, G as EditorShellProps, H as EditorState, I as FindOptions, J as FindRequest, K as FormulaSessionOptions, L as ImageDisplayMode, M as IngestedSidecar, N as InsertBlockOptions, O as LayoutMode, P as MentionCandidate, Q as MentionProvider, R as OutlineBlock, T as OutlineInsertion, U as PreviewPanel, V as PreviewPanelProps, W as RawEditor, Y as RawEditorProps, Z as ThemeInheritance, _ as ViewPreferences, $ as WriteCanvasSettings, a0 as WysiwygEditor, a1 as WysiwygEditorProps, a2 as XLSX_LOCKED_REASON, a3 as XlsxFormulaSession, a4 as applySourceEditsToText, a5 as blockInsertionPoint, a6 as createXlsxFormulaSession, a7 as getBlockSlices, a8 as headingDepthForInsertion, a9 as ingestSidecarBytes, aa as joinBlockAt, ab as lineToOffset, ac as minimalReplaceEdit, ad as normalizeSourceEdits, ae as offsetToLine, af as resolveOutlineInsertion, ag as sliceIndexAtOffset, ah as sourceOutline, ai as spliceBlock, aj as useEditorContext, ak as useEditorContextMenuItems, al as useEditorInsertMenuItems } from './shell-D9E73nri.js';
1
+ import { C as CodeContext, E as EditorHostMode, S as SceneTextChannel, a as CalcEngineFactory, b as EditorView$1, c as CsvSourceMeta, X as XlsxSourceMeta, F as FormulaEditRecord } from './shell-DXhttvsO.js';
2
+ export { A as ApplySourceEditsOptions, B as BlockInsertionBuilder, d as BlockInsertionContext, e as BlockPlacement, f as BlockRange, g as BlockSlice, h as BlockTagVisibility, i as CodeContextSection, j as CoverImageSaveOutput, D as DashboardImageSaveOutput, k as DocumentLinkCandidate, l as DocumentLinkProvider, m as EditorActions, n as EditorColorScheme, o as EditorContextMenuContext, p as EditorContextMenuItem, q as EditorContextMenuItemVisibility, r as EditorContextMenuProvider, s as EditorContextMenuProviderProps, t as EditorContextValue, u as EditorInsertMenuItem, v as EditorMode, w as EditorProvider, x as EditorProviderProps, y as EditorSelectionInfo, z as EditorShell, G as EditorShellProps, H as EditorState, I as FindOptions, J as FindRequest, K as FormulaSessionOptions, L as ImageDisplayMode, M as IngestedSidecar, N as InsertBlockOptions, O as LayoutMode, P as MentionCandidate, Q as MentionProvider, R as OutlineBlock, T as OutlineInsertion, U as PreviewPanel, V as PreviewPanelProps, W as RawEditor, Y as RawEditorProps, Z as ThemeInheritance, _ as ViewPreferences, $ as WriteCanvasSettings, a0 as WysiwygEditor, a1 as WysiwygEditorProps, a2 as XLSX_LOCKED_REASON, a3 as XlsxFormulaSession, a4 as applySourceEditsToText, a5 as blockInsertionPoint, a6 as createXlsxFormulaSession, a7 as getBlockSlices, a8 as headingDepthForInsertion, a9 as ingestSidecarBytes, aa as joinBlockAt, ab as lineToOffset, ac as minimalReplaceEdit, ad as normalizeSourceEdits, ae as offsetToLine, af as resolveOutlineInsertion, ag as sliceIndexAtOffset, ah as sourceOutline, ai as spliceBlock, aj as useEditorContext, ak as useEditorContextMenuItems, al as useEditorInsertMenuItems } from './shell-DXhttvsO.js';
3
3
  import * as react from 'react';
4
4
  import { ReactNode, CSSProperties, ReactElement } from 'react';
5
5
  import { Doc, ScheduledClip, VideoPlacement, VideoPipSize, VideoPipShape, VideoPipPosition, MediaEdits, MediaProvider, Theme, CustomTemplateDefinition, ThemeSeedColors, ViewportPreset, ViewportConfig, Block, MediaEntry, DiagramEdgeAnchor } from '@bendyline/squisq/schemas';
package/dist/index.js CHANGED
@@ -243,7 +243,7 @@ import {
243
243
  videoEmbedParagraphJson,
244
244
  viewStateFromBinding,
245
245
  writeHeadingViewState
246
- } from "./chunk-NESYESKT.js";
246
+ } from "./chunk-W63WEDBC.js";
247
247
  import {
248
248
  EditorProvider,
249
249
  applySourceEditsToText,
@@ -290,7 +290,7 @@ import {
290
290
  } from "./chunk-HLU6ZBS7.js";
291
291
  import {
292
292
  RecorderButton
293
- } from "./chunk-H3XGOKPT.js";
293
+ } from "./chunk-QZHUSMWA.js";
294
294
  import {
295
295
  RecorderDeviceQuickPicks,
296
296
  RecorderDeviceSettingsPanel,
@@ -315,7 +315,7 @@ import {
315
315
  unshownSlidesWarning,
316
316
  useMediaDevices,
317
317
  useMediaRecorder
318
- } from "./chunk-TCGWKYME.js";
318
+ } from "./chunk-LXGQA2SY.js";
319
319
  import {
320
320
  DEFAULT_RECORDER_DEVICE_SETTINGS,
321
321
  buildRecorderAudioConstraints,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RecorderButton
3
- } from "../chunk-H3XGOKPT.js";
3
+ } from "../chunk-QZHUSMWA.js";
4
4
  import {
5
5
  RecorderDeviceQuickPicks,
6
6
  RecorderDeviceSettingsPanel,
@@ -14,7 +14,7 @@ import {
14
14
  requestScreenStream,
15
15
  useMediaDevices,
16
16
  useMediaRecorder
17
- } from "../chunk-TCGWKYME.js";
17
+ } from "../chunk-LXGQA2SY.js";
18
18
  import {
19
19
  DEFAULT_RECORDER_DEVICE_SETTINGS,
20
20
  buildRecorderAudioConstraints,
@@ -1,4 +1,4 @@
1
- export { h as BlockTagVisibility, k as DocumentLinkCandidate, l as DocumentLinkProvider, m as EditorActions, n as EditorColorScheme, o as EditorContextMenuContext, p as EditorContextMenuItem, q as EditorContextMenuItemVisibility, r as EditorContextMenuProvider, s as EditorContextMenuProviderProps, t as EditorContextValue, E as EditorHostMode, u as EditorInsertMenuItem, v as EditorMode, w as EditorProvider, x as EditorProviderProps, z as EditorShell, G as EditorShellProps, H as EditorState, b as EditorView, L as ImageDisplayMode, O as LayoutMode, P as MentionCandidate, Q as MentionProvider, U as PreviewPanel, V as PreviewPanelProps, W as RawEditor, Y as RawEditorProps, Z as ThemeInheritance, _ as ViewPreferences, a0 as WysiwygEditor, a1 as WysiwygEditorProps, aj as useEditorContext, ak as useEditorContextMenuItems, al as useEditorInsertMenuItems } from '../shell-D9E73nri.js';
1
+ export { h as BlockTagVisibility, k as DocumentLinkCandidate, l as DocumentLinkProvider, m as EditorActions, n as EditorColorScheme, o as EditorContextMenuContext, p as EditorContextMenuItem, q as EditorContextMenuItemVisibility, r as EditorContextMenuProvider, s as EditorContextMenuProviderProps, t as EditorContextValue, E as EditorHostMode, u as EditorInsertMenuItem, v as EditorMode, w as EditorProvider, x as EditorProviderProps, z as EditorShell, G as EditorShellProps, H as EditorState, b as EditorView, L as ImageDisplayMode, O as LayoutMode, P as MentionCandidate, Q as MentionProvider, U as PreviewPanel, V as PreviewPanelProps, W as RawEditor, Y as RawEditorProps, Z as ThemeInheritance, _ as ViewPreferences, a0 as WysiwygEditor, a1 as WysiwygEditorProps, aj as useEditorContext, ak as useEditorContextMenuItems, al as useEditorInsertMenuItems } from '../shell-DXhttvsO.js';
2
2
  import 'react';
3
3
  import '@bendyline/squisq/table';
4
4
  import '@bendyline/squisq-calc';
@@ -5,7 +5,7 @@ import {
5
5
  RawEditor,
6
6
  WysiwygEditor,
7
7
  useEditorContextMenuItems
8
- } from "../chunk-NESYESKT.js";
8
+ } from "../chunk-W63WEDBC.js";
9
9
  import {
10
10
  EditorProvider,
11
11
  useEditorContext,
@@ -16,7 +16,7 @@ import "../chunk-A2H3JOA5.js";
16
16
  import "../chunk-LRUBYTKW.js";
17
17
  import "../chunk-MHG4KPMA.js";
18
18
  import "../chunk-HLU6ZBS7.js";
19
- import "../chunk-TCGWKYME.js";
19
+ import "../chunk-LXGQA2SY.js";
20
20
  import "../chunk-LRZJD5YD.js";
21
21
  import "../chunk-UYB5CPRE.js";
22
22
  import "../chunk-DJS5I5NO.js";
@@ -1666,8 +1666,8 @@ interface EditorShellProps {
1666
1666
  onImageExport?: (blob: Blob, format: 'png' | 'jpeg' | 'webp') => void;
1667
1667
  /**
1668
1668
  * Show an inline preview gutter to the right of the WYSIWYG editor.
1669
- * The gutter renders one small SVG card per template-annotated block in
1670
- * the document, letting authors see their rendered output without
1669
+ * The gutter renders one small SVG card per block, including blocks without
1670
+ * template tags, letting authors see their rendered output without
1671
1671
  * leaving Edit mode. Auto-hidden via container query when the editor
1672
1672
  * body is narrower than ~720px. Defaults to `false`.
1673
1673
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq-editor-react",
3
- "version": "2.12.5",
3
+ "version": "2.12.7",
4
4
  "description": "React editor shell with raw/WYSIWYG/preview modes for Squisq documents",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -102,12 +102,12 @@
102
102
  }
103
103
  },
104
104
  "dependencies": {
105
- "@bendyline/squisq": "2.12.3",
105
+ "@bendyline/squisq": "2.12.4",
106
106
  "@bendyline/squisq-calc": "2.11.2",
107
- "@bendyline/squisq-formats": "2.7.3",
108
- "@bendyline/squisq-grid-react": "2.11.26",
109
- "@bendyline/squisq-react": "2.12.4",
110
- "@bendyline/squisq-video-react": "2.5.4",
107
+ "@bendyline/squisq-formats": "2.7.4",
108
+ "@bendyline/squisq-grid-react": "2.11.27",
109
+ "@bendyline/squisq-react": "2.12.5",
110
+ "@bendyline/squisq-video-react": "2.5.6",
111
111
  "@fortawesome/fontawesome-free": "7.3.1",
112
112
  "@tiptap/core": "2.27.3",
113
113
  "@tiptap/extension-heading": "2.27.3",