@univerjs/docs 1.0.0-alpha.7 → 1.0.0-beta.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.
package/lib/cjs/facade.js CHANGED
@@ -107,8 +107,9 @@ function stripBlockTokens(text) {
107
107
  * that insert or remove content before it.
108
108
  * @hideconstructor
109
109
  */
110
- var FDocumentTextRange = class {
110
+ var FDocumentTextRange = class extends _univerjs_core_facade.FBaseInitialable {
111
111
  constructor(_document, _startOffset, _endOffset, _segmentId, _injector) {
112
+ super(_injector);
112
113
  this._document = _document;
113
114
  this._startOffset = _startOffset;
114
115
  this._endOffset = _endOffset;
@@ -156,18 +157,11 @@ var FDocumentTextRange = class {
156
157
  */
157
158
  getExplicitTextStyleRuns() {
158
159
  const { textRuns = [] } = this._document.getBody(this._segmentId);
159
- return textRuns.filter((run) => run.st < this._endOffset && run.ed > this._startOffset).map((run) => {
160
- var _run$ts;
161
- return {
162
- startOffset: Math.max(run.st, this._startOffset),
163
- endOffset: Math.min(run.ed, this._endOffset),
164
- textStyle: _univerjs_core.Tools.deepClone((_run$ts = run.ts) !== null && _run$ts !== void 0 ? _run$ts : {})
165
- };
166
- });
167
- }
168
- /** @deprecated Use `getExplicitTextStyleRuns()` to distinguish stored styles from effective styles. */
169
- getTextStyleRuns() {
170
- return this.getExplicitTextStyleRuns();
160
+ return textRuns.filter((run) => run.st < this._endOffset && run.ed > this._startOffset).map((run) => ({
161
+ startOffset: Math.max(run.st, this._startOffset),
162
+ endOffset: Math.min(run.ed, this._endOffset),
163
+ textStyle: _univerjs_core.Tools.deepClone(run.ts ?? {})
164
+ }));
171
165
  }
172
166
  /**
173
167
  * Returns top-level style properties that have the same explicit value
@@ -186,10 +180,6 @@ var FDocumentTextRange = class {
186
180
  for (const key of Object.keys(common)) if (rest.some((run) => !isDeepEqual(run.textStyle[key], common[key]))) delete common[key];
187
181
  return common;
188
182
  }
189
- /** @deprecated Use `getCommonExplicitTextStyle()` to distinguish stored styles from effective styles. */
190
- getCommonTextStyle() {
191
- return this.getCommonExplicitTextStyle();
192
- }
193
183
  /**
194
184
  * Returns a serializable summary suitable for an agent/tool response.
195
185
  * @example
@@ -207,9 +197,7 @@ var FDocumentTextRange = class {
207
197
  text: this.getText(),
208
198
  length: this._endOffset - this._startOffset,
209
199
  explicitTextStyleRuns,
210
- commonExplicitTextStyle,
211
- textStyleRuns: explicitTextStyleRuns,
212
- commonTextStyle: commonExplicitTextStyle
200
+ commonExplicitTextStyle
213
201
  };
214
202
  }
215
203
  /**
@@ -276,23 +264,33 @@ function isDeepEqual(left, right) {
276
264
  return JSON.stringify(left) === JSON.stringify(right);
277
265
  }
278
266
 
267
+ //#endregion
268
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorateParam.js
269
+ function __decorateParam(paramIndex, decorator) {
270
+ return function(target, key) {
271
+ decorator(target, key, paramIndex);
272
+ };
273
+ }
274
+
275
+ //#endregion
276
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorate.js
277
+ function __decorate(decorators, target, key, desc) {
278
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
279
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
280
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
281
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
282
+ }
283
+
279
284
  //#endregion
280
285
  //#region src/facade/f-document-paragraph.ts
281
- /**
282
- * A paragraph facade wrapper.
283
- *
284
- * Paragraph identity is backed by the persisted `paragraphId`. The id is
285
- * re-resolved before each method call, so insertions before this paragraph do
286
- * not break the wrapper.
287
- *
288
- * @hideconstructor
289
- */
290
- var FDocumentParagraph = class {
291
- constructor(_document, _paragraphId, _segmentId = "", _injector) {
286
+ let FDocumentParagraph = class FDocumentParagraph extends _univerjs_core_facade.FBaseInitialable {
287
+ constructor(_document, _paragraphId, _segmentId = "", _injector, _commandService) {
288
+ super(_injector);
292
289
  this._document = _document;
293
290
  this._paragraphId = _paragraphId;
294
291
  this._segmentId = _segmentId;
295
292
  this._injector = _injector;
293
+ this._commandService = _commandService;
296
294
  }
297
295
  /**
298
296
  * Get the persisted paragraph id.
@@ -383,6 +381,71 @@ var FDocumentParagraph = class {
383
381
  return this._injector.createInstance(FDocumentTextRange, this._document, startOffset, endOffset, this._segmentId, this._injector);
384
382
  }
385
383
  /**
384
+ * Finds one literal text occurrence inside this paragraph.
385
+ *
386
+ * The returned text range is fixed when it is created. Resolve a new range
387
+ * after edits that insert or remove content before the match.
388
+ *
389
+ * @param {string} text Literal text to find. It must not be empty.
390
+ * @param {IFDocumentFindTextOptions} [options] Case sensitivity and zero-based occurrence.
391
+ * @returns {FDocumentTextRange | null} The matching fixed text range, or `null` when no such occurrence exists.
392
+ * @example
393
+ * ```ts
394
+ * const univerAPI = FUniver.newAPI(univer);
395
+ * const document = univerAPI.getActiveDocument();
396
+ * if (!document) throw new Error('No active document');
397
+ *
398
+ * const paragraph = document.findParagraphByText('Launch formula');
399
+ * if (!paragraph) throw new Error('Target paragraph not found');
400
+ *
401
+ * const range = paragraph.findText('formula');
402
+ * if (!range) throw new Error('Target text not found');
403
+ *
404
+ * console.log(range.describe());
405
+ * ```
406
+ */
407
+ findText(text, options = {}) {
408
+ const occurrence = options.occurrence ?? 0;
409
+ if (!Number.isInteger(occurrence) || occurrence < 0) throw new RangeError("Text occurrence must be a non-negative integer.");
410
+ return this.findAllText(text, options)[occurrence] ?? null;
411
+ }
412
+ /**
413
+ * Finds every non-overlapping literal text occurrence inside this paragraph.
414
+ *
415
+ * Results are ordered from the start of the paragraph. The returned ranges
416
+ * are fixed when created; use them immediately and resolve new ranges after
417
+ * edits that change earlier document content.
418
+ *
419
+ * @param {string} text Literal text to find. It must not be empty.
420
+ * @param {Omit<IFDocumentFindTextOptions, 'occurrence'>} [options] Case-sensitivity option.
421
+ * @returns {FDocumentTextRange[]} All matching fixed text ranges, or an empty array when no matches exist.
422
+ * @example
423
+ * ```ts
424
+ * const univerAPI = FUniver.newAPI(univer);
425
+ * const document = univerAPI.getActiveDocument();
426
+ * if (!document) throw new Error('No active document');
427
+ *
428
+ * const paragraph = document.findParagraphByText('x plus x');
429
+ * if (!paragraph) throw new Error('Target paragraph not found');
430
+ *
431
+ * const matches = paragraph.findAllText('x');
432
+ * console.log(matches.map((range) => range.describe()));
433
+ * ```
434
+ */
435
+ findAllText(text, options = {}) {
436
+ if (text.length === 0) throw new TypeError("Text to find must not be empty.");
437
+ const matchCase = options.matchCase ?? true;
438
+ const paragraphText = this.getText();
439
+ const matcher = _univerjs_core.regexp.createLiteralRegExp(text, matchCase ? "gu" : "giu");
440
+ const { startOffset } = this.getInfo();
441
+ const matches = [];
442
+ for (const match of paragraphText.matchAll(matcher)) {
443
+ const matchStartOffset = startOffset + match.index;
444
+ matches.push(this._injector.createInstance(FDocumentTextRange, this._document, matchStartOffset, matchStartOffset + match[0].length, this._segmentId, this._injector));
445
+ }
446
+ return matches;
447
+ }
448
+ /**
386
449
  * Get this paragraph's plain text.
387
450
  * @returns {string} The paragraph text without the trailing paragraph break.
388
451
  * @example
@@ -434,59 +497,65 @@ var FDocumentParagraph = class {
434
497
  return this._document.insertText(endOffset, text, this._segmentId);
435
498
  }
436
499
  /**
437
- * Apply paragraph style to a paragraph handle or text range.
500
+ * Applies a paragraph and optional text-style patch through one document command.
501
+ *
502
+ * Pagination values use `BooleanNumber.TRUE` or `BooleanNumber.FALSE`; explicit
503
+ * false is preserved and overrides inherited true. The paragraph and text-style
504
+ * changes share one undo/redo item. A stale paragraph handle returns `false`
505
+ * without applying a partial update.
506
+ *
507
+ * The Traditional renderer applies these Word-compatible pagination rules:
508
+ * use `pageBreakBefore` for a hard chapter-page boundary, `keepLines` for a
509
+ * short paragraph that should stay intact, `keepNext` for a heading or caption
510
+ * that should accompany the next paragraph, and `widowControl` for natural
511
+ * multi-line body text. Do not enable every rule on every paragraph. Modern
512
+ * and Unspecified Docs preserve the values in the model but do not apply them
513
+ * to physical pages.
514
+ *
438
515
  * `style.textStyle.fs` is a font size in points (pt), not CSS pixels.
439
516
  * @param {IParagraphStyle} style The Univer paragraph style patch.
440
- * @returns {boolean} `true` if the style was applied.
517
+ * @returns {boolean} `true` when the complete patch was applied; otherwise `false`.
441
518
  * @example
442
519
  * ```ts
443
- * const fDocument = univerAPI.getActiveDocument();
444
- * const paragraph = fDocument.getParagraphs()[0];
445
- * paragraph?.setText('Styled text');
446
- * paragraph?.setStyle({
447
- * textStyle: {
448
- * cl: {
449
- * rgb: '#FF0000',
450
- * },
451
- * fs: 14,
452
- * },
453
- * horizontalAlign: 2,
520
+ * const document = univerAPI.getActiveDocument();
521
+ * if (!document) {
522
+ * throw new Error('No active document');
523
+ * }
524
+ * if (!document.isTraditional()) {
525
+ * throw new Error('Traditional document pagination is required');
526
+ * }
527
+ * const heading = document.findParagraphByText('Appendix');
528
+ * const following = document.findParagraphByText('Supporting details');
529
+ * if (!heading || !following) {
530
+ * throw new Error('Expected paragraphs were not found');
531
+ * }
532
+ *
533
+ * const headingUpdated = heading.setStyle({
534
+ * pageBreakBefore: univerAPI.Enum.BooleanNumber.TRUE,
535
+ * keepLines: univerAPI.Enum.BooleanNumber.TRUE,
536
+ * keepNext: univerAPI.Enum.BooleanNumber.TRUE,
537
+ * });
538
+ * const followingUpdated = following.setStyle({
539
+ * // Explicit FALSE terminates this authored keepNext chain even if a named
540
+ * // style or document default enables it.
541
+ * keepNext: univerAPI.Enum.BooleanNumber.FALSE,
542
+ * widowControl: univerAPI.Enum.BooleanNumber.TRUE,
454
543
  * });
455
- * console.log(paragraph?.getInfo().paragraph.paragraphStyle);
544
+ * if (!headingUpdated || !followingUpdated) {
545
+ * throw new Error('Failed to update paragraph pagination');
546
+ * }
456
547
  * ```
457
548
  */
458
549
  setStyle(style) {
459
- const { paragraph, startOffset, endOffset } = this.getInfo();
460
- let result = true;
461
- if (style.textStyle && startOffset < endOffset) result = retainBodyRange({
550
+ const { startOffset, endOffset } = this.getInfo();
551
+ return this._commandService.syncExecuteCommand(_univerjs_docs.UpdateDocumentParagraphStyleCommand.id, {
552
+ unitId: this._document.getId(),
553
+ segmentId: this._segmentId,
554
+ paragraphId: this._paragraphId,
462
555
  startOffset,
463
556
  endOffset,
464
- segmentId: this._segmentId
465
- }, {
466
- dataStream: "",
467
- textRuns: [{
468
- st: 0,
469
- ed: endOffset - startOffset,
470
- ts: style.textStyle
471
- }]
472
- }, _univerjs_core.UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
473
- const updateBody = {
474
- dataStream: "",
475
- paragraphs: [{
476
- ...paragraph,
477
- startIndex: 0,
478
- paragraphStyle: {
479
- ...paragraph.paragraphStyle,
480
- ...style
481
- }
482
- }]
483
- };
484
- this._preserveExplicitParagraphIds(updateBody);
485
- return retainBodyRange({
486
- startOffset: endOffset,
487
- endOffset: endOffset + 1,
488
- segmentId: this._segmentId
489
- }, updateBody, _univerjs_core.UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector) && result;
557
+ style
558
+ });
490
559
  }
491
560
  /**
492
561
  * Check whether this paragraph is a bullet, ordered, or checklist item.
@@ -578,6 +647,7 @@ var FDocumentParagraph = class {
578
647
  body[_univerjs_core.RESTORE_INSERTED_PARAGRAPH_IDS] = true;
579
648
  }
580
649
  };
650
+ FDocumentParagraph = __decorate([__decorateParam(4, _univerjs_core.ICommandService)], FDocumentParagraph);
581
651
  function isParagraphFacade(value) {
582
652
  if (typeof value !== "object" || value === null) return false;
583
653
  return typeof value.getId === "function" && typeof value.getSegmentId === "function" && typeof value.getInfo === "function" && typeof value.getRange === "function";
@@ -585,29 +655,30 @@ function isParagraphFacade(value) {
585
655
 
586
656
  //#endregion
587
657
  //#region src/facade/f-document-section.ts
588
- /** Error thrown when traditional section APIs are used to mutate a modern document. */
658
+ function validatePageSetup(pageSetup) {
659
+ const { pageNumberStart, pageSize, pageOrient, marginTop, marginBottom, marginLeft, marginRight } = pageSetup;
660
+ if (pageNumberStart != null && (!Number.isInteger(pageNumberStart) || pageNumberStart < 1)) throw new RangeError("Section page number start must be a positive integer.");
661
+ if (pageSize && [pageSize.width, pageSize.height].some((size) => size != null && (!Number.isFinite(size) || size <= 0))) throw new RangeError("Section page size must be finite and positive.");
662
+ if (pageOrient != null && !Object.values(_univerjs_core.PageOrientType).includes(pageOrient)) throw new RangeError("Invalid section page orientation.");
663
+ if ([
664
+ marginTop,
665
+ marginBottom,
666
+ marginLeft,
667
+ marginRight
668
+ ].some((margin) => margin != null && (!Number.isFinite(margin) || margin < 0))) throw new RangeError("Section page margins must be finite and non-negative.");
669
+ }
670
+ /** Error thrown when a Traditional-only section API is used with another document flavor. */
589
671
  var DocsSectionUnsupportedDocumentFlavorError = class extends Error {
590
672
  constructor() {
591
- super("Section column APIs are supported only in traditional documents. Use ColumnGroup APIs for modern documents.");
673
+ super("Section column APIs are supported only in traditional documents. Use ColumnGroup APIs for modern documents, or resolve an unspecified document flavor first.");
592
674
  this.name = "DocsSectionUnsupportedDocumentFlavorError";
593
675
  }
594
676
  };
595
- /**
596
- * Facade wrapper for an OOXML-compatible traditional document section.
597
- * Modern documents use ColumnGroup APIs and cannot mutate this facade.
598
- * @example
599
- * ```ts
600
- * const fDocument = univerAPI.getActiveDocument();
601
- * if (fDocument && !fDocument.isModern()) {
602
- * console.log(fDocument.getSection(0)?.describe());
603
- * }
604
- * ```
605
- */
606
- var FDocumentSection = class {
607
- constructor(_document, _sectionId, _injector) {
677
+ let FDocumentSection = class FDocumentSection {
678
+ constructor(_document, _sectionId, _commandService) {
608
679
  this._document = _document;
609
680
  this._sectionId = _sectionId;
610
- this._injector = _injector;
681
+ this._commandService = _commandService;
611
682
  }
612
683
  /**
613
684
  * Returns the persisted section id.
@@ -640,8 +711,7 @@ var FDocumentSection = class {
640
711
  * ```
641
712
  */
642
713
  getConfig() {
643
- const { sectionBreak } = this._resolve();
644
- return _univerjs_core.Tools.deepClone(sectionBreak);
714
+ return this._getConfigSnapshot();
645
715
  }
646
716
  /**
647
717
  * Returns the section content range, excluding its terminating section-break token.
@@ -652,17 +722,11 @@ var FDocumentSection = class {
652
722
  * ```
653
723
  */
654
724
  getRange() {
655
- const sectionBreaks = (0, _univerjs_docs.getTopLevelSectionBreaks)(this._document.getBody());
656
- const { index, sectionBreak } = this._resolve();
657
- return {
658
- startOffset: index === 0 ? 0 : sectionBreaks[index - 1].startIndex + 1,
659
- endOffset: sectionBreak.startIndex,
660
- segmentId: ""
661
- };
725
+ return this._getRange(this._resolve().index);
662
726
  }
663
727
  /**
664
728
  * Returns the explicit columns. An empty array means the normal single-column layout.
665
- * Column widths and trailing spaces are in points (pt).
729
+ * Column widths and trailing spaces are in 96-DPI layout pixels.
666
730
  * @example
667
731
  * ```ts
668
732
  * const fDocument = univerAPI.getActiveDocument();
@@ -670,8 +734,7 @@ var FDocumentSection = class {
670
734
  * ```
671
735
  */
672
736
  getColumns() {
673
- var _this$getConfig$colum;
674
- return _univerjs_core.Tools.deepClone((_this$getConfig$colum = this.getConfig().columnProperties) !== null && _this$getConfig$colum !== void 0 ? _this$getConfig$colum : []);
737
+ return _univerjs_core.Tools.deepClone(this._getConfigSnapshot().columnProperties ?? []);
675
738
  }
676
739
  /**
677
740
  * Returns a compact serializable section summary.
@@ -682,9 +745,9 @@ var FDocumentSection = class {
682
745
  * ```
683
746
  */
684
747
  describe() {
685
- var _config$columnPropert, _config$columnSeparat, _config$sectionType;
686
- const config = this.getConfig();
687
- const columns = (_config$columnPropert = config.columnProperties) !== null && _config$columnPropert !== void 0 ? _config$columnPropert : [];
748
+ const { index } = this._resolve();
749
+ const config = this._getConfigSnapshot();
750
+ const columns = config.columnProperties ?? [];
688
751
  const headerFooter = {
689
752
  defaultHeader: this._describeHeaderFooterReference("header", "default"),
690
753
  defaultFooter: this._describeHeaderFooterReference("footer", "default"),
@@ -695,12 +758,12 @@ var FDocumentSection = class {
695
758
  };
696
759
  return {
697
760
  sectionId: this._sectionId,
698
- index: this.getIndex(),
699
- range: this.getRange(),
761
+ index,
762
+ range: this._getRange(index),
700
763
  columnCount: columns.length || 1,
701
764
  columns: _univerjs_core.Tools.deepClone(columns),
702
- columnSeparatorType: (_config$columnSeparat = config.columnSeparatorType) !== null && _config$columnSeparat !== void 0 ? _config$columnSeparat : _univerjs_core.ColumnSeparatorType.NONE,
703
- sectionType: (_config$sectionType = config.sectionType) !== null && _config$sectionType !== void 0 ? _config$sectionType : _univerjs_core.SectionType.SECTION_TYPE_UNSPECIFIED,
765
+ columnSeparatorType: config.columnSeparatorType ?? _univerjs_core.ColumnSeparatorType.NONE,
766
+ sectionType: config.sectionType ?? _univerjs_core.SectionType.SECTION_TYPE_UNSPECIFIED,
704
767
  headerFooter,
705
768
  config
706
769
  };
@@ -708,36 +771,36 @@ var FDocumentSection = class {
708
771
  /**
709
772
  * Sets equal or explicitly sized columns for this traditional section.
710
773
  * Use `columnCount = 1` to restore normal single-column layout.
711
- * `gap` and `widths` are in points (pt).
774
+ * `gap` and `widths` are in 96-DPI layout pixels.
712
775
  * @example
713
776
  * ```ts
714
777
  * const fDocument = univerAPI.getActiveDocument();
715
- * if (fDocument && !fDocument.isModern()) {
778
+ * if (fDocument?.isTraditional()) {
716
779
  * fDocument.getSection(0)?.setColumns(2, { gap: 18, separator: true });
717
780
  * }
718
781
  * ```
719
782
  */
720
783
  setColumns(columnCount, options = {}) {
721
- var _options$gap, _options$separator;
722
784
  this._assertTraditionalDocument();
723
785
  if (!Number.isInteger(columnCount) || columnCount < 1) throw new RangeError("Section column count must be a positive integer.");
724
786
  if (options.widths && options.widths.length !== columnCount) throw new RangeError("Section column widths must match the column count.");
725
- const gap = Math.max(0, (_options$gap = options.gap) !== null && _options$gap !== void 0 ? _options$gap : 18);
726
- const config = this.getConfig();
787
+ if (options.gap != null && (!Number.isFinite(options.gap) || options.gap < 0)) throw new RangeError("Section column gap must be finite and non-negative.");
788
+ const gap = Math.max(0, options.gap ?? 18);
789
+ const config = this._getConfigSnapshot();
727
790
  const columns = (0, _univerjs_docs.createSectionColumnProperties)(this._document.getDocumentDataModel().getSnapshot().documentStyle, config, columnCount, gap, options.widths);
728
- const separator = typeof options.separator === "boolean" ? options.separator ? _univerjs_core.ColumnSeparatorType.BETWEEN_EACH_COLUMN : _univerjs_core.ColumnSeparatorType.NONE : (_options$separator = options.separator) !== null && _options$separator !== void 0 ? _options$separator : _univerjs_core.ColumnSeparatorType.NONE;
791
+ const separator = typeof options.separator === "boolean" ? options.separator ? _univerjs_core.ColumnSeparatorType.BETWEEN_EACH_COLUMN : _univerjs_core.ColumnSeparatorType.NONE : options.separator ?? _univerjs_core.ColumnSeparatorType.NONE;
792
+ if (!Object.values(_univerjs_core.ColumnSeparatorType).includes(separator)) throw new RangeError("Invalid section column separator type.");
729
793
  return this._update({
730
794
  columnProperties: columns,
731
- columnSeparatorType: separator,
732
- ...options.sectionType == null ? {} : { sectionType: options.sectionType }
795
+ columnSeparatorType: separator
733
796
  });
734
797
  }
735
798
  /**
736
- * Sets explicit OOXML-compatible column width and trailing-space values in points (pt).
799
+ * Sets explicit OOXML-compatible column width and trailing-space values in 96-DPI layout pixels.
737
800
  * @example
738
801
  * ```ts
739
802
  * const fDocument = univerAPI.getActiveDocument();
740
- * if (fDocument && !fDocument.isModern()) {
803
+ * if (fDocument?.isTraditional()) {
741
804
  * fDocument.getSection(0)?.setColumnProperties([
742
805
  * { width: 240, paddingEnd: 18 },
743
806
  * { width: 240, paddingEnd: 0 },
@@ -747,32 +810,163 @@ var FDocumentSection = class {
747
810
  */
748
811
  setColumnProperties(columns, separator = _univerjs_core.ColumnSeparatorType.NONE) {
749
812
  this._assertTraditionalDocument();
750
- if (columns.some(({ width, paddingEnd }) => width < 0 || paddingEnd < 0)) throw new RangeError("Section column widths and padding must be non-negative.");
813
+ if (!Object.values(_univerjs_core.ColumnSeparatorType).includes(separator)) throw new RangeError("Invalid section column separator type.");
814
+ if (columns.some(({ width, paddingEnd }) => !Number.isFinite(width) || !Number.isFinite(paddingEnd) || width < 0 || paddingEnd < 0)) throw new RangeError("Section column widths and padding must be finite and non-negative.");
815
+ const contentWidth = (0, _univerjs_docs.getSectionContentWidth)(this._document.getDocumentDataModel().getSnapshot().documentStyle, this._getConfigSnapshot());
816
+ if (columns.reduce((sum, { width, paddingEnd }) => sum + width + paddingEnd, 0) > contentWidth) throw new RangeError("Section columns exceed the available page content width.");
751
817
  return this._update({
752
818
  columnProperties: _univerjs_core.Tools.deepClone(columns),
753
819
  columnSeparatorType: separator
754
820
  });
755
821
  }
756
822
  /**
757
- * Sets how the next section begins.
823
+ * Sets how this section begins relative to the previous section.
824
+ *
825
+ * The first section has no preceding boundary, so setting its type does not
826
+ * create an initial blank page. Prefer `FDocument.insertSectionBreak` with
827
+ * `nextSectionType` when creating a new boundary; use this method when
828
+ * updating an existing section after resolving it again from the document.
829
+ *
830
+ * @param {SectionType} sectionType How this section begins.
831
+ * @returns {boolean} `true` when the section command was applied.
758
832
  * @example
759
833
  * ```ts
760
- * const fDocument = univerAPI.getActiveDocument();
761
- * if (fDocument && !fDocument.isModern()) {
762
- * fDocument.getSection(0)?.setSectionType(univerAPI.Enum.SectionType.NEXT_PAGE);
834
+ * const document = univerAPI.getActiveDocument();
835
+ * if (!document?.isTraditional()) {
836
+ * throw new Error('A Traditional document is required');
837
+ * }
838
+ *
839
+ * const secondSection = document.getSection(1);
840
+ * if (!secondSection) {
841
+ * throw new Error('The second section does not exist');
842
+ * }
843
+ * if (!secondSection.setSectionType(univerAPI.Enum.SectionType.NEXT_PAGE)) {
844
+ * throw new Error('Failed to update the second section');
763
845
  * }
764
846
  * ```
765
847
  */
766
848
  setSectionType(sectionType) {
767
849
  this._assertTraditionalDocument();
850
+ if (!Object.values(_univerjs_core.SectionType).includes(sectionType)) throw new RangeError("Invalid section type.");
768
851
  return this._update({ sectionType });
769
852
  }
770
853
  /**
854
+ * Returns this section's explicit page setup overrides.
855
+ * Missing values inherit from the document style. Geometry values use 96-DPI layout pixels.
856
+ *
857
+ * Use `getEffectivePageSetup()` when an agent needs resolved page and content
858
+ * dimensions rather than only the overrides stored on this section.
859
+ *
860
+ * @returns {FDocumentSectionPageSetup} A cloned object containing only explicit section overrides.
861
+ * @example
862
+ * ```ts
863
+ * const document = univerAPI.getActiveDocument();
864
+ * const section = document?.getSection(0);
865
+ * console.log(section?.getPageSetup());
866
+ * ```
867
+ */
868
+ getPageSetup() {
869
+ const { pageNumberStart, pageSize, pageOrient, marginTop, marginBottom, marginLeft, marginRight } = this._getConfigSnapshot();
870
+ return _univerjs_core.Tools.deepClone({
871
+ pageNumberStart,
872
+ pageSize,
873
+ pageOrient,
874
+ marginTop,
875
+ marginBottom,
876
+ marginLeft,
877
+ marginRight
878
+ });
879
+ }
880
+ /**
881
+ * Returns nominal page geometry after resolving this section's overrides
882
+ * against document defaults. All geometry values use 96-DPI layout pixels.
883
+ *
884
+ * This synchronous model-only API works without `engine-render`. It does not
885
+ * report physical page count, remaining page space, or final coordinates.
886
+ *
887
+ * @returns {IEffectiveSectionPageSetup} A cloned, serializable page setup.
888
+ * @example
889
+ * ```ts
890
+ * const document = univerAPI.getActiveDocument();
891
+ * if (!document) {
892
+ * throw new Error('No active document');
893
+ * }
894
+ * if (!document.isTraditional()) {
895
+ * throw new Error('Traditional document sections are required');
896
+ * }
897
+ *
898
+ * const section = document.getSection(0);
899
+ * if (!section) {
900
+ * throw new Error('The document has no traditional section');
901
+ * }
902
+ *
903
+ * const layout = section.getEffectivePageSetup();
904
+ * console.log({
905
+ * pageWidth: layout.pageSize.width,
906
+ * pageHeight: layout.pageSize.height,
907
+ * contentWidth: layout.contentSize.width,
908
+ * contentHeight: layout.contentSize.height,
909
+ * margins: layout.margins,
910
+ * });
911
+ * ```
912
+ */
913
+ getEffectivePageSetup() {
914
+ this._assertTraditionalDocument();
915
+ const documentStyle = this._document.getDocumentDataModel().getSnapshot().documentStyle;
916
+ return _univerjs_core.Tools.deepClone((0, _univerjs_docs.getEffectiveSectionPageSetup)(documentStyle, this._getConfigSnapshot()));
917
+ }
918
+ /**
919
+ * Updates this section's page setup through the document section command.
920
+ * Geometry values use 96-DPI layout pixels.
921
+ *
922
+ * This method changes static page geometry; it does not choose where the
923
+ * section begins. Use `setSectionType()` for an existing boundary, or
924
+ * `insertSectionBreak(..., { nextSectionType })` while creating one.
925
+ *
926
+ * @param {FDocumentSectionPageSetup} pageSetup Explicit section overrides to patch.
927
+ * @returns {boolean} `true` when the section command was applied.
928
+ * @example
929
+ * ```ts
930
+ * const document = univerAPI.getActiveDocument();
931
+ * if (!document?.isTraditional()) {
932
+ * throw new Error('A Traditional document is required');
933
+ * }
934
+ *
935
+ * const section = document.getSection(1);
936
+ * if (!section) {
937
+ * throw new Error('The second section does not exist');
938
+ * }
939
+ * const updated = section.setPageSetup({
940
+ * pageSize: { width: 816, height: 1056 },
941
+ * marginTop: 96,
942
+ * marginBottom: 96,
943
+ * marginLeft: 96,
944
+ * marginRight: 96,
945
+ * });
946
+ * if (!updated) {
947
+ * throw new Error('Failed to update section page setup');
948
+ * }
949
+ * console.log(section.getEffectivePageSetup());
950
+ * ```
951
+ */
952
+ setPageSetup(pageSetup) {
953
+ this._assertTraditionalDocument();
954
+ validatePageSetup(pageSetup);
955
+ const definedPageSetup = _univerjs_core.Tools.deepClone(pageSetup);
956
+ _univerjs_core.Tools.removeNull(definedPageSetup);
957
+ const documentStyle = this._document.getDocumentDataModel().getSnapshot().documentStyle;
958
+ (0, _univerjs_docs.getEffectiveSectionPageSetup)(documentStyle, {
959
+ ...this._getConfigSnapshot(),
960
+ ...definedPageSetup
961
+ });
962
+ return this._update(definedPageSetup);
963
+ }
964
+ /**
771
965
  * Ensures a header segment linked specifically to this section.
772
966
  * @example
773
967
  * ```ts
774
968
  * const fDocument = univerAPI.getActiveDocument();
775
- * if (fDocument && !fDocument.isModern()) {
969
+ * if (fDocument?.isTraditional()) {
776
970
  * const segmentId = fDocument.getSection(0)?.ensureHeader();
777
971
  * if (segmentId) {
778
972
  * fDocument.insertText(0, 'Quarterly report', segmentId);
@@ -788,7 +982,7 @@ var FDocumentSection = class {
788
982
  * @example
789
983
  * ```ts
790
984
  * const fDocument = univerAPI.getActiveDocument();
791
- * if (fDocument && !fDocument.isModern()) {
985
+ * if (fDocument?.isTraditional()) {
792
986
  * const segmentId = fDocument.getSection(0)?.ensureFooter('first');
793
987
  * if (segmentId) {
794
988
  * fDocument.insertText(0, 'Confidential', segmentId);
@@ -808,8 +1002,7 @@ var FDocumentSection = class {
808
1002
  * ```
809
1003
  */
810
1004
  getHeaderId(variant = "default") {
811
- var _this$_getHeaderFoote;
812
- return (_this$_getHeaderFoote = this._getHeaderFooterReference("header", variant).segmentId) !== null && _this$_getHeaderFoote !== void 0 ? _this$_getHeaderFoote : null;
1005
+ return this._getHeaderFooterReference("header", variant).segmentId ?? null;
813
1006
  }
814
1007
  /**
815
1008
  * Returns the effective footer id after resolving links to previous sections.
@@ -820,8 +1013,7 @@ var FDocumentSection = class {
820
1013
  * ```
821
1014
  */
822
1015
  getFooterId(variant = "default") {
823
- var _this$_getHeaderFoote2;
824
- return (_this$_getHeaderFoote2 = this._getHeaderFooterReference("footer", variant).segmentId) !== null && _this$_getHeaderFoote2 !== void 0 ? _this$_getHeaderFoote2 : null;
1016
+ return this._getHeaderFooterReference("footer", variant).segmentId ?? null;
825
1017
  }
826
1018
  /**
827
1019
  * Whether this header variant inherits the previous section's reference.
@@ -850,7 +1042,7 @@ var FDocumentSection = class {
850
1042
  * @example
851
1043
  * ```ts
852
1044
  * const fDocument = univerAPI.getActiveDocument();
853
- * if (fDocument && !fDocument.isModern()) {
1045
+ * if (fDocument?.isTraditional()) {
854
1046
  * fDocument.getSection(1)?.setHeaderLinkedToPrevious(false, 'default');
855
1047
  * }
856
1048
  * ```
@@ -863,7 +1055,7 @@ var FDocumentSection = class {
863
1055
  * @example
864
1056
  * ```ts
865
1057
  * const fDocument = univerAPI.getActiveDocument();
866
- * if (fDocument && !fDocument.isModern()) {
1058
+ * if (fDocument?.isTraditional()) {
867
1059
  * fDocument.getSection(1)?.setFooterLinkedToPrevious(true, 'even');
868
1060
  * }
869
1061
  * ```
@@ -873,11 +1065,11 @@ var FDocumentSection = class {
873
1065
  }
874
1066
  /**
875
1067
  * Updates header/footer switches and margins on this section break.
876
- * `marginHeader` and `marginFooter` are in points (pt).
1068
+ * `marginHeader` and `marginFooter` are in 96-DPI layout pixels.
877
1069
  * @example
878
1070
  * ```ts
879
1071
  * const fDocument = univerAPI.getActiveDocument();
880
- * if (fDocument && !fDocument.isModern()) {
1072
+ * if (fDocument?.isTraditional()) {
881
1073
  * fDocument.getSection(0)?.setHeaderFooterOptions({
882
1074
  * marginHeader: 36,
883
1075
  * marginFooter: 36,
@@ -895,7 +1087,7 @@ var FDocumentSection = class {
895
1087
  * @example
896
1088
  * ```ts
897
1089
  * const fDocument = univerAPI.getActiveDocument();
898
- * if (fDocument && !fDocument.isModern()) {
1090
+ * if (fDocument?.isTraditional()) {
899
1091
  * const sections = fDocument.getSections();
900
1092
  * if (sections.length > 1) {
901
1093
  * sections[0].remove();
@@ -905,14 +1097,14 @@ var FDocumentSection = class {
905
1097
  */
906
1098
  remove() {
907
1099
  this._assertTraditionalDocument();
908
- return this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.DeleteDocumentSectionBreakCommand.id, {
1100
+ return this._commandService.syncExecuteCommand(_univerjs_docs.DeleteDocumentSectionBreakCommand.id, {
909
1101
  unitId: this._document.getId(),
910
1102
  sectionId: this._sectionId
911
1103
  });
912
1104
  }
913
1105
  _update(patch) {
914
1106
  const { sectionId: _sectionId, startIndex: _startIndex, ...config } = patch;
915
- return this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.UpdateDocumentSectionCommand.id, {
1107
+ return this._commandService.syncExecuteCommand(_univerjs_docs.UpdateDocumentSectionCommand.id, {
916
1108
  unitId: this._document.getId(),
917
1109
  updates: [{
918
1110
  sectionId: this._sectionId,
@@ -923,11 +1115,11 @@ var FDocumentSection = class {
923
1115
  _ensureHeaderFooter(kind, variant) {
924
1116
  this._assertTraditionalDocument();
925
1117
  const { index } = this._resolve();
926
- const existing = this.getConfig()[(0, _univerjs_core.getSectionHeaderFooterReferenceKey)(kind, variant)];
1118
+ const existing = this._getConfigSnapshot()[(0, _univerjs_core.getSectionHeaderFooterReferenceKey)(kind, variant)];
927
1119
  if (typeof existing === "string" && existing) return existing;
928
1120
  if (index > 0) {
929
1121
  const segmentId = (0, _univerjs_core.generateRandomId)(6);
930
- if (!this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.SetSectionHeaderFooterLinkCommand.id, {
1122
+ if (!this._commandService.syncExecuteCommand(_univerjs_docs.SetSectionHeaderFooterLinkCommand.id, {
931
1123
  unitId: this._document.getId(),
932
1124
  sectionId: this._sectionId,
933
1125
  kind,
@@ -943,7 +1135,7 @@ var FDocumentSection = class {
943
1135
  even: kind === "header" ? _univerjs_docs.HeaderFooterType.EVEN_PAGE_HEADER : _univerjs_docs.HeaderFooterType.EVEN_PAGE_FOOTER
944
1136
  };
945
1137
  const segmentId = (0, _univerjs_core.generateRandomId)(6);
946
- if (!this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.CreateHeaderFooterCommand.id, {
1138
+ if (!this._commandService.syncExecuteCommand(_univerjs_docs.CreateHeaderFooterCommand.id, {
947
1139
  unitId: this._document.getId(),
948
1140
  segmentId,
949
1141
  createType: types[variant],
@@ -956,16 +1148,15 @@ var FDocumentSection = class {
956
1148
  return (0, _univerjs_core.resolveSectionHeaderFooterReference)(this._document.getDocumentDataModel().getSnapshot().documentStyle, (0, _univerjs_docs.getTopLevelSectionBreaks)(this._document.getBody()), index, (0, _univerjs_core.getSectionHeaderFooterReferenceKey)(kind, variant));
957
1149
  }
958
1150
  _describeHeaderFooterReference(kind, variant) {
959
- var _reference$segmentId;
960
1151
  const reference = this._getHeaderFooterReference(kind, variant);
961
1152
  return {
962
- segmentId: (_reference$segmentId = reference.segmentId) !== null && _reference$segmentId !== void 0 ? _reference$segmentId : null,
1153
+ segmentId: reference.segmentId ?? null,
963
1154
  linkedToPrevious: reference.linkedToPrevious
964
1155
  };
965
1156
  }
966
1157
  _setHeaderFooterLinkedToPrevious(kind, variant, linkedToPrevious) {
967
1158
  this._assertTraditionalDocument();
968
- return this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.SetSectionHeaderFooterLinkCommand.id, {
1159
+ return this._commandService.syncExecuteCommand(_univerjs_docs.SetSectionHeaderFooterLinkCommand.id, {
969
1160
  unitId: this._document.getId(),
970
1161
  sectionId: this._sectionId,
971
1162
  kind,
@@ -977,6 +1168,17 @@ var FDocumentSection = class {
977
1168
  _assertTraditionalDocument() {
978
1169
  if (this._document.getDocumentDataModel().getSnapshot().documentStyle.documentFlavor !== _univerjs_core.DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
979
1170
  }
1171
+ _getConfigSnapshot() {
1172
+ return _univerjs_core.Tools.deepClone(this._resolve().sectionBreak);
1173
+ }
1174
+ _getRange(index) {
1175
+ const sectionBreaks = (0, _univerjs_docs.getTopLevelSectionBreaks)(this._document.getBody());
1176
+ return {
1177
+ startOffset: index === 0 ? 0 : sectionBreaks[index - 1].startIndex + 1,
1178
+ endOffset: sectionBreaks[index].startIndex,
1179
+ segmentId: ""
1180
+ };
1181
+ }
980
1182
  _resolve() {
981
1183
  this._assertTraditionalDocument();
982
1184
  const sectionBreaks = (0, _univerjs_docs.getTopLevelSectionBreaks)(this._document.getBody());
@@ -988,9 +1190,10 @@ var FDocumentSection = class {
988
1190
  };
989
1191
  }
990
1192
  };
1193
+ FDocumentSection = __decorate([__decorateParam(2, _univerjs_core.ICommandService)], FDocumentSection);
991
1194
 
992
1195
  //#endregion
993
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
1196
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/typeof.js
994
1197
  function _typeof(o) {
995
1198
  "@babel/helpers - typeof";
996
1199
  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
@@ -1001,7 +1204,7 @@ function _typeof(o) {
1001
1204
  }
1002
1205
 
1003
1206
  //#endregion
1004
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPrimitive.js
1207
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPrimitive.js
1005
1208
  function toPrimitive(t, r) {
1006
1209
  if ("object" != _typeof(t) || !t) return t;
1007
1210
  var e = t[Symbol.toPrimitive];
@@ -1014,14 +1217,14 @@ function toPrimitive(t, r) {
1014
1217
  }
1015
1218
 
1016
1219
  //#endregion
1017
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
1220
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPropertyKey.js
1018
1221
  function toPropertyKey(t) {
1019
1222
  var i = toPrimitive(t, "string");
1020
1223
  return "symbol" == _typeof(i) ? i : i + "";
1021
1224
  }
1022
1225
 
1023
1226
  //#endregion
1024
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
1227
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/defineProperty.js
1025
1228
  function _defineProperty(e, r, t) {
1026
1229
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
1027
1230
  value: t,
@@ -1031,23 +1234,6 @@ function _defineProperty(e, r, t) {
1031
1234
  }) : e[r] = t, e;
1032
1235
  }
1033
1236
 
1034
- //#endregion
1035
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorateParam.js
1036
- function __decorateParam(paramIndex, decorator) {
1037
- return function(target, key) {
1038
- decorator(target, key, paramIndex);
1039
- };
1040
- }
1041
-
1042
- //#endregion
1043
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorate.js
1044
- function __decorate(decorators, target, key, desc) {
1045
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1046
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1047
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1048
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1049
- }
1050
-
1051
1237
  //#endregion
1052
1238
  //#region src/facade/f-document.ts
1053
1239
  let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
@@ -1080,6 +1266,28 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1080
1266
  return documentDataModel;
1081
1267
  }
1082
1268
  /**
1269
+ * Returns the document's custom blocks in stable model order.
1270
+ *
1271
+ * This method is available in Node/headless environments and does not
1272
+ * perform font measurement, line wrapping, pagination, or rendering.
1273
+ *
1274
+ * @returns {IDocumentCustomBlockLayout} Custom block identifiers and model positions.
1275
+ * @example
1276
+ * ```ts
1277
+ * const document = univerAPI.getActiveDocument();
1278
+ * const layout = document?.getCustomBlockLayout();
1279
+ * console.log(layout?.blocks);
1280
+ * ```
1281
+ */
1282
+ getCustomBlockLayout() {
1283
+ var _this$_documentDataMo;
1284
+ return { blocks: (((_this$_documentDataMo = this._documentDataModel.getBody()) === null || _this$_documentDataMo === void 0 ? void 0 : _this$_documentDataMo.customBlocks) ?? []).map(({ blockId, startIndex }, index) => ({
1285
+ blockId,
1286
+ startIndex,
1287
+ index
1288
+ })) };
1289
+ }
1290
+ /**
1083
1291
  * Get the document body or header/footer body by the segment id.
1084
1292
  * The main body has an empty segment id.
1085
1293
  * The header and footer body have their respective segment ids.
@@ -1095,8 +1303,8 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1095
1303
  * ```
1096
1304
  */
1097
1305
  getBody(segmentId = "") {
1098
- var _this$_documentDataMo;
1099
- const body = (_this$_documentDataMo = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _this$_documentDataMo === void 0 ? void 0 : _this$_documentDataMo.getBody();
1306
+ var _this$_documentDataMo2;
1307
+ const body = (_this$_documentDataMo2 = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _this$_documentDataMo2 === void 0 ? void 0 : _this$_documentDataMo2.getBody();
1100
1308
  if (!body) throw new Error(segmentId === "" ? "Body is not found in the document." : `Body is not found in the segment: ${segmentId}`);
1101
1309
  return body;
1102
1310
  }
@@ -1128,16 +1336,72 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1128
1336
  return this._documentDataModel.getTitle() || "";
1129
1337
  }
1130
1338
  /**
1131
- * Whether the document is a modern document or not.
1132
- * @returns {boolean} `true` if the document is a modern document, or `false` if it is not.
1339
+ * Returns the document's explicit layout flavor.
1340
+ *
1341
+ * Use this method when all three states matter. Do not infer a Traditional
1342
+ * document from `!isModern()`: that expression is also true for
1343
+ * `DocumentFlavor.UNSPECIFIED`.
1344
+ *
1345
+ * @returns {DocumentFlavor} `TRADITIONAL`, `MODERN`, or `UNSPECIFIED`.
1346
+ * @example
1347
+ * ```typescript
1348
+ * const document = univerAPI.getActiveDocument();
1349
+ * if (!document) {
1350
+ * throw new Error('No active document');
1351
+ * }
1352
+ *
1353
+ * switch (document.getDocumentFlavor()) {
1354
+ * case univerAPI.Enum.DocumentFlavor.TRADITIONAL:
1355
+ * console.log('Word-compatible physical pagination is available');
1356
+ * break;
1357
+ * case univerAPI.Enum.DocumentFlavor.MODERN:
1358
+ * console.log('Use Modern Doc layout APIs such as ColumnGroup');
1359
+ * break;
1360
+ * default:
1361
+ * console.log('Resolve the unspecified flavor before using flavor-specific APIs');
1362
+ * }
1363
+ * ```
1364
+ */
1365
+ getDocumentFlavor() {
1366
+ return this._resolveDocumentFlavor();
1367
+ }
1368
+ /**
1369
+ * Whether this is a Traditional document with Word-compatible physical pagination.
1370
+ *
1371
+ * Prefer this positive guard before calling section, column-break, page-setup,
1372
+ * or paragraph-pagination APIs.
1373
+ *
1374
+ * @returns {boolean} `true` only for `DocumentFlavor.TRADITIONAL`.
1375
+ * @example
1376
+ * ```typescript
1377
+ * const document = univerAPI.getActiveDocument();
1378
+ * if (document?.isTraditional()) {
1379
+ * console.log(document.getSection(0)?.getEffectivePageSetup());
1380
+ * }
1381
+ * ```
1382
+ */
1383
+ isTraditional() {
1384
+ return this._resolveDocumentFlavor() === _univerjs_core.DocumentFlavor.TRADITIONAL;
1385
+ }
1386
+ /**
1387
+ * Whether this is a Modern document.
1388
+ *
1389
+ * A `false` result can mean either Traditional or Unspecified. Use
1390
+ * `isTraditional()` before Traditional-only APIs, or `getDocumentFlavor()`
1391
+ * when all three states matter.
1392
+ *
1393
+ * @returns {boolean} `true` only for `DocumentFlavor.MODERN`.
1133
1394
  * @example
1134
1395
  * ```typescript
1135
1396
  * const fDocument = univerAPI.getActiveDocument();
1136
- * console.log(fDocument.isModern());
1397
+ * console.log(fDocument?.isModern());
1137
1398
  * ```
1138
1399
  */
1139
1400
  isModern() {
1140
- return this._documentDataModel.getSnapshot().documentStyle.documentFlavor === _univerjs_core.DocumentFlavor.MODERN;
1401
+ return this._resolveDocumentFlavor() === _univerjs_core.DocumentFlavor.MODERN;
1402
+ }
1403
+ _resolveDocumentFlavor() {
1404
+ return this._documentDataModel.getSnapshot().documentStyle.documentFlavor ?? _univerjs_core.DocumentFlavor.UNSPECIFIED;
1141
1405
  }
1142
1406
  /**
1143
1407
  * Save the document snapshot data, including the document content and resource data, etc.
@@ -1231,7 +1495,7 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1231
1495
  }, buildPlainTextInsertBody(text), this._documentDataModel, this._injector);
1232
1496
  }
1233
1497
  /**
1234
- * Returns document-level header/footer switches and margins. Margin values are in points (pt).
1498
+ * Returns document-level header/footer switches and margins. Margin values use 96-DPI layout pixels.
1235
1499
  * @example
1236
1500
  * ```ts
1237
1501
  * const fDocument = univerAPI.getActiveDocument();
@@ -1248,12 +1512,18 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1248
1512
  };
1249
1513
  }
1250
1514
  /**
1251
- * Updates document-level header/footer switches and margins in a traditional document.
1252
- * `marginHeader` and `marginFooter` are in points (pt).
1515
+ * Updates document-level header/footer switches and margins.
1516
+ *
1517
+ * Traditional and Unspecified documents keep the legacy header/footer
1518
+ * behavior. Modern documents reject this API. `marginHeader` and
1519
+ * `marginFooter` use 96-DPI layout pixels.
1253
1520
  * @example
1254
1521
  * ```ts
1255
1522
  * const fDocument = univerAPI.getActiveDocument();
1256
- * if (fDocument && !fDocument.isModern()) {
1523
+ * if (
1524
+ * fDocument &&
1525
+ * fDocument.getDocumentFlavor() !== univerAPI.Enum.DocumentFlavor.MODERN
1526
+ * ) {
1257
1527
  * fDocument.setHeaderFooterOptions({ marginHeader: 36, marginFooter: 36 });
1258
1528
  * }
1259
1529
  * ```
@@ -1294,7 +1564,7 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1294
1564
  */
1295
1565
  getSections() {
1296
1566
  if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== _univerjs_core.DocumentFlavor.TRADITIONAL) return [];
1297
- return (0, _univerjs_docs.getTopLevelSectionBreaks)(this.getBody()).map((sectionBreak) => this._injector.createInstance(FDocumentSection, this, sectionBreak.sectionId, this._injector));
1567
+ return (0, _univerjs_docs.getTopLevelSectionBreaks)(this.getBody()).map((sectionBreak) => this._injector.createInstance(FDocumentSection, this, sectionBreak.sectionId));
1298
1568
  }
1299
1569
  /**
1300
1570
  * Returns a traditional section by zero-based index, or `null` in modern documents.
@@ -1306,8 +1576,7 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1306
1576
  * ```
1307
1577
  */
1308
1578
  getSection(index) {
1309
- var _this$getSections$ind;
1310
- return (_this$getSections$ind = this.getSections()[index]) !== null && _this$getSections$ind !== void 0 ? _this$getSections$ind : null;
1579
+ return this.getSections()[index] ?? null;
1311
1580
  }
1312
1581
  /**
1313
1582
  * Returns the traditional section containing a data-stream offset, or `null` in modern documents.
@@ -1321,45 +1590,84 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1321
1590
  * ```
1322
1591
  */
1323
1592
  getSectionAt(offset) {
1324
- var _this$getSections$fin;
1325
- return (_this$getSections$fin = this.getSections().find((section) => {
1593
+ return this.getSections().find((section) => {
1326
1594
  const range = section.getRange();
1327
- return offset >= range.startOffset && offset <= range.endOffset;
1328
- })) !== null && _this$getSections$fin !== void 0 ? _this$getSections$fin : null;
1595
+ return offset >= range.startOffset && offset < range.endOffset;
1596
+ }) ?? null;
1329
1597
  }
1330
1598
  /**
1331
1599
  * Inserts a traditional document section break and returns its stable facade.
1332
- * Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
1333
- * Numeric layout values in `config` are in points (pt).
1600
+ *
1601
+ * `options` configures the section created before the inserted break.
1602
+ * Set `options.nextSectionType` to control how the existing section after the
1603
+ * break begins. For example, use `SectionType.NEXT_PAGE` to start a chapter on
1604
+ * a new physical page. Both changes are executed by one command and are
1605
+ * undone or redone together.
1606
+ *
1607
+ * The offset must be a top-level document position. To insert a break before
1608
+ * a table or block such as a callout, use that object's start offset instead
1609
+ * of an offset inside the object.
1610
+ *
1611
+ * Modern documents must use ColumnGroup. Unspecified documents must resolve
1612
+ * their flavor first. Both throw `DocsSectionUnsupportedDocumentFlavorError`.
1613
+ * Numeric layout values in `options` are in 96-DPI layout pixels.
1614
+ *
1615
+ * @param {number} offset Top-level data-stream offset where the section break is inserted.
1616
+ * @param {IFDocumentInsertSectionBreakOptions} [options] Section properties and the optional type of the following section.
1617
+ * @returns {FDocumentSection | null} The section created before the break, or `null` when the command rejects the insertion.
1334
1618
  * @example
1335
1619
  * ```ts
1336
- * const fDocument = univerAPI.getActiveDocument();
1337
- * if (fDocument && !fDocument.isModern()) {
1338
- * const paragraph = fDocument.findParagraphByText('Appendix');
1339
- * const offset = paragraph?.getInfo().startOffset;
1340
- * const section = offset == null ? null : fDocument.insertSectionBreak(offset);
1341
- * console.log(section?.getId());
1620
+ * const document = univerAPI.getActiveDocument();
1621
+ * if (!document) {
1622
+ * throw new Error('No active document');
1623
+ * }
1624
+ * if (!document.isTraditional()) {
1625
+ * throw new Error('Traditional document sections are required');
1626
+ * }
1627
+ *
1628
+ * const chapter = document.findParagraphByText('Chapter 2');
1629
+ * if (!chapter) {
1630
+ * throw new Error('Chapter heading not found');
1631
+ * }
1632
+ *
1633
+ * // Insert the boundary immediately before the chapter heading. The command
1634
+ * // also marks the following section as NEXT_PAGE, so the two model changes
1635
+ * // share one undo/redo step.
1636
+ * const sectionBeforeChapter = document.insertSectionBreak(
1637
+ * chapter.getInfo().startOffset,
1638
+ * { nextSectionType: univerAPI.Enum.SectionType.NEXT_PAGE }
1639
+ * );
1640
+ * if (!sectionBeforeChapter) {
1641
+ * throw new Error('The chapter heading is not at a valid top-level offset');
1342
1642
  * }
1643
+ *
1644
+ * console.log({
1645
+ * insertedSection: sectionBeforeChapter.describe(),
1646
+ * chapterSection: document.getSectionAt(chapter.getInfo().startOffset)?.describe(),
1647
+ * });
1343
1648
  * ```
1344
1649
  */
1345
- insertSectionBreak(offset, config = {}) {
1346
- var _this$getBody$section;
1650
+ insertSectionBreak(offset, options = {}) {
1347
1651
  if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== _univerjs_core.DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
1348
- const sectionId = (0, _univerjs_core.createSectionId)(new Set(((_this$getBody$section = this.getBody().sectionBreaks) !== null && _this$getBody$section !== void 0 ? _this$getBody$section : []).map((section) => section.sectionId)));
1652
+ const { nextSectionType, ...config } = options;
1653
+ const sectionId = (0, _univerjs_core.createSectionId)(new Set((this.getBody().sectionBreaks ?? []).map((section) => section.sectionId)));
1349
1654
  return this._commandService.syncExecuteCommand(_univerjs_docs.InsertDocumentSectionBreakCommand.id, {
1350
1655
  unitId: this.getId(),
1351
1656
  offset,
1352
1657
  sectionId,
1353
- config
1354
- }) ? this._injector.createInstance(FDocumentSection, this, sectionId, this._injector) : null;
1658
+ config,
1659
+ nextSectionType
1660
+ }) ? this._injector.createInstance(FDocumentSection, this, sectionId) : null;
1355
1661
  }
1356
1662
  /**
1357
1663
  * Inserts a column-break token in a traditional document.
1358
- * Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
1664
+ * In a single-column section, the traditional renderer advances to the next physical page.
1665
+ * Modern documents must use ColumnGroup. Unspecified documents must resolve
1666
+ * their flavor first. Both throw `DocsSectionUnsupportedDocumentFlavorError`.
1359
1667
  * @example
1360
1668
  * ```ts
1361
1669
  * const fDocument = univerAPI.getActiveDocument();
1362
- * if (fDocument && !fDocument.isModern()) {
1670
+ * if (fDocument?.isTraditional()) {
1363
1671
  * const paragraph = fDocument.findParagraphByText('Continue in next column');
1364
1672
  * const offset = paragraph?.getInfo().startOffset;
1365
1673
  * if (offset != null) {
@@ -1370,7 +1678,10 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1370
1678
  */
1371
1679
  insertColumnBreak(offset) {
1372
1680
  if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== _univerjs_core.DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
1373
- return this.insertText(offset, _univerjs_core.DataStreamTreeTokenType.COLUMN_BREAK);
1681
+ return this._commandService.syncExecuteCommand(_univerjs_docs.InsertDocumentColumnBreakCommand.id, {
1682
+ unitId: this.getId(),
1683
+ offset
1684
+ });
1374
1685
  }
1375
1686
  /**
1376
1687
  * Inserts a horizontal rule using the existing paragraph `borderBottom` mechanism.
@@ -1593,36 +1904,29 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
1593
1904
  return segmentId;
1594
1905
  }
1595
1906
  _getHeaderFooterCreateInfo(kind, pageIndex) {
1596
- var _documentStyle$defaul, _documentStyle$defaul2;
1597
1907
  const { documentStyle } = this._documentDataModel.getSnapshot();
1598
1908
  const isFirstPage = pageIndex === 0;
1599
1909
  const isEvenPage = (pageIndex + 1) % 2 === 0;
1600
- if (isFirstPage && documentStyle.useFirstPageHeaderFooter === _univerjs_core.BooleanNumber.TRUE) {
1601
- var _documentStyle$firstP, _documentStyle$firstP2;
1602
- return kind === "header" ? {
1603
- createType: _univerjs_docs.HeaderFooterType.FIRST_PAGE_HEADER,
1604
- segmentId: (_documentStyle$firstP = documentStyle.firstPageHeaderId) !== null && _documentStyle$firstP !== void 0 ? _documentStyle$firstP : ""
1605
- } : {
1606
- createType: _univerjs_docs.HeaderFooterType.FIRST_PAGE_FOOTER,
1607
- segmentId: (_documentStyle$firstP2 = documentStyle.firstPageFooterId) !== null && _documentStyle$firstP2 !== void 0 ? _documentStyle$firstP2 : ""
1608
- };
1609
- }
1610
- if (isEvenPage && documentStyle.evenAndOddHeaders === _univerjs_core.BooleanNumber.TRUE) {
1611
- var _documentStyle$evenPa, _documentStyle$evenPa2;
1612
- return kind === "header" ? {
1613
- createType: _univerjs_docs.HeaderFooterType.EVEN_PAGE_HEADER,
1614
- segmentId: (_documentStyle$evenPa = documentStyle.evenPageHeaderId) !== null && _documentStyle$evenPa !== void 0 ? _documentStyle$evenPa : ""
1615
- } : {
1616
- createType: _univerjs_docs.HeaderFooterType.EVEN_PAGE_FOOTER,
1617
- segmentId: (_documentStyle$evenPa2 = documentStyle.evenPageFooterId) !== null && _documentStyle$evenPa2 !== void 0 ? _documentStyle$evenPa2 : ""
1618
- };
1619
- }
1910
+ if (isFirstPage && documentStyle.useFirstPageHeaderFooter === _univerjs_core.BooleanNumber.TRUE) return kind === "header" ? {
1911
+ createType: _univerjs_docs.HeaderFooterType.FIRST_PAGE_HEADER,
1912
+ segmentId: documentStyle.firstPageHeaderId ?? ""
1913
+ } : {
1914
+ createType: _univerjs_docs.HeaderFooterType.FIRST_PAGE_FOOTER,
1915
+ segmentId: documentStyle.firstPageFooterId ?? ""
1916
+ };
1917
+ if (isEvenPage && documentStyle.evenAndOddHeaders === _univerjs_core.BooleanNumber.TRUE) return kind === "header" ? {
1918
+ createType: _univerjs_docs.HeaderFooterType.EVEN_PAGE_HEADER,
1919
+ segmentId: documentStyle.evenPageHeaderId ?? ""
1920
+ } : {
1921
+ createType: _univerjs_docs.HeaderFooterType.EVEN_PAGE_FOOTER,
1922
+ segmentId: documentStyle.evenPageFooterId ?? ""
1923
+ };
1620
1924
  return kind === "header" ? {
1621
1925
  createType: _univerjs_docs.HeaderFooterType.DEFAULT_HEADER,
1622
- segmentId: (_documentStyle$defaul = documentStyle.defaultHeaderId) !== null && _documentStyle$defaul !== void 0 ? _documentStyle$defaul : ""
1926
+ segmentId: documentStyle.defaultHeaderId ?? ""
1623
1927
  } : {
1624
1928
  createType: _univerjs_docs.HeaderFooterType.DEFAULT_FOOTER,
1625
- segmentId: (_documentStyle$defaul2 = documentStyle.defaultFooterId) !== null && _documentStyle$defaul2 !== void 0 ? _documentStyle$defaul2 : ""
1929
+ segmentId: documentStyle.defaultFooterId ?? ""
1626
1930
  };
1627
1931
  }
1628
1932
  };
@@ -1671,6 +1975,9 @@ _univerjs_core_facade.FUniver.extend(FUniverDocsMixin);
1671
1975
  * limitations under the License.
1672
1976
  */
1673
1977
  var FDocsEnumMixin = class extends _univerjs_core_facade.FEnum {
1978
+ get DocumentFlavor() {
1979
+ return _univerjs_core.DocumentFlavor;
1980
+ }
1674
1981
  get SectionType() {
1675
1982
  return _univerjs_core.SectionType;
1676
1983
  }
@@ -1689,8 +1996,18 @@ Object.defineProperty(exports, 'FDocument', {
1689
1996
  return FDocument;
1690
1997
  }
1691
1998
  });
1692
- exports.FDocumentParagraph = FDocumentParagraph;
1693
- exports.FDocumentSection = FDocumentSection;
1999
+ Object.defineProperty(exports, 'FDocumentParagraph', {
2000
+ enumerable: true,
2001
+ get: function () {
2002
+ return FDocumentParagraph;
2003
+ }
2004
+ });
2005
+ Object.defineProperty(exports, 'FDocumentSection', {
2006
+ enumerable: true,
2007
+ get: function () {
2008
+ return FDocumentSection;
2009
+ }
2010
+ });
1694
2011
  exports.FDocumentTextRange = FDocumentTextRange;
1695
2012
  exports.isParagraphFacade = isParagraphFacade;
1696
2013
  exports.stripBlockTokens = stripBlockTokens;