@bendyline/squisq-editor-react 2.13.23 → 2.13.24

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.
@@ -23457,6 +23457,7 @@ function Toolbar({
23457
23457
  slotAfterActions,
23458
23458
  slotRight,
23459
23459
  showPlayTab = true,
23460
+ showViewTabs = true,
23460
23461
  showFormattingControls = true,
23461
23462
  showInsertControls = true,
23462
23463
  hostMode = "document",
@@ -24819,7 +24820,7 @@ ${TASK_LIST_MARKDOWN}
24819
24820
  }
24820
24821
  ),
24821
24822
  !findMode && slotLeft,
24822
- /* @__PURE__ */ jsx55(EditorViewTabs, { showPlayTab, hostMode }),
24823
+ showViewTabs && /* @__PURE__ */ jsx55(EditorViewTabs, { showPlayTab, hostMode }),
24823
24824
  findMode ? /* @__PURE__ */ jsx55(
24824
24825
  FindToolbar,
24825
24826
  {
@@ -35803,7 +35804,7 @@ function persistFromWrite(bodyMd, state) {
35803
35804
  import { useCallback as useCallback45, useEffect as useEffect57, useMemo as useMemo45, useRef as useRef54, useState as useState68 } from "react";
35804
35805
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
35805
35806
  import { Selection as Selection2 } from "@tiptap/pm/state";
35806
- import { Extension as Extension20 } from "@tiptap/core";
35807
+ import { Extension as Extension21 } from "@tiptap/core";
35807
35808
  import StarterKit2 from "@tiptap/starter-kit";
35808
35809
  import Table from "@tiptap/extension-table";
35809
35810
  import TableRow from "@tiptap/extension-table-row";
@@ -37847,6 +37848,94 @@ function safeFontFamily(value) {
37847
37848
  return trimmed;
37848
37849
  }
37849
37850
 
37851
+ // src/footnotes/FootnoteSyntaxExtension.ts
37852
+ import { Extension as Extension20 } from "@tiptap/core";
37853
+ import { Plugin as Plugin21, PluginKey as PluginKey21 } from "@tiptap/pm/state";
37854
+ import { Decoration as Decoration16, DecorationSet as DecorationSet16 } from "@tiptap/pm/view";
37855
+ var REFERENCE = /\[\^([^\]\s]+)\]/g;
37856
+ var DEFINITION = /^\[\^([^\]\s]+)\]:[ \t]*/;
37857
+ function isCodeText(node2) {
37858
+ return node2.marks.some((mark) => mark.type.name === "code");
37859
+ }
37860
+ function scanFootnoteSyntax(doc) {
37861
+ const ranges = [];
37862
+ const definitions = [];
37863
+ const texts = /* @__PURE__ */ new Map();
37864
+ doc.descendants((node2, pos) => {
37865
+ if (node2.type.spec.code) return false;
37866
+ if (!node2.isTextblock) return true;
37867
+ const content = pos + 1;
37868
+ let skipUntil = -1;
37869
+ if (node2.type.name === "paragraph") {
37870
+ const definition = DEFINITION.exec(node2.textContent);
37871
+ if (definition) {
37872
+ const label = definition[1];
37873
+ definitions.push({ from: pos, to: pos + node2.nodeSize });
37874
+ ranges.push({
37875
+ kind: "definition-label",
37876
+ from: content,
37877
+ to: content + label.length + 4,
37878
+ label
37879
+ });
37880
+ skipUntil = content + definition[0].length;
37881
+ if (!texts.has(label)) {
37882
+ const text = node2.textContent.slice(definition[0].length).trim();
37883
+ if (text) texts.set(label, text);
37884
+ }
37885
+ }
37886
+ }
37887
+ node2.forEach((child, offset) => {
37888
+ if (!child.isText || !child.text || isCodeText(child)) return;
37889
+ const start = content + offset;
37890
+ for (const match of child.text.matchAll(REFERENCE)) {
37891
+ const from = start + match.index;
37892
+ if (from < skipUntil) continue;
37893
+ ranges.push({ kind: "reference", from, to: from + match[0].length, label: match[1] });
37894
+ }
37895
+ });
37896
+ return false;
37897
+ });
37898
+ return { ranges, definitions, texts };
37899
+ }
37900
+ function buildDecorations13(doc) {
37901
+ const { ranges, definitions, texts } = scanFootnoteSyntax(doc);
37902
+ if (ranges.length === 0) return DecorationSet16.empty;
37903
+ const decorations = [
37904
+ ...definitions.map(
37905
+ ({ from, to }) => Decoration16.node(from, to, { class: "squisq-footnote-definition" })
37906
+ ),
37907
+ ...ranges.map(({ kind, from, to, label }) => {
37908
+ if (kind === "definition-label") {
37909
+ return Decoration16.inline(from, to, { class: "squisq-footnote-label" });
37910
+ }
37911
+ const text = texts.get(label);
37912
+ return Decoration16.inline(from, to, {
37913
+ class: text ? "squisq-footnote-ref" : "squisq-footnote-ref squisq-footnote-ref--missing",
37914
+ title: text ? `Footnote: ${text}` : `Footnote "${label}" has no text yet`
37915
+ });
37916
+ })
37917
+ ];
37918
+ return DecorationSet16.create(doc, decorations);
37919
+ }
37920
+ var FOOTNOTE_SYNTAX_KEY = new PluginKey21("squisq-footnote-syntax");
37921
+ var FootnoteSyntaxExtension = Extension20.create({
37922
+ name: "squisqFootnoteSyntax",
37923
+ addProseMirrorPlugins() {
37924
+ return [
37925
+ new Plugin21({
37926
+ key: FOOTNOTE_SYNTAX_KEY,
37927
+ state: {
37928
+ init: (_2, state) => buildDecorations13(state.doc),
37929
+ apply: (transaction, previous, _oldState, newState) => transaction.docChanged ? buildDecorations13(newState.doc) : previous
37930
+ },
37931
+ props: {
37932
+ decorations: (state) => FOOTNOTE_SYNTAX_KEY.getState(state) ?? null
37933
+ }
37934
+ })
37935
+ ];
37936
+ }
37937
+ });
37938
+
37850
37939
  // src/accessoryFileLinks.ts
37851
37940
  var ACCESSORY_FILE_LINK_CLASS = "squisq-attachment-link";
37852
37941
  function syncAccessoryFileLinkPlaceholders(root, accessoryPaths) {
@@ -37858,17 +37947,27 @@ function syncAccessoryFileLinkPlaceholders(root, accessoryPaths) {
37858
37947
 
37859
37948
  // src/wysiwygMinimalSync.ts
37860
37949
  import { createDocument } from "@tiptap/core";
37950
+ import { Fragment as Fragment26 } from "@tiptap/pm/model";
37861
37951
  import { closeHistory } from "@tiptap/pm/history";
37952
+ function keepTrailingParagraph(current, next) {
37953
+ const trailing = current.lastChild;
37954
+ if (!trailing || withoutTrailingParagraph(current) === current) return next;
37955
+ if (!needsTrailingParagraph(next)) return next;
37956
+ return next.copy(next.content.append(Fragment26.from(trailing)));
37957
+ }
37862
37958
  function replaceDocumentMinimal(editor, content, frontmatter) {
37863
37959
  const { state } = editor;
37864
37960
  try {
37865
- const next = createDocument(
37866
- content,
37867
- editor.schema,
37868
- {},
37869
- {
37870
- errorOnInvalidContent: editor.options.enableContentCheck
37871
- }
37961
+ const next = keepTrailingParagraph(
37962
+ state.doc,
37963
+ createDocument(
37964
+ content,
37965
+ editor.schema,
37966
+ {},
37967
+ {
37968
+ errorOnInvalidContent: editor.options.enableContentCheck
37969
+ }
37970
+ )
37872
37971
  );
37873
37972
  const start = state.doc.content.findDiffStart(next.content);
37874
37973
  const metadataChanged = frontmatter !== void 0 && state.doc.attrs.sourceFrontmatter !== frontmatter;
@@ -37938,7 +38037,7 @@ var BLOCK_TAG_DATA_VALUES = {
37938
38037
  function pickEmptyPrompt() {
37939
38038
  return EMPTY_PROMPTS[Math.floor(Math.random() * EMPTY_PROMPTS.length)];
37940
38039
  }
37941
- var SourceFrontmatter = Extension20.create({
38040
+ var SourceFrontmatter = Extension21.create({
37942
38041
  name: "sourceFrontmatter",
37943
38042
  addOptions() {
37944
38043
  return { initial: "" };
@@ -38184,6 +38283,8 @@ function WysiwygEditor({
38184
38283
  buildMentionExtension(() => mentionProviderRef.current),
38185
38284
  InlineIcon,
38186
38285
  WikiLink.configure({ getSupport: () => wikiLinksRef.current }),
38286
+ // `[^note]` and `[^note]: …` read as footnotes; the Markdown is unchanged.
38287
+ FootnoteSyntaxExtension,
38187
38288
  FindHighlightExtension,
38188
38289
  ProofingExtension,
38189
38290
  ReviewExtension,
@@ -39132,7 +39233,7 @@ function useBlockPreviewItems(viewport, visibleIds) {
39132
39233
  }
39133
39234
 
39134
39235
  // src/InlinePreviewGutter.tsx
39135
- import { Fragment as Fragment26, jsx as jsx77, jsxs as jsxs59 } from "react/jsx-runtime";
39236
+ import { Fragment as Fragment27, jsx as jsx77, jsxs as jsxs59 } from "react/jsx-runtime";
39136
39237
  var BAR_RIGHT_OFFSET = 14;
39137
39238
  var CARD_LABEL_OFFSET = 16;
39138
39239
  var EXTENT_TOP_PAD = CARD_LABEL_OFFSET;
@@ -39345,7 +39446,7 @@ function InlinePreviewGutter({
39345
39446
  children: [
39346
39447
  /* @__PURE__ */ jsxs59("div", { className: "squisq-inline-preview-card-label", children: [
39347
39448
  /* @__PURE__ */ jsx77("span", { className: "squisq-inline-preview-card-template", children: templateLabel(item.template) }),
39348
- item.headingText && /* @__PURE__ */ jsxs59(Fragment26, { children: [
39449
+ item.headingText && /* @__PURE__ */ jsxs59(Fragment27, { children: [
39349
39450
  /* @__PURE__ */ jsx77("span", { className: "squisq-inline-preview-card-sep", children: "\u2014" }),
39350
39451
  /* @__PURE__ */ jsx77("span", { className: "squisq-inline-preview-card-title", children: item.headingText })
39351
39452
  ] })
@@ -40194,7 +40295,7 @@ function CodeContextSectionView({
40194
40295
  }
40195
40296
 
40196
40297
  // src/codeContext/CodeContextZones.tsx
40197
- import { Fragment as Fragment27, jsx as jsx80 } from "react/jsx-runtime";
40298
+ import { Fragment as Fragment28, jsx as jsx80 } from "react/jsx-runtime";
40198
40299
  function CodeContextZones({ options }) {
40199
40300
  const { monacoEditor } = useEditorContext();
40200
40301
  const [manager, setManager] = useState73(null);
@@ -40263,7 +40364,7 @@ function CodeContextZones({ options }) {
40263
40364
  [monacoEditor]
40264
40365
  );
40265
40366
  if (!manager) return null;
40266
- return /* @__PURE__ */ jsx80(Fragment27, { children: resolved.map(({ section }) => {
40367
+ return /* @__PURE__ */ jsx80(Fragment28, { children: resolved.map(({ section }) => {
40267
40368
  const domNode = manager.getDomNode(section.id);
40268
40369
  if (!domNode) return null;
40269
40370
  return createPortal15(
@@ -40861,7 +40962,7 @@ function timelineBars(clips) {
40861
40962
  // src/TimelineItemMenu.tsx
40862
40963
  import { useEffect as useEffect65, useLayoutEffect as useLayoutEffect16, useRef as useRef60, useState as useState75 } from "react";
40863
40964
  import { createPortal as createPortal16 } from "react-dom";
40864
- import { Fragment as Fragment28, jsx as jsx83, jsxs as jsxs63 } from "react/jsx-runtime";
40965
+ import { Fragment as Fragment29, jsx as jsx83, jsxs as jsxs63 } from "react/jsx-runtime";
40865
40966
  function TimelineItemMenu({
40866
40967
  anchor,
40867
40968
  target,
@@ -40936,7 +41037,7 @@ function TimelineItemMenu({
40936
41037
  onClearTiming: onBlockClearTiming,
40937
41038
  onTransition: onBlockTransition
40938
41039
  }
40939
- ) : /* @__PURE__ */ jsxs63(Fragment28, { children: [
41040
+ ) : /* @__PURE__ */ jsxs63(Fragment29, { children: [
40940
41041
  /* @__PURE__ */ jsx83(VideoMenu, { target, onPatch: onVideoPatch }),
40941
41042
  onEditMedia && /* @__PURE__ */ jsx83(
40942
41043
  "button",
@@ -40984,7 +41085,7 @@ function BlockMenu({
40984
41085
  };
40985
41086
  const pinned = explicitDuration || startTime !== "";
40986
41087
  return /* @__PURE__ */ jsxs63("div", { className: "squisq-timeline-item-menu-body", children: [
40987
- target.timingLocked ? /* @__PURE__ */ jsxs63(Fragment28, { children: [
41088
+ target.timingLocked ? /* @__PURE__ */ jsxs63(Fragment29, { children: [
40988
41089
  /* @__PURE__ */ jsxs63("p", { className: "squisq-timeline-item-menu-hint", children: [
40989
41090
  "Dynamic slides time each slide from the narration or reading pace, so this section's length and start can't be pinned.",
40990
41091
  pinned && " A pinned time here stops a narrated deck from playing."
@@ -41002,7 +41103,7 @@ function BlockMenu({
41002
41103
  children: "Clear pinned timing"
41003
41104
  }
41004
41105
  )
41005
- ] }) : /* @__PURE__ */ jsxs63(Fragment28, { children: [
41106
+ ] }) : /* @__PURE__ */ jsxs63(Fragment29, { children: [
41006
41107
  /* @__PURE__ */ jsxs63("label", { className: "squisq-timeline-item-menu-check", children: [
41007
41108
  /* @__PURE__ */ jsx83(
41008
41109
  "input",
@@ -41104,7 +41205,7 @@ function VideoMenu({
41104
41205
  }
41105
41206
  )
41106
41207
  ] }),
41107
- placed && /* @__PURE__ */ jsxs63(Fragment28, { children: [
41208
+ placed && /* @__PURE__ */ jsxs63(Fragment29, { children: [
41108
41209
  /* @__PURE__ */ jsxs63("label", { className: "squisq-timeline-item-menu-check", children: [
41109
41210
  /* @__PURE__ */ jsx83(
41110
41211
  "input",
@@ -41122,7 +41223,7 @@ function VideoMenu({
41122
41223
  ),
41123
41224
  /* @__PURE__ */ jsx83("span", { children: "Lock to block" })
41124
41225
  ] }),
41125
- placement === "picture-in-picture" && /* @__PURE__ */ jsxs63(Fragment28, { children: [
41226
+ placement === "picture-in-picture" && /* @__PURE__ */ jsxs63(Fragment29, { children: [
41126
41227
  /* @__PURE__ */ jsxs63("label", { className: "squisq-timeline-item-menu-field", children: [
41127
41228
  /* @__PURE__ */ jsx83("span", { className: "squisq-timeline-item-menu-label", children: "PIP size" }),
41128
41229
  /* @__PURE__ */ jsxs63(
@@ -44031,7 +44132,7 @@ function collectSlideshowDataSources(doc) {
44031
44132
  }
44032
44133
 
44033
44134
  // src/slideshow/SlideshowDataGrid.tsx
44034
- import { Fragment as Fragment29, jsx as jsx92 } from "react/jsx-runtime";
44135
+ import { Fragment as Fragment30, jsx as jsx92 } from "react/jsx-runtime";
44035
44136
  var EMPTY_CONTEXT = {
44036
44137
  container: null,
44037
44138
  mediaRevision: 0,
@@ -44161,7 +44262,7 @@ function SlideshowDataGridRenderer({
44161
44262
  const initialView = ready?.initialView ?? EMPTY_VIEW;
44162
44263
  const [view, setView] = useState80(initialView);
44163
44264
  useEffect71(() => setView(initialView), [initialView, provider]);
44164
- if (!provider || !ingest || !gridModule) return /* @__PURE__ */ jsx92(Fragment29, { children: fallback });
44265
+ if (!provider || !ingest || !gridModule) return /* @__PURE__ */ jsx92(Fragment30, { children: fallback });
44165
44266
  const { style } = layer.content;
44166
44267
  const rowHeight = Math.max(32, style.fontSize * 2.1);
44167
44268
  const footerHeight = Math.max(28, style.fontSize * 1.5);
@@ -44694,7 +44795,7 @@ function MediaPreviewDialog({
44694
44795
  }
44695
44796
 
44696
44797
  // src/MediaBin.tsx
44697
- import { Fragment as Fragment30, jsx as jsx95, jsxs as jsxs73 } from "react/jsx-runtime";
44798
+ import { Fragment as Fragment31, jsx as jsx95, jsxs as jsxs73 } from "react/jsx-runtime";
44698
44799
  function formatSize(bytes) {
44699
44800
  if (bytes < 1024) return `${bytes} B`;
44700
44801
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -45025,7 +45126,7 @@ function MediaBin({
45025
45126
  [openContextMenu, openPreview]
45026
45127
  );
45027
45128
  const previewKind = preview ? squisqMediaKind(preview.entry.mimeType) : "file";
45028
- return /* @__PURE__ */ jsxs73(Fragment30, { children: [
45129
+ return /* @__PURE__ */ jsxs73(Fragment31, { children: [
45029
45130
  /* @__PURE__ */ jsxs73(
45030
45131
  "div",
45031
45132
  {
@@ -45220,7 +45321,7 @@ ${formatSize(entry.size)}`,
45220
45321
 
45221
45322
  // src/DropZoneOverlay.tsx
45222
45323
  import { useState as useState84 } from "react";
45223
- import { Fragment as Fragment31, jsx as jsx96, jsxs as jsxs74 } from "react/jsx-runtime";
45324
+ import { Fragment as Fragment32, jsx as jsx96, jsxs as jsxs74 } from "react/jsx-runtime";
45224
45325
  function DropZoneOverlay({
45225
45326
  dragContentType,
45226
45327
  zoneProps,
@@ -45241,7 +45342,7 @@ function DropZoneOverlay({
45241
45342
  variant: "media"
45242
45343
  }
45243
45344
  ),
45244
- showText && /* @__PURE__ */ jsxs74(Fragment31, { children: [
45345
+ showText && /* @__PURE__ */ jsxs74(Fragment32, { children: [
45245
45346
  /* @__PURE__ */ jsx96(
45246
45347
  DropZone,
45247
45348
  {
@@ -45507,7 +45608,7 @@ import { useCallback as useCallback58, useRef as useRef70 } from "react";
45507
45608
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS9 } from "@bendyline/squisq/schemas";
45508
45609
  import { flattenBlocks as flattenBlocks8 } from "@bendyline/squisq/doc";
45509
45610
  import { BlockRenderer as BlockRenderer6, MediaContext as MediaContext7 } from "@bendyline/squisq-react";
45510
- import { Fragment as Fragment32, jsx as jsx99, jsxs as jsxs75 } from "react/jsx-runtime";
45611
+ import { Fragment as Fragment33, jsx as jsx99, jsxs as jsxs75 } from "react/jsx-runtime";
45511
45612
  function BlockPreviewList({
45512
45613
  basePath = "/",
45513
45614
  viewport = VIEWPORT_PRESETS9.landscape,
@@ -45555,7 +45656,7 @@ function BlockPreviewList({
45555
45656
  children: [
45556
45657
  /* @__PURE__ */ jsxs75("span", { className: "squisq-inline-preview-card-label", children: [
45557
45658
  /* @__PURE__ */ jsx99("span", { className: "squisq-inline-preview-card-template", children: templateLabel(item.template) }),
45558
- item.headingText && /* @__PURE__ */ jsxs75(Fragment32, { children: [
45659
+ item.headingText && /* @__PURE__ */ jsxs75(Fragment33, { children: [
45559
45660
  /* @__PURE__ */ jsx99("span", { className: "squisq-inline-preview-card-sep", "aria-hidden": "true", children: "\u2014" }),
45560
45661
  /* @__PURE__ */ jsx99("span", { className: "squisq-inline-preview-card-title", children: item.headingText })
45561
45662
  ] })
@@ -45707,7 +45808,7 @@ function useNavigationSheetSwipe({
45707
45808
  }
45708
45809
 
45709
45810
  // src/NavigationSheet.tsx
45710
- import { Fragment as Fragment33, jsx as jsx100, jsxs as jsxs76 } from "react/jsx-runtime";
45811
+ import { Fragment as Fragment34, jsx as jsx100, jsxs as jsxs76 } from "react/jsx-runtime";
45711
45812
  var PANEL_LABELS = {
45712
45813
  outline: "Outline",
45713
45814
  previews: "Block previews"
@@ -45797,7 +45898,7 @@ function NavigationSheet({
45797
45898
  role: "dialog",
45798
45899
  "aria-label": content ? PANEL_LABELS[content] : "Document navigation",
45799
45900
  tabIndex: -1,
45800
- children: content && /* @__PURE__ */ jsxs76(Fragment33, { children: [
45901
+ children: content && /* @__PURE__ */ jsxs76(Fragment34, { children: [
45801
45902
  /* @__PURE__ */ jsxs76("div", { className: "squisq-navigation-sheet-header", children: [
45802
45903
  /* @__PURE__ */ jsx100("div", { className: "squisq-navigation-sheet-tabs", role: "tablist", children: PANELS.map((option) => /* @__PURE__ */ jsx100(
45803
45904
  "button",
@@ -46275,7 +46376,7 @@ function StopIcon() {
46275
46376
  }
46276
46377
 
46277
46378
  // src/mediaEdit/MediaEditAudioSection.tsx
46278
- import { Fragment as Fragment34, jsx as jsx104, jsxs as jsxs80 } from "react/jsx-runtime";
46379
+ import { Fragment as Fragment35, jsx as jsx104, jsxs as jsxs80 } from "react/jsx-runtime";
46279
46380
  var STAGES = [
46280
46381
  {
46281
46382
  id: "highpass",
@@ -46558,7 +46659,7 @@ function MediaEditAudioSection({
46558
46659
  children: previewing ? "Rendering preview\u2026" : preview ? "Update preview" : "Create preview"
46559
46660
  }
46560
46661
  ) }),
46561
- preview != null && player.duration > 0 && /* @__PURE__ */ jsxs80(Fragment34, { children: [
46662
+ preview != null && player.duration > 0 && /* @__PURE__ */ jsxs80(Fragment35, { children: [
46562
46663
  /* @__PURE__ */ jsxs80("div", { className: "squisq-media-edit-playback", "data-playing": player.playing ?? void 0, children: [
46563
46664
  /* @__PURE__ */ jsx104("span", { className: "squisq-media-edit-playback__label", children: player.playing ? `${player.playing === "original" ? "Original" : "Processed"} from ${Math.round(preview.startSec)} s` : "Stopped" }),
46564
46665
  /* @__PURE__ */ jsx104(
@@ -47854,7 +47955,7 @@ function useSaveEditedCopy(manager, saveOutput) {
47854
47955
  }
47855
47956
 
47856
47957
  // src/mediaEdit/MediaEditModal.tsx
47857
- import { Fragment as Fragment35, jsx as jsx109, jsxs as jsxs85 } from "react/jsx-runtime";
47958
+ import { Fragment as Fragment36, jsx as jsx109, jsxs as jsxs85 } from "react/jsx-runtime";
47858
47959
  var TABS = [
47859
47960
  { id: "audio", label: "Audio cleanup" },
47860
47961
  { id: "cuts", label: "Cuts" },
@@ -47892,16 +47993,16 @@ function RenderStatusText({
47892
47993
  }) {
47893
47994
  switch (status.state) {
47894
47995
  case "ready":
47895
- return /* @__PURE__ */ jsx109(Fragment35, { children: "Processed audio is in use." });
47996
+ return /* @__PURE__ */ jsx109(Fragment36, { children: "Processed audio is in use." });
47896
47997
  case "queued":
47897
- return /* @__PURE__ */ jsx109(Fragment35, { children: "Waiting to process\u2026" });
47998
+ return /* @__PURE__ */ jsx109(Fragment36, { children: "Waiting to process\u2026" });
47898
47999
  case "rendering":
47899
- return /* @__PURE__ */ jsxs85(Fragment35, { children: [
48000
+ return /* @__PURE__ */ jsxs85(Fragment36, { children: [
47900
48001
  "Processing\u2026 ",
47901
48002
  percent(status)
47902
48003
  ] });
47903
48004
  case "failed":
47904
- return /* @__PURE__ */ jsxs85(Fragment35, { children: [
48005
+ return /* @__PURE__ */ jsxs85(Fragment36, { children: [
47905
48006
  "Processing failed: ",
47906
48007
  status.error,
47907
48008
  " ",
@@ -47998,7 +48099,7 @@ function MediaEditModal({ target, onClose }) {
47998
48099
  }
47999
48100
  )
48000
48101
  ] }),
48001
- !item ? /* @__PURE__ */ jsx109("p", { className: "squisq-media-edit-modal__empty", children: "This clip is no longer in the document." }) : !mediaEditRenders ? /* @__PURE__ */ jsx109("p", { className: "squisq-media-edit-modal__empty", children: "Media editing needs a media folder for this document." }) : /* @__PURE__ */ jsxs85(Fragment35, { children: [
48102
+ !item ? /* @__PURE__ */ jsx109("p", { className: "squisq-media-edit-modal__empty", children: "This clip is no longer in the document." }) : !mediaEditRenders ? /* @__PURE__ */ jsx109("p", { className: "squisq-media-edit-modal__empty", children: "Media editing needs a media folder for this document." }) : /* @__PURE__ */ jsxs85(Fragment36, { children: [
48002
48103
  /* @__PURE__ */ jsx109("div", { className: "squisq-media-edit-tabs", role: "tablist", "aria-label": "Edit sections", children: tabs.map((tab, index2) => {
48003
48104
  const selected = tab.id === activeTab;
48004
48105
  const edited = tabHasEdits(tab.id, draft);
@@ -48105,11 +48206,11 @@ function MediaEditModal({ target, onClose }) {
48105
48206
  className: "squisq-media-edit-status",
48106
48207
  role: "status",
48107
48208
  "data-state": copy.state.status === "failed" ? "failed" : renderStatus?.state,
48108
- children: copy.state.status === "saved" ? /* @__PURE__ */ jsxs85(Fragment35, { children: [
48209
+ children: copy.state.status === "saved" ? /* @__PURE__ */ jsxs85(Fragment36, { children: [
48109
48210
  "Saved ",
48110
48211
  copy.state.filename,
48111
48212
  "."
48112
- ] }) : copy.state.status === "failed" ? /* @__PURE__ */ jsxs85(Fragment35, { children: [
48213
+ ] }) : copy.state.status === "failed" ? /* @__PURE__ */ jsxs85(Fragment36, { children: [
48113
48214
  "The copy could not be made: ",
48114
48215
  copy.state.error
48115
48216
  ] }) : renderStatus && item && mediaEditRenders && /* @__PURE__ */ jsx109(
@@ -48399,7 +48500,7 @@ import {
48399
48500
  createMediaEditRenderManager,
48400
48501
  useProcessedAudio as useProcessedAudio4
48401
48502
  } from "@bendyline/squisq-video-react/media-edit";
48402
- import { Fragment as Fragment36, jsx as jsx110, jsxs as jsxs86 } from "react/jsx-runtime";
48503
+ import { Fragment as Fragment37, jsx as jsx110, jsxs as jsxs86 } from "react/jsx-runtime";
48403
48504
  function EditorShell({
48404
48505
  ariaLabel,
48405
48506
  initialMarkdown = "",
@@ -48433,11 +48534,13 @@ function EditorShell({
48433
48534
  toolbarSlotLeft,
48434
48535
  toolbarSlotAfterActions,
48435
48536
  toolbarSlotRight,
48537
+ toolbarPosition = "top",
48436
48538
  summarizationDesigner,
48437
48539
  statusBarSlotRight,
48438
48540
  sidePanelSlot,
48439
48541
  reviewProviders,
48440
48542
  showPlayTab = true,
48543
+ showViewTabs = true,
48441
48544
  allowPresentationWindow = true,
48442
48545
  allowPresentationFullscreen = true,
48443
48546
  allowPrint = true,
@@ -48583,10 +48686,12 @@ function EditorShell({
48583
48686
  toolbarSlotLeft,
48584
48687
  toolbarSlotAfterActions,
48585
48688
  toolbarSlotRight,
48689
+ toolbarPosition,
48586
48690
  summarizationDesigner,
48587
48691
  statusBarSlotRight,
48588
48692
  sidePanelSlot,
48589
48693
  showPlayTab,
48694
+ showViewTabs,
48590
48695
  hostMode,
48591
48696
  allowPresentationWindow,
48592
48697
  allowPresentationFullscreen,
@@ -48625,7 +48730,7 @@ function UseModeToolbarControls({
48625
48730
  }) {
48626
48731
  const printMode = usePrintMode();
48627
48732
  if (printMode.active) return /* @__PURE__ */ jsx110(PrintPreviewToolbar, {});
48628
- return /* @__PURE__ */ jsxs86(Fragment36, { children: [
48733
+ return /* @__PURE__ */ jsxs86(Fragment37, { children: [
48629
48734
  /* @__PURE__ */ jsx110(PreviewToolbarControls, { summarizationDesigner }),
48630
48735
  /* @__PURE__ */ jsx110(PresentationModeControl, {}),
48631
48736
  allowPrint && /* @__PURE__ */ jsx110(PrintModeControl, {})
@@ -48670,10 +48775,12 @@ function EditorShellInner({
48670
48775
  toolbarSlotLeft,
48671
48776
  toolbarSlotAfterActions,
48672
48777
  toolbarSlotRight,
48778
+ toolbarPosition,
48673
48779
  summarizationDesigner,
48674
48780
  statusBarSlotRight,
48675
48781
  sidePanelSlot,
48676
48782
  showPlayTab,
48783
+ showViewTabs,
48677
48784
  hostMode,
48678
48785
  allowPresentationWindow,
48679
48786
  allowPresentationFullscreen,
@@ -48997,6 +49104,35 @@ function EditorShellInner({
48997
49104
  clearLinkHoverTitle(anchor);
48998
49105
  }, []);
48999
49106
  const autoGrow = minHeight !== void 0 || maxHeight !== void 0;
49107
+ const header = isImageMode ? (toolbarSlotLeft || toolbarSlotRight) && /* @__PURE__ */ jsxs86("div", { className: "squisq-editor-header squisq-editor-header--image", children: [
49108
+ toolbarSlotLeft,
49109
+ /* @__PURE__ */ jsx110("div", { style: { flex: 1 } }),
49110
+ toolbarSlotRight
49111
+ ] }) : /* @__PURE__ */ jsx110("div", { className: "squisq-editor-header", children: /* @__PURE__ */ jsx110(
49112
+ Toolbar,
49113
+ {
49114
+ showFiles,
49115
+ fileCount: mediaCount,
49116
+ onToggleFiles: !isCodeMode && filesToggleEnabled ? handleToggleFiles : void 0,
49117
+ slotLeft: toolbarSlotLeft,
49118
+ slotAfterTabs: !isCodeMode && isPreview && /* @__PURE__ */ jsx110(
49119
+ UseModeToolbarControls,
49120
+ {
49121
+ allowPrint,
49122
+ summarizationDesigner
49123
+ }
49124
+ ),
49125
+ slotAfterActions: toolbarSlotAfterActions,
49126
+ slotRight: toolbarSlotRight,
49127
+ showPlayTab,
49128
+ showViewTabs,
49129
+ showFormattingControls,
49130
+ showInsertControls,
49131
+ hostMode,
49132
+ readOnly,
49133
+ findShortcut
49134
+ }
49135
+ ) });
49000
49136
  const shell = /* @__PURE__ */ jsxs86(
49001
49137
  "div",
49002
49138
  {
@@ -49009,6 +49145,7 @@ function EditorShellInner({
49009
49145
  className: `squisq-editor-shell ${className || ""}`,
49010
49146
  "data-theme": colorScheme,
49011
49147
  "data-host-mode": hostMode,
49148
+ "data-toolbar-position": toolbarPosition === "bottom" ? "bottom" : void 0,
49012
49149
  "data-link-handler": onLinkClick ? "true" : void 0,
49013
49150
  "data-full-width": fullWidth ? "true" : void 0,
49014
49151
  "data-thin-margins": thinMargins ? "true" : void 0,
@@ -49052,34 +49189,7 @@ function EditorShellInner({
49052
49189
  allowPresentationWindow,
49053
49190
  allowPresentationFullscreen,
49054
49191
  children: [
49055
- isImageMode ? (toolbarSlotLeft || toolbarSlotRight) && /* @__PURE__ */ jsxs86("div", { className: "squisq-editor-header squisq-editor-header--image", children: [
49056
- toolbarSlotLeft,
49057
- /* @__PURE__ */ jsx110("div", { style: { flex: 1 } }),
49058
- toolbarSlotRight
49059
- ] }) : /* @__PURE__ */ jsx110("div", { className: "squisq-editor-header", children: /* @__PURE__ */ jsx110(
49060
- Toolbar,
49061
- {
49062
- showFiles,
49063
- fileCount: mediaCount,
49064
- onToggleFiles: !isCodeMode && filesToggleEnabled ? handleToggleFiles : void 0,
49065
- slotLeft: toolbarSlotLeft,
49066
- slotAfterTabs: !isCodeMode && isPreview && /* @__PURE__ */ jsx110(
49067
- UseModeToolbarControls,
49068
- {
49069
- allowPrint,
49070
- summarizationDesigner
49071
- }
49072
- ),
49073
- slotAfterActions: toolbarSlotAfterActions,
49074
- slotRight: toolbarSlotRight,
49075
- showPlayTab,
49076
- showFormattingControls,
49077
- showInsertControls,
49078
- hostMode,
49079
- readOnly,
49080
- findShortcut
49081
- }
49082
- ) }),
49192
+ toolbarPosition === "top" && header,
49083
49193
  /* @__PURE__ */ jsxs86(
49084
49194
  "div",
49085
49195
  {
@@ -49315,6 +49425,7 @@ function EditorShellInner({
49315
49425
  basePath
49316
49426
  }
49317
49427
  ),
49428
+ toolbarPosition === "bottom" && header,
49318
49429
  statusBarVisible && !isImageMode && /* @__PURE__ */ jsx110(StatusBar, { slotRight: statusBarSlotRight }),
49319
49430
  isMarkdownMode && allowRecording && mediaProvider && /* @__PURE__ */ jsx110(
49320
49431
  RecorderEntry,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CodeContext, P as PageTemplateSettings, E as EditorHostMode, S as SceneTextChannel, a as CalcEngineFactory, b as EditorView$1, c as CsvSourceMeta, X as XlsxSourceMeta, F as FormulaEditRecord } from './shell-CKXPqADV.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, Q as MediaEditSaveOutput, R as MentionCandidate, T as MentionProvider, U as NavigationSheetPanel, V as OutlineBlock, W as OutlineInsertion, Y as PageTemplateChoice, Z as PreviewPanel, _ as PreviewPanelProps, $ as RawEditor, a0 as RawEditorProps, a1 as ThemeInheritance, a2 as ViewPreferences, a3 as WriteCanvasSettings, a4 as WysiwygEditor, a5 as WysiwygEditorProps, a6 as XLSX_LOCKED_REASON, a7 as XlsxFormulaSession, a8 as applySourceEditsToText, a9 as blockInsertionPoint, aa as createXlsxFormulaSession, ab as getBlockSlices, ac as headingDepthForInsertion, ad as ingestSidecarBytes, ae as joinBlockAt, af as lineToOffset, ag as minimalReplaceEdit, ah as normalizeSourceEdits, ai as offsetToLine, aj as resolveOutlineInsertion, ak as sliceIndexAtOffset, al as sourceOutline, am as spliceBlock, an as useEditorContext, ao as useEditorContextMenuItems, ap as useEditorInsertMenuItems } from './shell-CKXPqADV.js';
1
+ import { C as CodeContext, P as PageTemplateSettings, E as EditorHostMode, S as SceneTextChannel, a as CalcEngineFactory, b as EditorView$1, c as CsvSourceMeta, X as XlsxSourceMeta, F as FormulaEditRecord } from './shell-DOxTnb9f.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 EditorToolbarPosition, J as FindOptions, K as FindRequest, L as FormulaSessionOptions, M as ImageDisplayMode, N as IngestedSidecar, O as InsertBlockOptions, Q as LayoutMode, R as MediaEditSaveOutput, T as MentionCandidate, U as MentionProvider, V as NavigationSheetPanel, W as OutlineBlock, Y as OutlineInsertion, Z as PageTemplateChoice, _ as PreviewPanel, $ as PreviewPanelProps, a0 as RawEditor, a1 as RawEditorProps, a2 as ThemeInheritance, a3 as ViewPreferences, a4 as WriteCanvasSettings, a5 as WysiwygEditor, a6 as WysiwygEditorProps, a7 as XLSX_LOCKED_REASON, a8 as XlsxFormulaSession, a9 as applySourceEditsToText, aa as blockInsertionPoint, ab as createXlsxFormulaSession, ac as getBlockSlices, ad as headingDepthForInsertion, ae as ingestSidecarBytes, af as joinBlockAt, ag as lineToOffset, ah as minimalReplaceEdit, ai as normalizeSourceEdits, aj as offsetToLine, ak as resolveOutlineInsertion, al as sliceIndexAtOffset, am as sourceOutline, an as spliceBlock, ao as useEditorContext, ap as useEditorContextMenuItems, aq as useEditorInsertMenuItems } from './shell-DOxTnb9f.js';
3
3
  import * as react from 'react';
4
4
  import { ReactNode, CSSProperties, RefObject, 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';
@@ -1072,6 +1072,11 @@ interface ToolbarProps {
1072
1072
  * editing free-form prompts — can pass false to suppress it.
1073
1073
  */
1074
1074
  showPlayTab?: boolean;
1075
+ /**
1076
+ * Whether to render the view tabs and their mode menus at all. Defaults to
1077
+ * true. See `EditorShellProps.showViewTabs`.
1078
+ */
1079
+ showViewTabs?: boolean;
1075
1080
  /**
1076
1081
  * Whether to render Squisq's built-in text, block, and contextual
1077
1082
  * formatting controls. The toolbar, Insert menu, view tabs, and host slots
@@ -1099,7 +1104,7 @@ interface ToolbarProps {
1099
1104
  * - WYSIWYG: calls Tiptap chain commands (toggleBold, etc.)
1100
1105
  * - Raw: appends markdown syntax to the source
1101
1106
  */
1102
- declare function Toolbar({ className, showFiles, fileCount, onToggleFiles, slotLeft, slotAfterTabs, slotAfterActions, slotRight, showPlayTab, showFormattingControls, showInsertControls, hostMode, readOnly, findShortcut, }: ToolbarProps): react.JSX.Element;
1107
+ declare function Toolbar({ className, showFiles, fileCount, onToggleFiles, slotLeft, slotAfterTabs, slotAfterActions, slotRight, showPlayTab, showViewTabs, showFormattingControls, showInsertControls, hostMode, readOnly, findShortcut, }: ToolbarProps): react.JSX.Element;
1103
1108
 
1104
1109
  /**
1105
1110
  * VersionHistoryPanel
package/dist/index.js CHANGED
@@ -248,7 +248,7 @@ import {
248
248
  videoEmbedParagraphJson,
249
249
  viewStateFromBinding,
250
250
  writeHeadingViewState
251
- } from "./chunk-CBFPGSYR.js";
251
+ } from "./chunk-5NA2IDXP.js";
252
252
  import {
253
253
  EditorProvider,
254
254
  applySourceEditsToText,
@@ -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, R as MentionCandidate, T as MentionProvider, Z as PreviewPanel, _ as PreviewPanelProps, $ as RawEditor, a0 as RawEditorProps, a1 as ThemeInheritance, a2 as ViewPreferences, a4 as WysiwygEditor, a5 as WysiwygEditorProps, an as useEditorContext, ao as useEditorContextMenuItems, ap as useEditorInsertMenuItems } from '../shell-CKXPqADV.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, M as ImageDisplayMode, Q as LayoutMode, T as MentionCandidate, U as MentionProvider, _ as PreviewPanel, $ as PreviewPanelProps, a0 as RawEditor, a1 as RawEditorProps, a2 as ThemeInheritance, a3 as ViewPreferences, a5 as WysiwygEditor, a6 as WysiwygEditorProps, ao as useEditorContext, ap as useEditorContextMenuItems, aq as useEditorInsertMenuItems } from '../shell-DOxTnb9f.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-CBFPGSYR.js";
8
+ } from "../chunk-5NA2IDXP.js";
9
9
  import {
10
10
  EditorProvider,
11
11
  useEditorContext,
@@ -1245,6 +1245,11 @@ interface WriteCanvasSettings {
1245
1245
  * authoring controls that do not belong in a message composer.
1246
1246
  */
1247
1247
  type EditorHostMode = 'document' | 'chat';
1248
+ /**
1249
+ * Where the editor shell places its toolbar: above the editing surface (the
1250
+ * document default) or below it (a chat composer's attach and send row).
1251
+ */
1252
+ type EditorToolbarPosition = 'top' | 'bottom';
1248
1253
 
1249
1254
  interface EditorShellProps {
1250
1255
  /** Accessible name for the editing surface, separate from its empty placeholder. */
@@ -1398,6 +1403,14 @@ interface EditorShellProps {
1398
1403
  toolbarSlotAfterActions?: ReactNode;
1399
1404
  /** Content rendered at the rightmost end of the toolbar, after all other elements. */
1400
1405
  toolbarSlotRight?: ReactNode;
1406
+ /**
1407
+ * Where the toolbar sits relative to the editing surface (default: `'top'`).
1408
+ * `'bottom'` renders it after the content, above the status bar, the way a
1409
+ * chat composer carries its attach and send keys under the draft. The
1410
+ * toolbar follows the content in DOM order too, so keyboard focus moves
1411
+ * from the draft to the keys in the order they are seen.
1412
+ */
1413
+ toolbarPosition?: EditorToolbarPosition;
1401
1414
  /** Optional designer opened beside Summarize in the preview toolbar. */
1402
1415
  summarizationDesigner?: (onClose: () => void) => ReactNode;
1403
1416
  /** Host-supplied content rendered at the right edge of the bottom status bar. */
@@ -1432,6 +1445,15 @@ interface EditorShellProps {
1432
1445
  * sense (e.g. editing free-form prompt documents). Defaults to true.
1433
1446
  */
1434
1447
  showPlayTab?: boolean;
1448
+ /**
1449
+ * Whether to show the view tabs (Write, Source, Use) and their mode menus.
1450
+ * Defaults to true. When false the editor stays in `initialView` — the
1451
+ * Ctrl/Cmd+Shift+1/2/3 view shortcuts act through the tabs, so they do
1452
+ * nothing either — while the formatting and Insert controls remain. Use it
1453
+ * for a small field inside a form, where switching views is not a choice
1454
+ * the person should face. `hostMode="chat"` already hides the tabs.
1455
+ */
1456
+ showViewTabs?: boolean;
1435
1457
  /**
1436
1458
  * Whether Use mode may open its audience view in a separate browser window.
1437
1459
  * Defaults to true. Disable this in embedded hosts that block popups.
@@ -1846,7 +1868,7 @@ interface EditorShellProps {
1846
1868
  * Complete markdown editor shell with toolbar, view switcher, and three
1847
1869
  * editing modes: Raw (Monaco), WYSIWYG (Tiptap), and Preview.
1848
1870
  */
1849
- declare function EditorShell({ ariaLabel, initialMarkdown, initialView, hostMode, defaultViewportPreset, articleId, basePath, onChange, onLinkClick, showCodeCopyButton, onCopyCode, colorScheme, className, height, minHeight, maxHeight, mediaProvider, mediaEditRenders, workspaceContainer, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, showFilesToggle, showFilesWhenNotEmpty, showFormattingControls, showInsertControls, allowBinaryDownloads, toolbarSlotLeft, toolbarSlotAfterActions, toolbarSlotRight, summarizationDesigner, statusBarSlotRight, sidePanelSlot, reviewProviders, showPlayTab, allowPresentationWindow, allowPresentationFullscreen, allowPrint, submitOnEnter, calcEngineFactory, codeContext, fullWidth, uxFont, thinMargins, writeCanvasSettings, showStatusBar, imageDisplayMode, fileName, saveCoverImageOutput, saveDashboardImageOutput, saveMediaEditOutput, language, findMode, onFindModeChange, findRequest, findShortcut, mentionProvider, proofing, proofingDefaultEnabled, proofingSpellingEnabled, proofingGrammarEnabled, proofingIgnoreStore, speechInput, documentLinkProvider, wikiLinks, fenceRenderers, linkSchemes, allowRecording, allowNarrate, preserveSourceWrapping, placeholder, readOnly, imageSrc, imageAlt, imageMode, imageEditorContainer, onImageExport, inlinePreview, inlinePreviewWidth, outline, outlineWidth, navigationSheet, onNavigationSheetChange, blockTags, blockTagVisibility, themeInheritance, viewPreferences, onViewPreferencesChange, themeOverride, defaultThemeId, defaultThemeLabel, pageTemplates, }: EditorShellProps): react.JSX.Element;
1871
+ declare function EditorShell({ ariaLabel, initialMarkdown, initialView, hostMode, defaultViewportPreset, articleId, basePath, onChange, onLinkClick, showCodeCopyButton, onCopyCode, colorScheme, className, height, minHeight, maxHeight, mediaProvider, mediaEditRenders, workspaceContainer, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, showFilesToggle, showFilesWhenNotEmpty, showFormattingControls, showInsertControls, allowBinaryDownloads, toolbarSlotLeft, toolbarSlotAfterActions, toolbarSlotRight, toolbarPosition, summarizationDesigner, statusBarSlotRight, sidePanelSlot, reviewProviders, showPlayTab, showViewTabs, allowPresentationWindow, allowPresentationFullscreen, allowPrint, submitOnEnter, calcEngineFactory, codeContext, fullWidth, uxFont, thinMargins, writeCanvasSettings, showStatusBar, imageDisplayMode, fileName, saveCoverImageOutput, saveDashboardImageOutput, saveMediaEditOutput, language, findMode, onFindModeChange, findRequest, findShortcut, mentionProvider, proofing, proofingDefaultEnabled, proofingSpellingEnabled, proofingGrammarEnabled, proofingIgnoreStore, speechInput, documentLinkProvider, wikiLinks, fenceRenderers, linkSchemes, allowRecording, allowNarrate, preserveSourceWrapping, placeholder, readOnly, imageSrc, imageAlt, imageMode, imageEditorContainer, onImageExport, inlinePreview, inlinePreviewWidth, outline, outlineWidth, navigationSheet, onNavigationSheetChange, blockTags, blockTagVisibility, themeInheritance, viewPreferences, onViewPreferencesChange, themeOverride, defaultThemeId, defaultThemeLabel, pageTemplates, }: EditorShellProps): react.JSX.Element;
1850
1872
 
1851
1873
  /**
1852
1874
  * MediaClipboard — copy, cut and paste of one image, video or audio clip in
@@ -2044,4 +2066,4 @@ interface EditorInsertMenuItem {
2044
2066
  /** Call from a toolbar slot; callbacks retain access to the editor context. */
2045
2067
  declare function useEditorInsertMenuItems(items: readonly EditorInsertMenuItem[]): void;
2046
2068
 
2047
- export { RawEditor as $, type ApplySourceEditsOptions as A, type BlockInsertionBuilder as B, type CodeContext as C, type DashboardImageSaveOutput as D, type EditorHostMode as E, type FormulaEditRecord as F, type EditorShellProps as G, type EditorState as H, type FindOptions as I, type FindRequest as J, type FormulaSessionOptions as K, type ImageDisplayMode as L, type IngestedSidecar as M, type InsertBlockOptions as N, type LayoutMode as O, type PageTemplateSettings as P, type MediaEditSaveOutput as Q, type MentionCandidate as R, type SceneTextChannel as S, type MentionProvider as T, type NavigationSheetPanel as U, type OutlineBlock as V, type OutlineInsertion as W, type XlsxSourceMeta as X, type PageTemplateChoice as Y, PreviewPanel as Z, type PreviewPanelProps as _, type CalcEngineFactory as a, type RawEditorProps as a0, type ThemeInheritance as a1, type ViewPreferences as a2, type WriteCanvasSettings as a3, WysiwygEditor as a4, type WysiwygEditorProps as a5, XLSX_LOCKED_REASON as a6, type XlsxFormulaSession as a7, applySourceEditsToText as a8, blockInsertionPoint as a9, createXlsxFormulaSession as aa, getBlockSlices as ab, headingDepthForInsertion as ac, ingestSidecarBytes as ad, joinBlockAt as ae, lineToOffset as af, minimalReplaceEdit as ag, normalizeSourceEdits as ah, offsetToLine as ai, resolveOutlineInsertion as aj, sliceIndexAtOffset as ak, sourceOutline as al, spliceBlock as am, useEditorContext as an, useEditorContextMenuItems as ao, useEditorInsertMenuItems as ap, type EditorView as b, type CsvSourceMeta as c, type BlockInsertionContext as d, type BlockPlacement as e, type BlockRange as f, type BlockSlice as g, type BlockTagVisibility as h, type CodeContextSection as i, type CoverImageSaveOutput as j, type DocumentLinkCandidate as k, type DocumentLinkProvider as l, type EditorActions as m, type EditorColorScheme as n, type EditorContextMenuContext as o, type EditorContextMenuItem as p, type EditorContextMenuItemVisibility as q, EditorContextMenuProvider as r, type EditorContextMenuProviderProps as s, type EditorContextValue as t, type EditorInsertMenuItem as u, type EditorMode as v, EditorProvider as w, type EditorProviderProps as x, type EditorSelectionInfo as y, EditorShell as z };
2069
+ export { type PreviewPanelProps as $, type ApplySourceEditsOptions as A, type BlockInsertionBuilder as B, type CodeContext as C, type DashboardImageSaveOutput as D, type EditorHostMode as E, type FormulaEditRecord as F, type EditorShellProps as G, type EditorState as H, type EditorToolbarPosition as I, type FindOptions as J, type FindRequest as K, type FormulaSessionOptions as L, type ImageDisplayMode as M, type IngestedSidecar as N, type InsertBlockOptions as O, type PageTemplateSettings as P, type LayoutMode as Q, type MediaEditSaveOutput as R, type SceneTextChannel as S, type MentionCandidate as T, type MentionProvider as U, type NavigationSheetPanel as V, type OutlineBlock as W, type XlsxSourceMeta as X, type OutlineInsertion as Y, type PageTemplateChoice as Z, PreviewPanel as _, type CalcEngineFactory as a, RawEditor as a0, type RawEditorProps as a1, type ThemeInheritance as a2, type ViewPreferences as a3, type WriteCanvasSettings as a4, WysiwygEditor as a5, type WysiwygEditorProps as a6, XLSX_LOCKED_REASON as a7, type XlsxFormulaSession as a8, applySourceEditsToText as a9, blockInsertionPoint as aa, createXlsxFormulaSession as ab, getBlockSlices as ac, headingDepthForInsertion as ad, ingestSidecarBytes as ae, joinBlockAt as af, lineToOffset as ag, minimalReplaceEdit as ah, normalizeSourceEdits as ai, offsetToLine as aj, resolveOutlineInsertion as ak, sliceIndexAtOffset as al, sourceOutline as am, spliceBlock as an, useEditorContext as ao, useEditorContextMenuItems as ap, useEditorInsertMenuItems as aq, type EditorView as b, type CsvSourceMeta as c, type BlockInsertionContext as d, type BlockPlacement as e, type BlockRange as f, type BlockSlice as g, type BlockTagVisibility as h, type CodeContextSection as i, type CoverImageSaveOutput as j, type DocumentLinkCandidate as k, type DocumentLinkProvider as l, type EditorActions as m, type EditorColorScheme as n, type EditorContextMenuContext as o, type EditorContextMenuItem as p, type EditorContextMenuItemVisibility as q, EditorContextMenuProvider as r, type EditorContextMenuProviderProps as s, type EditorContextValue as t, type EditorInsertMenuItem as u, type EditorMode as v, EditorProvider as w, type EditorProviderProps as x, type EditorSelectionInfo as y, EditorShell as z };
@@ -9632,6 +9632,10 @@
9632
9632
  background: var(--squisq-surface-subtle);
9633
9633
  flex-shrink: 0;
9634
9634
  }
9635
+ .squisq-editor-shell[data-toolbar-position=bottom] > .squisq-editor-header {
9636
+ border-bottom: 0;
9637
+ border-top: 1px solid var(--squisq-border-subtle);
9638
+ }
9635
9639
  .squisq-editor-header--image {
9636
9640
  display: flex;
9637
9641
  align-items: center;
@@ -15438,6 +15442,35 @@ button.squisq-view-menu-radio-row:focus-visible {
15438
15442
  font-weight: 600;
15439
15443
  }
15440
15444
 
15445
+ /* src/styles/footnotes.css */
15446
+ .squisq-footnote-ref {
15447
+ font-size: 0.72em;
15448
+ vertical-align: super;
15449
+ line-height: 0;
15450
+ padding: 0 0.2em;
15451
+ border-radius: 3px;
15452
+ color: var(--squisq-accent);
15453
+ background: var(--squisq-accent-subtle);
15454
+ white-space: nowrap;
15455
+ }
15456
+ .squisq-footnote-ref--missing {
15457
+ color: var(--squisq-text-muted);
15458
+ background: transparent;
15459
+ }
15460
+ .squisq-footnote-definition {
15461
+ font-size: 0.875em;
15462
+ color: var(--squisq-text-muted);
15463
+ }
15464
+ .squisq-footnote-definition:not(.squisq-footnote-definition + .squisq-footnote-definition) {
15465
+ margin-top: 1.25em;
15466
+ padding-top: 0.5em;
15467
+ border-top: 1px solid var(--squisq-border-subtle);
15468
+ }
15469
+ .squisq-footnote-label {
15470
+ color: var(--squisq-accent);
15471
+ font-weight: 600;
15472
+ }
15473
+
15441
15474
  /* src/styles/document-tray.css */
15442
15475
  .squisq-wysiwyg-editor .squisq-document-tray-source {
15443
15476
  display: none !important;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq-editor-react",
3
- "version": "2.13.23",
3
+ "version": "2.13.24",
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.13.16",
105
+ "@bendyline/squisq": "2.13.17",
106
106
  "@bendyline/squisq-calc": "2.11.2",
107
- "@bendyline/squisq-formats": "2.8.18",
108
- "@bendyline/squisq-grid-react": "2.11.45",
109
- "@bendyline/squisq-react": "2.12.28",
110
- "@bendyline/squisq-video-react": "2.5.29",
107
+ "@bendyline/squisq-formats": "2.8.19",
108
+ "@bendyline/squisq-grid-react": "2.11.46",
109
+ "@bendyline/squisq-react": "2.12.29",
110
+ "@bendyline/squisq-video-react": "2.5.30",
111
111
  "@fortawesome/fontawesome-free": "7.3.1",
112
112
  "@tiptap/core": "2.27.3",
113
113
  "@tiptap/extension-heading": "2.27.3",