superdoc 2.16.1-next.9 → 2.17.0

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.
@@ -19,7 +19,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
19
19
  var PRIVATE_ENGINE_INFO = (0, _superdoc_docx_engine_collaboration_upgrade_engine.getCollaborationUpgradeEngineInfo)();
20
20
  var ENGINE_INFO = Object.freeze({
21
21
  ...PRIVATE_ENGINE_INFO,
22
- superdocVersion: "2.16.1-next.9",
22
+ superdocVersion: "2.17.0",
23
23
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
24
24
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
25
25
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -18,7 +18,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
18
18
  var PRIVATE_ENGINE_INFO = getCollaborationUpgradeEngineInfo$1();
19
19
  var ENGINE_INFO = Object.freeze({
20
20
  ...PRIVATE_ENGINE_INFO,
21
- superdocVersion: "2.16.1-next.9",
21
+ superdocVersion: "2.17.0",
22
22
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
23
23
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
24
24
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -34,6 +34,16 @@ export interface ClipboardParseOptions {
34
34
  maxDepth?: number;
35
35
  }
36
36
  export interface SDPasteRunMarks {
37
+ /** Complex-script bold state. */
38
+ boldCs?: boolean;
39
+ /** Complex-script italic state. */
40
+ italicCs?: boolean;
41
+ /** All-caps text transform. */
42
+ caps?: boolean;
43
+ /** Small-caps text transform. */
44
+ smallCaps?: boolean;
45
+ /** Complex-script font size in points. */
46
+ fontSizeCsPt?: number;
37
47
  bold?: boolean;
38
48
  italic?: boolean;
39
49
  underline?: boolean;
@@ -112,6 +122,14 @@ export type SDPasteInline = SDPasteLeafInline | {
112
122
  inlines: readonly SDPasteLeafInline[];
113
123
  tooltip?: string;
114
124
  sourcePath?: readonly (string | number)[];
125
+ } | {
126
+ kind: 'footnoteRef';
127
+ noteId: string;
128
+ sourcePath?: readonly (string | number)[];
129
+ } | {
130
+ kind: 'endnoteRef';
131
+ noteId: string;
132
+ sourcePath?: readonly (string | number)[];
115
133
  };
116
134
  export interface SDPasteParagraphBlock {
117
135
  kind: 'paragraph';
@@ -0,0 +1,11 @@
1
+ export declare class Utf16Sha256 {
2
+ private readonly state;
3
+ private readonly block;
4
+ private readonly words;
5
+ private readonly view;
6
+ private blockLength;
7
+ private totalBytes;
8
+ private finalized;
9
+ write(value: string): void;
10
+ digestHex(): string;
11
+ }
@@ -42,6 +42,8 @@ export type AnchoredTableCollection = {
42
42
  */
43
43
  export declare function collectPreRegisteredAnchorsSteps(blocks: FlowBlock[], measures: Measure[], checkpointEveryBlocks?: number | null): Generator<LayoutWorkCheckpoint, AnchoredDrawing[], void>;
44
44
  export declare function collectPreRegisteredAnchors(blocks: FlowBlock[], measures: Measure[]): AnchoredDrawing[];
45
+ /** Collect page- or margin-relative floating tables before paragraph layout. */
46
+ export declare function collectPreRegisteredTablesSteps(blocks: FlowBlock[], measures: Measure[], checkpointEveryBlocks?: number | null): Generator<LayoutWorkCheckpoint, AnchoredTable[], void>;
45
47
  /**
46
48
  * Collect anchored drawings (images/drawings) mapped to their anchor paragraph index.
47
49
  * Map of paragraph block index -> anchored images/drawings associated with that paragraph.
@@ -11,11 +11,16 @@ export type FloatingTableAnchorResolution = {
11
11
  };
12
12
  /** Width ratio for inline (paginated) layout vs single float fragment. */
13
13
  export declare const ANCHORED_TABLE_FULL_WIDTH_RATIO = 0.99;
14
+ /**
15
+ * Word pins page-relative floating tables to the physical page instead of
16
+ * allowing a negative tblpY to clip the table above the page canvas.
17
+ */
18
+ export declare function clampPageRelativeFloatingTableY(block: TableBlock, y: number): number;
14
19
  /**
15
20
  * True when an anchored table should paginate inline instead of as one float fragment.
16
21
  * Uses tbl width, flow-affecting wrap distances from w:tblpPr, and table indent — not a fixed px fudge factor.
17
22
  */
18
- export declare function isAnchoredTableFullWidth(block: TableBlock, measure: TableMeasure, columnWidth: number): boolean;
23
+ export declare function isAnchoredTableFullWidth(block: TableBlock, measure: TableMeasure, columnWidth: number, pageHeight?: number): boolean;
19
24
  /**
20
25
  * Resolve anchor paragraph + vertical offset for a block-level floating table.
21
26
  */
@@ -39,6 +39,8 @@ export type LayoutOptions = {
39
39
  remeasureParagraph?: (block: ParagraphBlock, maxWidth: number, firstLineIndent?: number, lineRegions?: readonly (readonly ParagraphLineRegion[])[]) => ParagraphMeasure;
40
40
  /** @internal Positioned paragraph frames that render without advancing the story cursor. */
41
41
  nonFlowPositionedParagraphFrameIds?: ReadonlySet<string>;
42
+ /** @internal Physical page height used for page-relative tables laid out on a synthetic region canvas. */
43
+ pagePositionedTableFitHeight?: number;
42
44
  sectionMetadata?: SectionMetadata[];
43
45
  /**
44
46
  * Extra bottom margin per page index (0-based) reserved for non-body content
@@ -102,6 +102,7 @@ export type ParagraphAnchorsContext = {
102
102
  columnWidth: number;
103
103
  pageWidth: number;
104
104
  pageMargins: PageMargins;
105
+ pagePositionedTableFitHeight?: number;
105
106
  columns: ColumnLayoutForAnchor;
106
107
  placedAnchoredIds: Set<string>;
107
108
  };
@@ -5,6 +5,7 @@ export type TableLayoutContext = {
5
5
  block: TableBlock;
6
6
  measure: TableMeasure;
7
7
  columnWidth: number;
8
+ pagePositionedTableFitHeight?: number;
8
9
  ensurePage: () => PageState;
9
10
  advanceColumn: (state: PageState) => PageState;
10
11
  columnX: (state: PageState, columnIndex?: number) => number;
@@ -90,7 +91,7 @@ export declare function generateFragmentMetadata(measure: TableMeasure, block: T
90
91
  * @param context - Table layout context
91
92
 
92
93
  */
93
- export declare function layoutTableBlockSteps({ block, measure, columnWidth, ensurePage, advanceColumn, columnX, resumeCursor, onFragmentStart, }: TableLayoutContext): Generator<TableLayoutStep, void, void>;
94
+ export declare function layoutTableBlockSteps({ block, measure, columnWidth, pagePositionedTableFitHeight, ensurePage, advanceColumn, columnX, resumeCursor, onFragmentStart, }: TableLayoutContext): Generator<TableLayoutStep, void, void>;
94
95
  export declare function layoutTableBlock(context: TableLayoutContext): void;
95
96
  /**
96
97
  * Create a table fragment for an anchored/floating table at its computed position.
@@ -0,0 +1 @@
1
+ export declare function warnForMissingDocumentFonts(missingFonts: readonly string[] | undefined, warnedFonts: Set<string>, hostname?: string): void;
@@ -4311,7 +4311,7 @@ export interface Config {
4311
4311
  proofing?: ProofingConfig;
4312
4312
  /**
4313
4313
  * Font system configuration. The reviewed fallback pack ships in the optional
4314
- * `@superdoc-dev/fonts` package: pass `superdocFonts` (bundler) or the `SuperDocFonts`
4314
+ * `@superdoc/fonts` package: pass `superdocFonts` (bundler) or the `SuperDocFonts`
4315
4315
  * global from its `superdoc-fonts.min.js` browser build (CDN). To self-host, set
4316
4316
  * `fonts.assetBaseUrl` (e.g. `/fonts/` or a CDN URL) or `fonts.resolveAssetUrl` for
4317
4317
  * signed/versioned hosting. Core ships no document families, so with none configured the
package/dist/superdoc.cjs CHANGED
@@ -316,7 +316,7 @@ var shuffleArray = (array) => {
316
316
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
317
317
  function getSuperdocVersion() {
318
318
  try {
319
- return "2.16.1-next.9";
319
+ return "2.17.0";
320
320
  } catch {
321
321
  return "unknown";
322
322
  }
@@ -38514,6 +38514,21 @@ function normalizeSurfacesConfig(config = {}) {
38514
38514
  };
38515
38515
  }
38516
38516
  //#endregion
38517
+ //#region src/core/helpers/font-diagnostics.ts
38518
+ var FONT_GUIDE_URL = "https://docs.superdoc.dev/editor/fonts/";
38519
+ function isLocalDevelopmentHost(hostname) {
38520
+ return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "0.0.0.0" || hostname === "::1" || hostname === "[::1]" || hostname.startsWith("127.");
38521
+ }
38522
+ function warnForMissingDocumentFonts(missingFonts, warnedFonts, hostname = typeof window === "undefined" ? "" : window.location.hostname) {
38523
+ if (!isLocalDevelopmentHost(hostname) || !Array.isArray(missingFonts)) return;
38524
+ const newlyMissing = [...new Set(missingFonts.map((font) => font.trim()).filter(Boolean))].filter((font) => !warnedFonts.has(font));
38525
+ if (newlyMissing.length === 0) return;
38526
+ for (const font of newlyMissing) warnedFonts.add(font);
38527
+ const noun = newlyMissing.length === 1 ? "font" : "fonts";
38528
+ const names = newlyMissing.map((font) => `"${font}"`).join(", ");
38529
+ console.warn(`[SuperDoc] Missing document ${noun}: ${names}. The browser is using fallback fonts, which can change line and page breaks. Configure document fonts: ${FONT_GUIDE_URL}`);
38530
+ }
38531
+ //#endregion
38517
38532
  //#region src/core/editor-runtime/editor-runtime-registry.ts
38518
38533
  /**
38519
38534
  * Internal SuperDoc registry of mounted editor runtimes and the active-runtime
@@ -45615,6 +45630,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45615
45630
  useLayoutEngine: true
45616
45631
  };
45617
45632
  this.#fontsRelayEditors = /* @__PURE__ */ new WeakSet();
45633
+ this.#warnedMissingFonts = /* @__PURE__ */ new WeakMap();
45618
45634
  this.#lastFontsChangedPayload = null;
45619
45635
  this.#fontsApi = null;
45620
45636
  this.#v2FontsUnsub = null;
@@ -45710,7 +45726,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
45710
45726
  this.config.colors = shuffleArray(this.config.colors);
45711
45727
  this.userColorMap = /* @__PURE__ */ new Map();
45712
45728
  this.colorIndex = 0;
45713
- this.version = "2.16.1-next.9";
45729
+ this.version = "2.17.0";
45714
45730
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
45715
45731
  this.superdocId = config.superdocId || require_uuid.v4();
45716
45732
  this.colors = this.config.colors ?? [];
@@ -46704,6 +46720,7 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46704
46720
  }
46705
46721
  /** Editors whose `fonts-changed` we already relay, so a repeated create wires once. */
46706
46722
  #fontsRelayEditors;
46723
+ #warnedMissingFonts;
46707
46724
  /**
46708
46725
  * Relay an editor's authoritative `fonts-changed` up to the SuperDoc surface, so
46709
46726
  * `superdoc.on('fonts-changed')` / `onFontsChanged` fire without the legacy
@@ -46719,10 +46736,10 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46719
46736
  if (this.#fontsRelayEditors.has(editor)) return;
46720
46737
  this.#fontsRelayEditors.add(editor);
46721
46738
  editor.on("fonts-changed", (payload) => {
46722
- if (this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(payload);
46739
+ if (this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(editor, payload);
46723
46740
  });
46724
46741
  const cached = (editor.documentRenderer ?? editor["presentationEditor"])?.getLastFontsChangedPayload?.();
46725
- if (cached && this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(cached);
46742
+ if (cached && this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(editor, cached);
46726
46743
  }
46727
46744
  /**
46728
46745
  * Whether a wired editor's font report may surface on the SuperDoc instance. Only the
@@ -46738,8 +46755,16 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46738
46755
  /** Last font report delivered on this instance, so `fonts.onReport` can replay it. */
46739
46756
  #lastFontsChangedPayload;
46740
46757
  /** Cache then emit a font report, so a later `onReport` subscriber gets the current one. */
46741
- #deliverFontsChanged(payload) {
46758
+ #deliverFontsChanged(editor, payload) {
46742
46759
  this.#lastFontsChangedPayload = payload;
46760
+ if (editor.editorVersion === 2) {
46761
+ let warnedFonts = this.#warnedMissingFonts.get(editor);
46762
+ if (!warnedFonts) {
46763
+ warnedFonts = /* @__PURE__ */ new Set();
46764
+ this.#warnedMissingFonts.set(editor, warnedFonts);
46765
+ }
46766
+ warnForMissingDocumentFonts(payload.missingFonts, warnedFonts);
46767
+ }
46743
46768
  this.emit("fonts-changed", payload);
46744
46769
  }
46745
46770
  /**
@@ -46837,10 +46862,10 @@ var SuperDoc = class extends require_eventemitter3.import_eventemitter3.default
46837
46862
  #wireV2FontsRelay(facade) {
46838
46863
  this.#teardownV2FontsRelay();
46839
46864
  const runtime = getActiveFontRuntime(facade);
46840
- if (!runtime?.onChanged) return;
46865
+ if (!facade || !runtime?.onChanged) return;
46841
46866
  const current = runtime.getLastFontsChangedPayload?.();
46842
- if (current) this.#deliverFontsChanged(current);
46843
- this.#v2FontsUnsub = runtime.onChanged((payload) => this.#deliverFontsChanged(payload));
46867
+ if (current) this.#deliverFontsChanged(facade, current);
46868
+ this.#v2FontsUnsub = runtime.onChanged((payload) => this.#deliverFontsChanged(facade, payload));
46844
46869
  }
46845
46870
  /**
46846
46871
  * Reconcile the compatibility `activeEditor` projection with a registry
@@ -315,7 +315,7 @@ var shuffleArray = (array) => {
315
315
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
316
316
  function getSuperdocVersion() {
317
317
  try {
318
- return "2.16.1-next.9";
318
+ return "2.17.0";
319
319
  } catch {
320
320
  return "unknown";
321
321
  }
@@ -38474,6 +38474,21 @@ function normalizeSurfacesConfig(config = {}) {
38474
38474
  };
38475
38475
  }
38476
38476
  //#endregion
38477
+ //#region src/core/helpers/font-diagnostics.ts
38478
+ var FONT_GUIDE_URL = "https://docs.superdoc.dev/editor/fonts/";
38479
+ function isLocalDevelopmentHost(hostname) {
38480
+ return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "0.0.0.0" || hostname === "::1" || hostname === "[::1]" || hostname.startsWith("127.");
38481
+ }
38482
+ function warnForMissingDocumentFonts(missingFonts, warnedFonts, hostname = typeof window === "undefined" ? "" : window.location.hostname) {
38483
+ if (!isLocalDevelopmentHost(hostname) || !Array.isArray(missingFonts)) return;
38484
+ const newlyMissing = [...new Set(missingFonts.map((font) => font.trim()).filter(Boolean))].filter((font) => !warnedFonts.has(font));
38485
+ if (newlyMissing.length === 0) return;
38486
+ for (const font of newlyMissing) warnedFonts.add(font);
38487
+ const noun = newlyMissing.length === 1 ? "font" : "fonts";
38488
+ const names = newlyMissing.map((font) => `"${font}"`).join(", ");
38489
+ console.warn(`[SuperDoc] Missing document ${noun}: ${names}. The browser is using fallback fonts, which can change line and page breaks. Configure document fonts: ${FONT_GUIDE_URL}`);
38490
+ }
38491
+ //#endregion
38477
38492
  //#region src/core/editor-runtime/editor-runtime-registry.ts
38478
38493
  /**
38479
38494
  * Internal SuperDoc registry of mounted editor runtimes and the active-runtime
@@ -45546,6 +45561,7 @@ var SuperDoc = class extends import_eventemitter3.default {
45546
45561
  useLayoutEngine: true
45547
45562
  };
45548
45563
  this.#fontsRelayEditors = /* @__PURE__ */ new WeakSet();
45564
+ this.#warnedMissingFonts = /* @__PURE__ */ new WeakMap();
45549
45565
  this.#lastFontsChangedPayload = null;
45550
45566
  this.#fontsApi = null;
45551
45567
  this.#v2FontsUnsub = null;
@@ -45641,7 +45657,7 @@ var SuperDoc = class extends import_eventemitter3.default {
45641
45657
  this.config.colors = shuffleArray(this.config.colors);
45642
45658
  this.userColorMap = /* @__PURE__ */ new Map();
45643
45659
  this.colorIndex = 0;
45644
- this.version = "2.16.1-next.9";
45660
+ this.version = "2.17.0";
45645
45661
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
45646
45662
  this.superdocId = config.superdocId || v4();
45647
45663
  this.colors = this.config.colors ?? [];
@@ -46635,6 +46651,7 @@ var SuperDoc = class extends import_eventemitter3.default {
46635
46651
  }
46636
46652
  /** Editors whose `fonts-changed` we already relay, so a repeated create wires once. */
46637
46653
  #fontsRelayEditors;
46654
+ #warnedMissingFonts;
46638
46655
  /**
46639
46656
  * Relay an editor's authoritative `fonts-changed` up to the SuperDoc surface, so
46640
46657
  * `superdoc.on('fonts-changed')` / `onFontsChanged` fire without the legacy
@@ -46650,10 +46667,10 @@ var SuperDoc = class extends import_eventemitter3.default {
46650
46667
  if (this.#fontsRelayEditors.has(editor)) return;
46651
46668
  this.#fontsRelayEditors.add(editor);
46652
46669
  editor.on("fonts-changed", (payload) => {
46653
- if (this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(payload);
46670
+ if (this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(editor, payload);
46654
46671
  });
46655
46672
  const cached = (editor.documentRenderer ?? editor["presentationEditor"])?.getLastFontsChangedPayload?.();
46656
- if (cached && this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(cached);
46673
+ if (cached && this.#fontReportSurfaces(editor)) this.#deliverFontsChanged(editor, cached);
46657
46674
  }
46658
46675
  /**
46659
46676
  * Whether a wired editor's font report may surface on the SuperDoc instance. Only the
@@ -46669,8 +46686,16 @@ var SuperDoc = class extends import_eventemitter3.default {
46669
46686
  /** Last font report delivered on this instance, so `fonts.onReport` can replay it. */
46670
46687
  #lastFontsChangedPayload;
46671
46688
  /** Cache then emit a font report, so a later `onReport` subscriber gets the current one. */
46672
- #deliverFontsChanged(payload) {
46689
+ #deliverFontsChanged(editor, payload) {
46673
46690
  this.#lastFontsChangedPayload = payload;
46691
+ if (editor.editorVersion === 2) {
46692
+ let warnedFonts = this.#warnedMissingFonts.get(editor);
46693
+ if (!warnedFonts) {
46694
+ warnedFonts = /* @__PURE__ */ new Set();
46695
+ this.#warnedMissingFonts.set(editor, warnedFonts);
46696
+ }
46697
+ warnForMissingDocumentFonts(payload.missingFonts, warnedFonts);
46698
+ }
46674
46699
  this.emit("fonts-changed", payload);
46675
46700
  }
46676
46701
  /**
@@ -46768,10 +46793,10 @@ var SuperDoc = class extends import_eventemitter3.default {
46768
46793
  #wireV2FontsRelay(facade) {
46769
46794
  this.#teardownV2FontsRelay();
46770
46795
  const runtime = getActiveFontRuntime(facade);
46771
- if (!runtime?.onChanged) return;
46796
+ if (!facade || !runtime?.onChanged) return;
46772
46797
  const current = runtime.getLastFontsChangedPayload?.();
46773
- if (current) this.#deliverFontsChanged(current);
46774
- this.#v2FontsUnsub = runtime.onChanged((payload) => this.#deliverFontsChanged(payload));
46798
+ if (current) this.#deliverFontsChanged(facade, current);
46799
+ this.#v2FontsUnsub = runtime.onChanged((payload) => this.#deliverFontsChanged(facade, payload));
46775
46800
  }
46776
46801
  /**
46777
46802
  * Reconcile the compatibility `activeEditor` projection with a registry