@univerjs/docs 1.0.0-alpha.7 → 1.0.0-alpha.8

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/facade.js CHANGED
@@ -1,6 +1,6 @@
1
- import { BooleanNumber, ColumnSeparatorType, DashStyleType, DataStreamTreeTokenType, DocumentFlavor, ICommandService, IResourceLoaderService, IUniverInstanceService, Inject, Injector, JSONX, PresetListType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommand, SectionType, TextX, TextXActionType, Tools, UndoCommand, UniverInstanceType, UpdateDocsAttributeType, createParagraphId, createSectionId, generateRandomId, getParagraphContentStartOffset, getRichTextEditPath, getSectionHeaderFooterReferenceKey, resolveSectionHeaderFooterReference } from "@univerjs/core";
1
+ import { BooleanNumber, ColumnSeparatorType, DashStyleType, DataStreamTreeTokenType, DocumentFlavor, ICommandService, IResourceLoaderService, IUniverInstanceService, Inject, Injector, JSONX, PageOrientType, PresetListType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommand, SectionType, TextX, TextXActionType, Tools, UndoCommand, UniverInstanceType, UpdateDocsAttributeType, createParagraphId, createSectionId, generateRandomId, getParagraphContentStartOffset, getRichTextEditPath, getSectionHeaderFooterReferenceKey, regexp, resolveSectionHeaderFooterReference } from "@univerjs/core";
2
2
  import { FBaseInitialable, FEnum, FUniver } from "@univerjs/core/facade";
3
- import { CreateHeaderFooterCommand, DeleteDocumentSectionBreakCommand, HeaderFooterType, InsertDocumentSectionBreakCommand, RichTextEditingMutation, SetSectionHeaderFooterLinkCommand, UpdateDocumentSectionCommand, createSectionColumnProperties, generateParagraphs, getTopLevelSectionBreaks } from "@univerjs/docs";
3
+ import { CreateHeaderFooterCommand, DeleteDocumentSectionBreakCommand, HeaderFooterType, InsertDocumentColumnBreakCommand, InsertDocumentSectionBreakCommand, RichTextEditingMutation, SetSectionHeaderFooterLinkCommand, UpdateDocumentParagraphStyleCommand, UpdateDocumentSectionCommand, createSectionColumnProperties, generateParagraphs, getEffectiveSectionPageSetup, getSectionContentWidth, getTopLevelSectionBreaks } from "@univerjs/docs";
4
4
 
5
5
  //#region src/facade/utils.ts
6
6
  function cloneParagraphStyle(paragraphStyle) {
@@ -106,8 +106,9 @@ function stripBlockTokens(text) {
106
106
  * that insert or remove content before it.
107
107
  * @hideconstructor
108
108
  */
109
- var FDocumentTextRange = class {
109
+ var FDocumentTextRange = class extends FBaseInitialable {
110
110
  constructor(_document, _startOffset, _endOffset, _segmentId, _injector) {
111
+ super(_injector);
111
112
  this._document = _document;
112
113
  this._startOffset = _startOffset;
113
114
  this._endOffset = _endOffset;
@@ -164,10 +165,6 @@ var FDocumentTextRange = class {
164
165
  };
165
166
  });
166
167
  }
167
- /** @deprecated Use `getExplicitTextStyleRuns()` to distinguish stored styles from effective styles. */
168
- getTextStyleRuns() {
169
- return this.getExplicitTextStyleRuns();
170
- }
171
168
  /**
172
169
  * Returns top-level style properties that have the same explicit value
173
170
  * across the complete range. Unstyled gaps make a property non-common.
@@ -185,10 +182,6 @@ var FDocumentTextRange = class {
185
182
  for (const key of Object.keys(common)) if (rest.some((run) => !isDeepEqual(run.textStyle[key], common[key]))) delete common[key];
186
183
  return common;
187
184
  }
188
- /** @deprecated Use `getCommonExplicitTextStyle()` to distinguish stored styles from effective styles. */
189
- getCommonTextStyle() {
190
- return this.getCommonExplicitTextStyle();
191
- }
192
185
  /**
193
186
  * Returns a serializable summary suitable for an agent/tool response.
194
187
  * @example
@@ -206,9 +199,7 @@ var FDocumentTextRange = class {
206
199
  text: this.getText(),
207
200
  length: this._endOffset - this._startOffset,
208
201
  explicitTextStyleRuns,
209
- commonExplicitTextStyle,
210
- textStyleRuns: explicitTextStyleRuns,
211
- commonTextStyle: commonExplicitTextStyle
202
+ commonExplicitTextStyle
212
203
  };
213
204
  }
214
205
  /**
@@ -275,23 +266,33 @@ function isDeepEqual(left, right) {
275
266
  return JSON.stringify(left) === JSON.stringify(right);
276
267
  }
277
268
 
269
+ //#endregion
270
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorateParam.js
271
+ function __decorateParam(paramIndex, decorator) {
272
+ return function(target, key) {
273
+ decorator(target, key, paramIndex);
274
+ };
275
+ }
276
+
277
+ //#endregion
278
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorate.js
279
+ function __decorate(decorators, target, key, desc) {
280
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
281
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
282
+ 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;
283
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
284
+ }
285
+
278
286
  //#endregion
279
287
  //#region src/facade/f-document-paragraph.ts
280
- /**
281
- * A paragraph facade wrapper.
282
- *
283
- * Paragraph identity is backed by the persisted `paragraphId`. The id is
284
- * re-resolved before each method call, so insertions before this paragraph do
285
- * not break the wrapper.
286
- *
287
- * @hideconstructor
288
- */
289
- var FDocumentParagraph = class {
290
- constructor(_document, _paragraphId, _segmentId = "", _injector) {
288
+ let FDocumentParagraph = class FDocumentParagraph extends FBaseInitialable {
289
+ constructor(_document, _paragraphId, _segmentId = "", _injector, _commandService) {
290
+ super(_injector);
291
291
  this._document = _document;
292
292
  this._paragraphId = _paragraphId;
293
293
  this._segmentId = _segmentId;
294
294
  this._injector = _injector;
295
+ this._commandService = _commandService;
295
296
  }
296
297
  /**
297
298
  * Get the persisted paragraph id.
@@ -382,6 +383,73 @@ var FDocumentParagraph = class {
382
383
  return this._injector.createInstance(FDocumentTextRange, this._document, startOffset, endOffset, this._segmentId, this._injector);
383
384
  }
384
385
  /**
386
+ * Finds one literal text occurrence inside this paragraph.
387
+ *
388
+ * The returned text range is fixed when it is created. Resolve a new range
389
+ * after edits that insert or remove content before the match.
390
+ *
391
+ * @param {string} text Literal text to find. It must not be empty.
392
+ * @param {IFDocumentFindTextOptions} [options] Case sensitivity and zero-based occurrence.
393
+ * @returns {FDocumentTextRange | null} The matching fixed text range, or `null` when no such occurrence exists.
394
+ * @example
395
+ * ```ts
396
+ * const univerAPI = FUniver.newAPI(univer);
397
+ * const document = univerAPI.getActiveDocument();
398
+ * if (!document) throw new Error('No active document');
399
+ *
400
+ * const paragraph = document.findParagraphByText('Launch formula');
401
+ * if (!paragraph) throw new Error('Target paragraph not found');
402
+ *
403
+ * const range = paragraph.findText('formula');
404
+ * if (!range) throw new Error('Target text not found');
405
+ *
406
+ * console.log(range.describe());
407
+ * ```
408
+ */
409
+ findText(text, options = {}) {
410
+ var _options$occurrence, _this$findAllText$occ;
411
+ const occurrence = (_options$occurrence = options.occurrence) !== null && _options$occurrence !== void 0 ? _options$occurrence : 0;
412
+ if (!Number.isInteger(occurrence) || occurrence < 0) throw new RangeError("Text occurrence must be a non-negative integer.");
413
+ return (_this$findAllText$occ = this.findAllText(text, options)[occurrence]) !== null && _this$findAllText$occ !== void 0 ? _this$findAllText$occ : null;
414
+ }
415
+ /**
416
+ * Finds every non-overlapping literal text occurrence inside this paragraph.
417
+ *
418
+ * Results are ordered from the start of the paragraph. The returned ranges
419
+ * are fixed when created; use them immediately and resolve new ranges after
420
+ * edits that change earlier document content.
421
+ *
422
+ * @param {string} text Literal text to find. It must not be empty.
423
+ * @param {Omit<IFDocumentFindTextOptions, 'occurrence'>} [options] Case-sensitivity option.
424
+ * @returns {FDocumentTextRange[]} All matching fixed text ranges, or an empty array when no matches exist.
425
+ * @example
426
+ * ```ts
427
+ * const univerAPI = FUniver.newAPI(univer);
428
+ * const document = univerAPI.getActiveDocument();
429
+ * if (!document) throw new Error('No active document');
430
+ *
431
+ * const paragraph = document.findParagraphByText('x plus x');
432
+ * if (!paragraph) throw new Error('Target paragraph not found');
433
+ *
434
+ * const matches = paragraph.findAllText('x');
435
+ * console.log(matches.map((range) => range.describe()));
436
+ * ```
437
+ */
438
+ findAllText(text, options = {}) {
439
+ var _options$matchCase;
440
+ if (text.length === 0) throw new TypeError("Text to find must not be empty.");
441
+ const matchCase = (_options$matchCase = options.matchCase) !== null && _options$matchCase !== void 0 ? _options$matchCase : true;
442
+ const paragraphText = this.getText();
443
+ const matcher = regexp.createLiteralRegExp(text, matchCase ? "gu" : "giu");
444
+ const { startOffset } = this.getInfo();
445
+ const matches = [];
446
+ for (const match of paragraphText.matchAll(matcher)) {
447
+ const matchStartOffset = startOffset + match.index;
448
+ matches.push(this._injector.createInstance(FDocumentTextRange, this._document, matchStartOffset, matchStartOffset + match[0].length, this._segmentId, this._injector));
449
+ }
450
+ return matches;
451
+ }
452
+ /**
385
453
  * Get this paragraph's plain text.
386
454
  * @returns {string} The paragraph text without the trailing paragraph break.
387
455
  * @example
@@ -433,59 +501,65 @@ var FDocumentParagraph = class {
433
501
  return this._document.insertText(endOffset, text, this._segmentId);
434
502
  }
435
503
  /**
436
- * Apply paragraph style to a paragraph handle or text range.
504
+ * Applies a paragraph and optional text-style patch through one document command.
505
+ *
506
+ * Pagination values use `BooleanNumber.TRUE` or `BooleanNumber.FALSE`; explicit
507
+ * false is preserved and overrides inherited true. The paragraph and text-style
508
+ * changes share one undo/redo item. A stale paragraph handle returns `false`
509
+ * without applying a partial update.
510
+ *
511
+ * The Traditional renderer applies these Word-compatible pagination rules:
512
+ * use `pageBreakBefore` for a hard chapter-page boundary, `keepLines` for a
513
+ * short paragraph that should stay intact, `keepNext` for a heading or caption
514
+ * that should accompany the next paragraph, and `widowControl` for natural
515
+ * multi-line body text. Do not enable every rule on every paragraph. Modern
516
+ * and Unspecified Docs preserve the values in the model but do not apply them
517
+ * to physical pages.
518
+ *
437
519
  * `style.textStyle.fs` is a font size in points (pt), not CSS pixels.
438
520
  * @param {IParagraphStyle} style The Univer paragraph style patch.
439
- * @returns {boolean} `true` if the style was applied.
521
+ * @returns {boolean} `true` when the complete patch was applied; otherwise `false`.
440
522
  * @example
441
523
  * ```ts
442
- * const fDocument = univerAPI.getActiveDocument();
443
- * const paragraph = fDocument.getParagraphs()[0];
444
- * paragraph?.setText('Styled text');
445
- * paragraph?.setStyle({
446
- * textStyle: {
447
- * cl: {
448
- * rgb: '#FF0000',
449
- * },
450
- * fs: 14,
451
- * },
452
- * horizontalAlign: 2,
524
+ * const document = univerAPI.getActiveDocument();
525
+ * if (!document) {
526
+ * throw new Error('No active document');
527
+ * }
528
+ * if (!document.isTraditional()) {
529
+ * throw new Error('Traditional document pagination is required');
530
+ * }
531
+ * const heading = document.findParagraphByText('Appendix');
532
+ * const following = document.findParagraphByText('Supporting details');
533
+ * if (!heading || !following) {
534
+ * throw new Error('Expected paragraphs were not found');
535
+ * }
536
+ *
537
+ * const headingUpdated = heading.setStyle({
538
+ * pageBreakBefore: univerAPI.Enum.BooleanNumber.TRUE,
539
+ * keepLines: univerAPI.Enum.BooleanNumber.TRUE,
540
+ * keepNext: univerAPI.Enum.BooleanNumber.TRUE,
453
541
  * });
454
- * console.log(paragraph?.getInfo().paragraph.paragraphStyle);
542
+ * const followingUpdated = following.setStyle({
543
+ * // Explicit FALSE terminates this authored keepNext chain even if a named
544
+ * // style or document default enables it.
545
+ * keepNext: univerAPI.Enum.BooleanNumber.FALSE,
546
+ * widowControl: univerAPI.Enum.BooleanNumber.TRUE,
547
+ * });
548
+ * if (!headingUpdated || !followingUpdated) {
549
+ * throw new Error('Failed to update paragraph pagination');
550
+ * }
455
551
  * ```
456
552
  */
457
553
  setStyle(style) {
458
- const { paragraph, startOffset, endOffset } = this.getInfo();
459
- let result = true;
460
- if (style.textStyle && startOffset < endOffset) result = retainBodyRange({
554
+ const { startOffset, endOffset } = this.getInfo();
555
+ return this._commandService.syncExecuteCommand(UpdateDocumentParagraphStyleCommand.id, {
556
+ unitId: this._document.getId(),
557
+ segmentId: this._segmentId,
558
+ paragraphId: this._paragraphId,
461
559
  startOffset,
462
560
  endOffset,
463
- segmentId: this._segmentId
464
- }, {
465
- dataStream: "",
466
- textRuns: [{
467
- st: 0,
468
- ed: endOffset - startOffset,
469
- ts: style.textStyle
470
- }]
471
- }, UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
472
- const updateBody = {
473
- dataStream: "",
474
- paragraphs: [{
475
- ...paragraph,
476
- startIndex: 0,
477
- paragraphStyle: {
478
- ...paragraph.paragraphStyle,
479
- ...style
480
- }
481
- }]
482
- };
483
- this._preserveExplicitParagraphIds(updateBody);
484
- return retainBodyRange({
485
- startOffset: endOffset,
486
- endOffset: endOffset + 1,
487
- segmentId: this._segmentId
488
- }, updateBody, UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector) && result;
561
+ style
562
+ });
489
563
  }
490
564
  /**
491
565
  * Check whether this paragraph is a bullet, ordered, or checklist item.
@@ -577,6 +651,7 @@ var FDocumentParagraph = class {
577
651
  body[RESTORE_INSERTED_PARAGRAPH_IDS] = true;
578
652
  }
579
653
  };
654
+ FDocumentParagraph = __decorate([__decorateParam(4, ICommandService)], FDocumentParagraph);
580
655
  function isParagraphFacade(value) {
581
656
  if (typeof value !== "object" || value === null) return false;
582
657
  return typeof value.getId === "function" && typeof value.getSegmentId === "function" && typeof value.getInfo === "function" && typeof value.getRange === "function";
@@ -584,29 +659,30 @@ function isParagraphFacade(value) {
584
659
 
585
660
  //#endregion
586
661
  //#region src/facade/f-document-section.ts
587
- /** Error thrown when traditional section APIs are used to mutate a modern document. */
662
+ function validatePageSetup(pageSetup) {
663
+ const { pageNumberStart, pageSize, pageOrient, marginTop, marginBottom, marginLeft, marginRight } = pageSetup;
664
+ if (pageNumberStart != null && (!Number.isInteger(pageNumberStart) || pageNumberStart < 1)) throw new RangeError("Section page number start must be a positive integer.");
665
+ 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.");
666
+ if (pageOrient != null && !Object.values(PageOrientType).includes(pageOrient)) throw new RangeError("Invalid section page orientation.");
667
+ if ([
668
+ marginTop,
669
+ marginBottom,
670
+ marginLeft,
671
+ marginRight
672
+ ].some((margin) => margin != null && (!Number.isFinite(margin) || margin < 0))) throw new RangeError("Section page margins must be finite and non-negative.");
673
+ }
674
+ /** Error thrown when a Traditional-only section API is used with another document flavor. */
588
675
  var DocsSectionUnsupportedDocumentFlavorError = class extends Error {
589
676
  constructor() {
590
- super("Section column APIs are supported only in traditional documents. Use ColumnGroup APIs for modern documents.");
677
+ super("Section column APIs are supported only in traditional documents. Use ColumnGroup APIs for modern documents, or resolve an unspecified document flavor first.");
591
678
  this.name = "DocsSectionUnsupportedDocumentFlavorError";
592
679
  }
593
680
  };
594
- /**
595
- * Facade wrapper for an OOXML-compatible traditional document section.
596
- * Modern documents use ColumnGroup APIs and cannot mutate this facade.
597
- * @example
598
- * ```ts
599
- * const fDocument = univerAPI.getActiveDocument();
600
- * if (fDocument && !fDocument.isModern()) {
601
- * console.log(fDocument.getSection(0)?.describe());
602
- * }
603
- * ```
604
- */
605
- var FDocumentSection = class {
606
- constructor(_document, _sectionId, _injector) {
681
+ let FDocumentSection = class FDocumentSection {
682
+ constructor(_document, _sectionId, _commandService) {
607
683
  this._document = _document;
608
684
  this._sectionId = _sectionId;
609
- this._injector = _injector;
685
+ this._commandService = _commandService;
610
686
  }
611
687
  /**
612
688
  * Returns the persisted section id.
@@ -639,8 +715,7 @@ var FDocumentSection = class {
639
715
  * ```
640
716
  */
641
717
  getConfig() {
642
- const { sectionBreak } = this._resolve();
643
- return Tools.deepClone(sectionBreak);
718
+ return this._getConfigSnapshot();
644
719
  }
645
720
  /**
646
721
  * Returns the section content range, excluding its terminating section-break token.
@@ -651,17 +726,11 @@ var FDocumentSection = class {
651
726
  * ```
652
727
  */
653
728
  getRange() {
654
- const sectionBreaks = getTopLevelSectionBreaks(this._document.getBody());
655
- const { index, sectionBreak } = this._resolve();
656
- return {
657
- startOffset: index === 0 ? 0 : sectionBreaks[index - 1].startIndex + 1,
658
- endOffset: sectionBreak.startIndex,
659
- segmentId: ""
660
- };
729
+ return this._getRange(this._resolve().index);
661
730
  }
662
731
  /**
663
732
  * Returns the explicit columns. An empty array means the normal single-column layout.
664
- * Column widths and trailing spaces are in points (pt).
733
+ * Column widths and trailing spaces are in 96-DPI layout pixels.
665
734
  * @example
666
735
  * ```ts
667
736
  * const fDocument = univerAPI.getActiveDocument();
@@ -669,8 +738,8 @@ var FDocumentSection = class {
669
738
  * ```
670
739
  */
671
740
  getColumns() {
672
- var _this$getConfig$colum;
673
- return Tools.deepClone((_this$getConfig$colum = this.getConfig().columnProperties) !== null && _this$getConfig$colum !== void 0 ? _this$getConfig$colum : []);
741
+ var _this$_getConfigSnaps;
742
+ return Tools.deepClone((_this$_getConfigSnaps = this._getConfigSnapshot().columnProperties) !== null && _this$_getConfigSnaps !== void 0 ? _this$_getConfigSnaps : []);
674
743
  }
675
744
  /**
676
745
  * Returns a compact serializable section summary.
@@ -682,7 +751,8 @@ var FDocumentSection = class {
682
751
  */
683
752
  describe() {
684
753
  var _config$columnPropert, _config$columnSeparat, _config$sectionType;
685
- const config = this.getConfig();
754
+ const { index } = this._resolve();
755
+ const config = this._getConfigSnapshot();
686
756
  const columns = (_config$columnPropert = config.columnProperties) !== null && _config$columnPropert !== void 0 ? _config$columnPropert : [];
687
757
  const headerFooter = {
688
758
  defaultHeader: this._describeHeaderFooterReference("header", "default"),
@@ -694,8 +764,8 @@ var FDocumentSection = class {
694
764
  };
695
765
  return {
696
766
  sectionId: this._sectionId,
697
- index: this.getIndex(),
698
- range: this.getRange(),
767
+ index,
768
+ range: this._getRange(index),
699
769
  columnCount: columns.length || 1,
700
770
  columns: Tools.deepClone(columns),
701
771
  columnSeparatorType: (_config$columnSeparat = config.columnSeparatorType) !== null && _config$columnSeparat !== void 0 ? _config$columnSeparat : ColumnSeparatorType.NONE,
@@ -707,11 +777,11 @@ var FDocumentSection = class {
707
777
  /**
708
778
  * Sets equal or explicitly sized columns for this traditional section.
709
779
  * Use `columnCount = 1` to restore normal single-column layout.
710
- * `gap` and `widths` are in points (pt).
780
+ * `gap` and `widths` are in 96-DPI layout pixels.
711
781
  * @example
712
782
  * ```ts
713
783
  * const fDocument = univerAPI.getActiveDocument();
714
- * if (fDocument && !fDocument.isModern()) {
784
+ * if (fDocument?.isTraditional()) {
715
785
  * fDocument.getSection(0)?.setColumns(2, { gap: 18, separator: true });
716
786
  * }
717
787
  * ```
@@ -721,22 +791,23 @@ var FDocumentSection = class {
721
791
  this._assertTraditionalDocument();
722
792
  if (!Number.isInteger(columnCount) || columnCount < 1) throw new RangeError("Section column count must be a positive integer.");
723
793
  if (options.widths && options.widths.length !== columnCount) throw new RangeError("Section column widths must match the column count.");
794
+ if (options.gap != null && (!Number.isFinite(options.gap) || options.gap < 0)) throw new RangeError("Section column gap must be finite and non-negative.");
724
795
  const gap = Math.max(0, (_options$gap = options.gap) !== null && _options$gap !== void 0 ? _options$gap : 18);
725
- const config = this.getConfig();
796
+ const config = this._getConfigSnapshot();
726
797
  const columns = createSectionColumnProperties(this._document.getDocumentDataModel().getSnapshot().documentStyle, config, columnCount, gap, options.widths);
727
798
  const separator = typeof options.separator === "boolean" ? options.separator ? ColumnSeparatorType.BETWEEN_EACH_COLUMN : ColumnSeparatorType.NONE : (_options$separator = options.separator) !== null && _options$separator !== void 0 ? _options$separator : ColumnSeparatorType.NONE;
799
+ if (!Object.values(ColumnSeparatorType).includes(separator)) throw new RangeError("Invalid section column separator type.");
728
800
  return this._update({
729
801
  columnProperties: columns,
730
- columnSeparatorType: separator,
731
- ...options.sectionType == null ? {} : { sectionType: options.sectionType }
802
+ columnSeparatorType: separator
732
803
  });
733
804
  }
734
805
  /**
735
- * Sets explicit OOXML-compatible column width and trailing-space values in points (pt).
806
+ * Sets explicit OOXML-compatible column width and trailing-space values in 96-DPI layout pixels.
736
807
  * @example
737
808
  * ```ts
738
809
  * const fDocument = univerAPI.getActiveDocument();
739
- * if (fDocument && !fDocument.isModern()) {
810
+ * if (fDocument?.isTraditional()) {
740
811
  * fDocument.getSection(0)?.setColumnProperties([
741
812
  * { width: 240, paddingEnd: 18 },
742
813
  * { width: 240, paddingEnd: 0 },
@@ -746,32 +817,163 @@ var FDocumentSection = class {
746
817
  */
747
818
  setColumnProperties(columns, separator = ColumnSeparatorType.NONE) {
748
819
  this._assertTraditionalDocument();
749
- if (columns.some(({ width, paddingEnd }) => width < 0 || paddingEnd < 0)) throw new RangeError("Section column widths and padding must be non-negative.");
820
+ if (!Object.values(ColumnSeparatorType).includes(separator)) throw new RangeError("Invalid section column separator type.");
821
+ 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.");
822
+ const contentWidth = getSectionContentWidth(this._document.getDocumentDataModel().getSnapshot().documentStyle, this._getConfigSnapshot());
823
+ if (columns.reduce((sum, { width, paddingEnd }) => sum + width + paddingEnd, 0) > contentWidth) throw new RangeError("Section columns exceed the available page content width.");
750
824
  return this._update({
751
825
  columnProperties: Tools.deepClone(columns),
752
826
  columnSeparatorType: separator
753
827
  });
754
828
  }
755
829
  /**
756
- * Sets how the next section begins.
830
+ * Sets how this section begins relative to the previous section.
831
+ *
832
+ * The first section has no preceding boundary, so setting its type does not
833
+ * create an initial blank page. Prefer `FDocument.insertSectionBreak` with
834
+ * `nextSectionType` when creating a new boundary; use this method when
835
+ * updating an existing section after resolving it again from the document.
836
+ *
837
+ * @param {SectionType} sectionType How this section begins.
838
+ * @returns {boolean} `true` when the section command was applied.
757
839
  * @example
758
840
  * ```ts
759
- * const fDocument = univerAPI.getActiveDocument();
760
- * if (fDocument && !fDocument.isModern()) {
761
- * fDocument.getSection(0)?.setSectionType(univerAPI.Enum.SectionType.NEXT_PAGE);
841
+ * const document = univerAPI.getActiveDocument();
842
+ * if (!document?.isTraditional()) {
843
+ * throw new Error('A Traditional document is required');
844
+ * }
845
+ *
846
+ * const secondSection = document.getSection(1);
847
+ * if (!secondSection) {
848
+ * throw new Error('The second section does not exist');
849
+ * }
850
+ * if (!secondSection.setSectionType(univerAPI.Enum.SectionType.NEXT_PAGE)) {
851
+ * throw new Error('Failed to update the second section');
762
852
  * }
763
853
  * ```
764
854
  */
765
855
  setSectionType(sectionType) {
766
856
  this._assertTraditionalDocument();
857
+ if (!Object.values(SectionType).includes(sectionType)) throw new RangeError("Invalid section type.");
767
858
  return this._update({ sectionType });
768
859
  }
769
860
  /**
861
+ * Returns this section's explicit page setup overrides.
862
+ * Missing values inherit from the document style. Geometry values use 96-DPI layout pixels.
863
+ *
864
+ * Use `getEffectivePageSetup()` when an agent needs resolved page and content
865
+ * dimensions rather than only the overrides stored on this section.
866
+ *
867
+ * @returns {FDocumentSectionPageSetup} A cloned object containing only explicit section overrides.
868
+ * @example
869
+ * ```ts
870
+ * const document = univerAPI.getActiveDocument();
871
+ * const section = document?.getSection(0);
872
+ * console.log(section?.getPageSetup());
873
+ * ```
874
+ */
875
+ getPageSetup() {
876
+ const { pageNumberStart, pageSize, pageOrient, marginTop, marginBottom, marginLeft, marginRight } = this._getConfigSnapshot();
877
+ return Tools.deepClone({
878
+ pageNumberStart,
879
+ pageSize,
880
+ pageOrient,
881
+ marginTop,
882
+ marginBottom,
883
+ marginLeft,
884
+ marginRight
885
+ });
886
+ }
887
+ /**
888
+ * Returns nominal page geometry after resolving this section's overrides
889
+ * against document defaults. All geometry values use 96-DPI layout pixels.
890
+ *
891
+ * This synchronous model-only API works without `engine-render`. It does not
892
+ * report physical page count, remaining page space, or final coordinates.
893
+ *
894
+ * @returns {IEffectiveSectionPageSetup} A cloned, serializable page setup.
895
+ * @example
896
+ * ```ts
897
+ * const document = univerAPI.getActiveDocument();
898
+ * if (!document) {
899
+ * throw new Error('No active document');
900
+ * }
901
+ * if (!document.isTraditional()) {
902
+ * throw new Error('Traditional document sections are required');
903
+ * }
904
+ *
905
+ * const section = document.getSection(0);
906
+ * if (!section) {
907
+ * throw new Error('The document has no traditional section');
908
+ * }
909
+ *
910
+ * const layout = section.getEffectivePageSetup();
911
+ * console.log({
912
+ * pageWidth: layout.pageSize.width,
913
+ * pageHeight: layout.pageSize.height,
914
+ * contentWidth: layout.contentSize.width,
915
+ * contentHeight: layout.contentSize.height,
916
+ * margins: layout.margins,
917
+ * });
918
+ * ```
919
+ */
920
+ getEffectivePageSetup() {
921
+ this._assertTraditionalDocument();
922
+ const documentStyle = this._document.getDocumentDataModel().getSnapshot().documentStyle;
923
+ return Tools.deepClone(getEffectiveSectionPageSetup(documentStyle, this._getConfigSnapshot()));
924
+ }
925
+ /**
926
+ * Updates this section's page setup through the document section command.
927
+ * Geometry values use 96-DPI layout pixels.
928
+ *
929
+ * This method changes static page geometry; it does not choose where the
930
+ * section begins. Use `setSectionType()` for an existing boundary, or
931
+ * `insertSectionBreak(..., { nextSectionType })` while creating one.
932
+ *
933
+ * @param {FDocumentSectionPageSetup} pageSetup Explicit section overrides to patch.
934
+ * @returns {boolean} `true` when the section command was applied.
935
+ * @example
936
+ * ```ts
937
+ * const document = univerAPI.getActiveDocument();
938
+ * if (!document?.isTraditional()) {
939
+ * throw new Error('A Traditional document is required');
940
+ * }
941
+ *
942
+ * const section = document.getSection(1);
943
+ * if (!section) {
944
+ * throw new Error('The second section does not exist');
945
+ * }
946
+ * const updated = section.setPageSetup({
947
+ * pageSize: { width: 816, height: 1056 },
948
+ * marginTop: 96,
949
+ * marginBottom: 96,
950
+ * marginLeft: 96,
951
+ * marginRight: 96,
952
+ * });
953
+ * if (!updated) {
954
+ * throw new Error('Failed to update section page setup');
955
+ * }
956
+ * console.log(section.getEffectivePageSetup());
957
+ * ```
958
+ */
959
+ setPageSetup(pageSetup) {
960
+ this._assertTraditionalDocument();
961
+ validatePageSetup(pageSetup);
962
+ const definedPageSetup = Tools.deepClone(pageSetup);
963
+ Tools.removeNull(definedPageSetup);
964
+ const documentStyle = this._document.getDocumentDataModel().getSnapshot().documentStyle;
965
+ getEffectiveSectionPageSetup(documentStyle, {
966
+ ...this._getConfigSnapshot(),
967
+ ...definedPageSetup
968
+ });
969
+ return this._update(definedPageSetup);
970
+ }
971
+ /**
770
972
  * Ensures a header segment linked specifically to this section.
771
973
  * @example
772
974
  * ```ts
773
975
  * const fDocument = univerAPI.getActiveDocument();
774
- * if (fDocument && !fDocument.isModern()) {
976
+ * if (fDocument?.isTraditional()) {
775
977
  * const segmentId = fDocument.getSection(0)?.ensureHeader();
776
978
  * if (segmentId) {
777
979
  * fDocument.insertText(0, 'Quarterly report', segmentId);
@@ -787,7 +989,7 @@ var FDocumentSection = class {
787
989
  * @example
788
990
  * ```ts
789
991
  * const fDocument = univerAPI.getActiveDocument();
790
- * if (fDocument && !fDocument.isModern()) {
992
+ * if (fDocument?.isTraditional()) {
791
993
  * const segmentId = fDocument.getSection(0)?.ensureFooter('first');
792
994
  * if (segmentId) {
793
995
  * fDocument.insertText(0, 'Confidential', segmentId);
@@ -849,7 +1051,7 @@ var FDocumentSection = class {
849
1051
  * @example
850
1052
  * ```ts
851
1053
  * const fDocument = univerAPI.getActiveDocument();
852
- * if (fDocument && !fDocument.isModern()) {
1054
+ * if (fDocument?.isTraditional()) {
853
1055
  * fDocument.getSection(1)?.setHeaderLinkedToPrevious(false, 'default');
854
1056
  * }
855
1057
  * ```
@@ -862,7 +1064,7 @@ var FDocumentSection = class {
862
1064
  * @example
863
1065
  * ```ts
864
1066
  * const fDocument = univerAPI.getActiveDocument();
865
- * if (fDocument && !fDocument.isModern()) {
1067
+ * if (fDocument?.isTraditional()) {
866
1068
  * fDocument.getSection(1)?.setFooterLinkedToPrevious(true, 'even');
867
1069
  * }
868
1070
  * ```
@@ -872,11 +1074,11 @@ var FDocumentSection = class {
872
1074
  }
873
1075
  /**
874
1076
  * Updates header/footer switches and margins on this section break.
875
- * `marginHeader` and `marginFooter` are in points (pt).
1077
+ * `marginHeader` and `marginFooter` are in 96-DPI layout pixels.
876
1078
  * @example
877
1079
  * ```ts
878
1080
  * const fDocument = univerAPI.getActiveDocument();
879
- * if (fDocument && !fDocument.isModern()) {
1081
+ * if (fDocument?.isTraditional()) {
880
1082
  * fDocument.getSection(0)?.setHeaderFooterOptions({
881
1083
  * marginHeader: 36,
882
1084
  * marginFooter: 36,
@@ -894,7 +1096,7 @@ var FDocumentSection = class {
894
1096
  * @example
895
1097
  * ```ts
896
1098
  * const fDocument = univerAPI.getActiveDocument();
897
- * if (fDocument && !fDocument.isModern()) {
1099
+ * if (fDocument?.isTraditional()) {
898
1100
  * const sections = fDocument.getSections();
899
1101
  * if (sections.length > 1) {
900
1102
  * sections[0].remove();
@@ -904,14 +1106,14 @@ var FDocumentSection = class {
904
1106
  */
905
1107
  remove() {
906
1108
  this._assertTraditionalDocument();
907
- return this._injector.get(ICommandService).syncExecuteCommand(DeleteDocumentSectionBreakCommand.id, {
1109
+ return this._commandService.syncExecuteCommand(DeleteDocumentSectionBreakCommand.id, {
908
1110
  unitId: this._document.getId(),
909
1111
  sectionId: this._sectionId
910
1112
  });
911
1113
  }
912
1114
  _update(patch) {
913
1115
  const { sectionId: _sectionId, startIndex: _startIndex, ...config } = patch;
914
- return this._injector.get(ICommandService).syncExecuteCommand(UpdateDocumentSectionCommand.id, {
1116
+ return this._commandService.syncExecuteCommand(UpdateDocumentSectionCommand.id, {
915
1117
  unitId: this._document.getId(),
916
1118
  updates: [{
917
1119
  sectionId: this._sectionId,
@@ -922,11 +1124,11 @@ var FDocumentSection = class {
922
1124
  _ensureHeaderFooter(kind, variant) {
923
1125
  this._assertTraditionalDocument();
924
1126
  const { index } = this._resolve();
925
- const existing = this.getConfig()[getSectionHeaderFooterReferenceKey(kind, variant)];
1127
+ const existing = this._getConfigSnapshot()[getSectionHeaderFooterReferenceKey(kind, variant)];
926
1128
  if (typeof existing === "string" && existing) return existing;
927
1129
  if (index > 0) {
928
1130
  const segmentId = generateRandomId(6);
929
- if (!this._injector.get(ICommandService).syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
1131
+ if (!this._commandService.syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
930
1132
  unitId: this._document.getId(),
931
1133
  sectionId: this._sectionId,
932
1134
  kind,
@@ -942,7 +1144,7 @@ var FDocumentSection = class {
942
1144
  even: kind === "header" ? HeaderFooterType.EVEN_PAGE_HEADER : HeaderFooterType.EVEN_PAGE_FOOTER
943
1145
  };
944
1146
  const segmentId = generateRandomId(6);
945
- if (!this._injector.get(ICommandService).syncExecuteCommand(CreateHeaderFooterCommand.id, {
1147
+ if (!this._commandService.syncExecuteCommand(CreateHeaderFooterCommand.id, {
946
1148
  unitId: this._document.getId(),
947
1149
  segmentId,
948
1150
  createType: types[variant],
@@ -964,7 +1166,7 @@ var FDocumentSection = class {
964
1166
  }
965
1167
  _setHeaderFooterLinkedToPrevious(kind, variant, linkedToPrevious) {
966
1168
  this._assertTraditionalDocument();
967
- return this._injector.get(ICommandService).syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
1169
+ return this._commandService.syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
968
1170
  unitId: this._document.getId(),
969
1171
  sectionId: this._sectionId,
970
1172
  kind,
@@ -976,6 +1178,17 @@ var FDocumentSection = class {
976
1178
  _assertTraditionalDocument() {
977
1179
  if (this._document.getDocumentDataModel().getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
978
1180
  }
1181
+ _getConfigSnapshot() {
1182
+ return Tools.deepClone(this._resolve().sectionBreak);
1183
+ }
1184
+ _getRange(index) {
1185
+ const sectionBreaks = getTopLevelSectionBreaks(this._document.getBody());
1186
+ return {
1187
+ startOffset: index === 0 ? 0 : sectionBreaks[index - 1].startIndex + 1,
1188
+ endOffset: sectionBreaks[index].startIndex,
1189
+ segmentId: ""
1190
+ };
1191
+ }
979
1192
  _resolve() {
980
1193
  this._assertTraditionalDocument();
981
1194
  const sectionBreaks = getTopLevelSectionBreaks(this._document.getBody());
@@ -987,9 +1200,10 @@ var FDocumentSection = class {
987
1200
  };
988
1201
  }
989
1202
  };
1203
+ FDocumentSection = __decorate([__decorateParam(2, ICommandService)], FDocumentSection);
990
1204
 
991
1205
  //#endregion
992
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
1206
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/typeof.js
993
1207
  function _typeof(o) {
994
1208
  "@babel/helpers - typeof";
995
1209
  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
@@ -1000,7 +1214,7 @@ function _typeof(o) {
1000
1214
  }
1001
1215
 
1002
1216
  //#endregion
1003
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPrimitive.js
1217
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPrimitive.js
1004
1218
  function toPrimitive(t, r) {
1005
1219
  if ("object" != _typeof(t) || !t) return t;
1006
1220
  var e = t[Symbol.toPrimitive];
@@ -1013,14 +1227,14 @@ function toPrimitive(t, r) {
1013
1227
  }
1014
1228
 
1015
1229
  //#endregion
1016
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
1230
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPropertyKey.js
1017
1231
  function toPropertyKey(t) {
1018
1232
  var i = toPrimitive(t, "string");
1019
1233
  return "symbol" == _typeof(i) ? i : i + "";
1020
1234
  }
1021
1235
 
1022
1236
  //#endregion
1023
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
1237
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/defineProperty.js
1024
1238
  function _defineProperty(e, r, t) {
1025
1239
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
1026
1240
  value: t,
@@ -1030,23 +1244,6 @@ function _defineProperty(e, r, t) {
1030
1244
  }) : e[r] = t, e;
1031
1245
  }
1032
1246
 
1033
- //#endregion
1034
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorateParam.js
1035
- function __decorateParam(paramIndex, decorator) {
1036
- return function(target, key) {
1037
- decorator(target, key, paramIndex);
1038
- };
1039
- }
1040
-
1041
- //#endregion
1042
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorate.js
1043
- function __decorate(decorators, target, key, desc) {
1044
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1045
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1046
- 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;
1047
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1048
- }
1049
-
1050
1247
  //#endregion
1051
1248
  //#region src/facade/f-document.ts
1052
1249
  let FDocument = class FDocument extends FBaseInitialable {
@@ -1127,16 +1324,73 @@ let FDocument = class FDocument extends FBaseInitialable {
1127
1324
  return this._documentDataModel.getTitle() || "";
1128
1325
  }
1129
1326
  /**
1130
- * Whether the document is a modern document or not.
1131
- * @returns {boolean} `true` if the document is a modern document, or `false` if it is not.
1327
+ * Returns the document's explicit layout flavor.
1328
+ *
1329
+ * Use this method when all three states matter. Do not infer a Traditional
1330
+ * document from `!isModern()`: that expression is also true for
1331
+ * `DocumentFlavor.UNSPECIFIED`.
1332
+ *
1333
+ * @returns {DocumentFlavor} `TRADITIONAL`, `MODERN`, or `UNSPECIFIED`.
1334
+ * @example
1335
+ * ```typescript
1336
+ * const document = univerAPI.getActiveDocument();
1337
+ * if (!document) {
1338
+ * throw new Error('No active document');
1339
+ * }
1340
+ *
1341
+ * switch (document.getDocumentFlavor()) {
1342
+ * case univerAPI.Enum.DocumentFlavor.TRADITIONAL:
1343
+ * console.log('Word-compatible physical pagination is available');
1344
+ * break;
1345
+ * case univerAPI.Enum.DocumentFlavor.MODERN:
1346
+ * console.log('Use Modern Doc layout APIs such as ColumnGroup');
1347
+ * break;
1348
+ * default:
1349
+ * console.log('Resolve the unspecified flavor before using flavor-specific APIs');
1350
+ * }
1351
+ * ```
1352
+ */
1353
+ getDocumentFlavor() {
1354
+ return this._resolveDocumentFlavor();
1355
+ }
1356
+ /**
1357
+ * Whether this is a Traditional document with Word-compatible physical pagination.
1358
+ *
1359
+ * Prefer this positive guard before calling section, column-break, page-setup,
1360
+ * or paragraph-pagination APIs.
1361
+ *
1362
+ * @returns {boolean} `true` only for `DocumentFlavor.TRADITIONAL`.
1363
+ * @example
1364
+ * ```typescript
1365
+ * const document = univerAPI.getActiveDocument();
1366
+ * if (document?.isTraditional()) {
1367
+ * console.log(document.getSection(0)?.getEffectivePageSetup());
1368
+ * }
1369
+ * ```
1370
+ */
1371
+ isTraditional() {
1372
+ return this._resolveDocumentFlavor() === DocumentFlavor.TRADITIONAL;
1373
+ }
1374
+ /**
1375
+ * Whether this is a Modern document.
1376
+ *
1377
+ * A `false` result can mean either Traditional or Unspecified. Use
1378
+ * `isTraditional()` before Traditional-only APIs, or `getDocumentFlavor()`
1379
+ * when all three states matter.
1380
+ *
1381
+ * @returns {boolean} `true` only for `DocumentFlavor.MODERN`.
1132
1382
  * @example
1133
1383
  * ```typescript
1134
1384
  * const fDocument = univerAPI.getActiveDocument();
1135
- * console.log(fDocument.isModern());
1385
+ * console.log(fDocument?.isModern());
1136
1386
  * ```
1137
1387
  */
1138
1388
  isModern() {
1139
- return this._documentDataModel.getSnapshot().documentStyle.documentFlavor === DocumentFlavor.MODERN;
1389
+ return this._resolveDocumentFlavor() === DocumentFlavor.MODERN;
1390
+ }
1391
+ _resolveDocumentFlavor() {
1392
+ var _this$_documentDataMo2;
1393
+ return (_this$_documentDataMo2 = this._documentDataModel.getSnapshot().documentStyle.documentFlavor) !== null && _this$_documentDataMo2 !== void 0 ? _this$_documentDataMo2 : DocumentFlavor.UNSPECIFIED;
1140
1394
  }
1141
1395
  /**
1142
1396
  * Save the document snapshot data, including the document content and resource data, etc.
@@ -1230,7 +1484,7 @@ let FDocument = class FDocument extends FBaseInitialable {
1230
1484
  }, buildPlainTextInsertBody(text), this._documentDataModel, this._injector);
1231
1485
  }
1232
1486
  /**
1233
- * Returns document-level header/footer switches and margins. Margin values are in points (pt).
1487
+ * Returns document-level header/footer switches and margins. Margin values use 96-DPI layout pixels.
1234
1488
  * @example
1235
1489
  * ```ts
1236
1490
  * const fDocument = univerAPI.getActiveDocument();
@@ -1247,12 +1501,18 @@ let FDocument = class FDocument extends FBaseInitialable {
1247
1501
  };
1248
1502
  }
1249
1503
  /**
1250
- * Updates document-level header/footer switches and margins in a traditional document.
1251
- * `marginHeader` and `marginFooter` are in points (pt).
1504
+ * Updates document-level header/footer switches and margins.
1505
+ *
1506
+ * Traditional and Unspecified documents keep the legacy header/footer
1507
+ * behavior. Modern documents reject this API. `marginHeader` and
1508
+ * `marginFooter` use 96-DPI layout pixels.
1252
1509
  * @example
1253
1510
  * ```ts
1254
1511
  * const fDocument = univerAPI.getActiveDocument();
1255
- * if (fDocument && !fDocument.isModern()) {
1512
+ * if (
1513
+ * fDocument &&
1514
+ * fDocument.getDocumentFlavor() !== univerAPI.Enum.DocumentFlavor.MODERN
1515
+ * ) {
1256
1516
  * fDocument.setHeaderFooterOptions({ marginHeader: 36, marginFooter: 36 });
1257
1517
  * }
1258
1518
  * ```
@@ -1293,7 +1553,7 @@ let FDocument = class FDocument extends FBaseInitialable {
1293
1553
  */
1294
1554
  getSections() {
1295
1555
  if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) return [];
1296
- return getTopLevelSectionBreaks(this.getBody()).map((sectionBreak) => this._injector.createInstance(FDocumentSection, this, sectionBreak.sectionId, this._injector));
1556
+ return getTopLevelSectionBreaks(this.getBody()).map((sectionBreak) => this._injector.createInstance(FDocumentSection, this, sectionBreak.sectionId));
1297
1557
  }
1298
1558
  /**
1299
1559
  * Returns a traditional section by zero-based index, or `null` in modern documents.
@@ -1323,42 +1583,83 @@ let FDocument = class FDocument extends FBaseInitialable {
1323
1583
  var _this$getSections$fin;
1324
1584
  return (_this$getSections$fin = this.getSections().find((section) => {
1325
1585
  const range = section.getRange();
1326
- return offset >= range.startOffset && offset <= range.endOffset;
1586
+ return offset >= range.startOffset && offset < range.endOffset;
1327
1587
  })) !== null && _this$getSections$fin !== void 0 ? _this$getSections$fin : null;
1328
1588
  }
1329
1589
  /**
1330
1590
  * Inserts a traditional document section break and returns its stable facade.
1331
- * Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
1332
- * Numeric layout values in `config` are in points (pt).
1591
+ *
1592
+ * `options` configures the section created before the inserted break.
1593
+ * Set `options.nextSectionType` to control how the existing section after the
1594
+ * break begins. For example, use `SectionType.NEXT_PAGE` to start a chapter on
1595
+ * a new physical page. Both changes are executed by one command and are
1596
+ * undone or redone together.
1597
+ *
1598
+ * The offset must be a top-level document position. To insert a break before
1599
+ * a table or block such as a callout, use that object's start offset instead
1600
+ * of an offset inside the object.
1601
+ *
1602
+ * Modern documents must use ColumnGroup. Unspecified documents must resolve
1603
+ * their flavor first. Both throw `DocsSectionUnsupportedDocumentFlavorError`.
1604
+ * Numeric layout values in `options` are in 96-DPI layout pixels.
1605
+ *
1606
+ * @param {number} offset Top-level data-stream offset where the section break is inserted.
1607
+ * @param {IFDocumentInsertSectionBreakOptions} [options] Section properties and the optional type of the following section.
1608
+ * @returns {FDocumentSection | null} The section created before the break, or `null` when the command rejects the insertion.
1333
1609
  * @example
1334
1610
  * ```ts
1335
- * const fDocument = univerAPI.getActiveDocument();
1336
- * if (fDocument && !fDocument.isModern()) {
1337
- * const paragraph = fDocument.findParagraphByText('Appendix');
1338
- * const offset = paragraph?.getInfo().startOffset;
1339
- * const section = offset == null ? null : fDocument.insertSectionBreak(offset);
1340
- * console.log(section?.getId());
1611
+ * const document = univerAPI.getActiveDocument();
1612
+ * if (!document) {
1613
+ * throw new Error('No active document');
1614
+ * }
1615
+ * if (!document.isTraditional()) {
1616
+ * throw new Error('Traditional document sections are required');
1617
+ * }
1618
+ *
1619
+ * const chapter = document.findParagraphByText('Chapter 2');
1620
+ * if (!chapter) {
1621
+ * throw new Error('Chapter heading not found');
1622
+ * }
1623
+ *
1624
+ * // Insert the boundary immediately before the chapter heading. The command
1625
+ * // also marks the following section as NEXT_PAGE, so the two model changes
1626
+ * // share one undo/redo step.
1627
+ * const sectionBeforeChapter = document.insertSectionBreak(
1628
+ * chapter.getInfo().startOffset,
1629
+ * { nextSectionType: univerAPI.Enum.SectionType.NEXT_PAGE }
1630
+ * );
1631
+ * if (!sectionBeforeChapter) {
1632
+ * throw new Error('The chapter heading is not at a valid top-level offset');
1341
1633
  * }
1634
+ *
1635
+ * console.log({
1636
+ * insertedSection: sectionBeforeChapter.describe(),
1637
+ * chapterSection: document.getSectionAt(chapter.getInfo().startOffset)?.describe(),
1638
+ * });
1342
1639
  * ```
1343
1640
  */
1344
- insertSectionBreak(offset, config = {}) {
1641
+ insertSectionBreak(offset, options = {}) {
1345
1642
  var _this$getBody$section;
1346
1643
  if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
1644
+ const { nextSectionType, ...config } = options;
1347
1645
  const sectionId = createSectionId(new Set(((_this$getBody$section = this.getBody().sectionBreaks) !== null && _this$getBody$section !== void 0 ? _this$getBody$section : []).map((section) => section.sectionId)));
1348
1646
  return this._commandService.syncExecuteCommand(InsertDocumentSectionBreakCommand.id, {
1349
1647
  unitId: this.getId(),
1350
1648
  offset,
1351
1649
  sectionId,
1352
- config
1353
- }) ? this._injector.createInstance(FDocumentSection, this, sectionId, this._injector) : null;
1650
+ config,
1651
+ nextSectionType
1652
+ }) ? this._injector.createInstance(FDocumentSection, this, sectionId) : null;
1354
1653
  }
1355
1654
  /**
1356
1655
  * Inserts a column-break token in a traditional document.
1357
- * Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
1656
+ * In a single-column section, the traditional renderer advances to the next physical page.
1657
+ * Modern documents must use ColumnGroup. Unspecified documents must resolve
1658
+ * their flavor first. Both throw `DocsSectionUnsupportedDocumentFlavorError`.
1358
1659
  * @example
1359
1660
  * ```ts
1360
1661
  * const fDocument = univerAPI.getActiveDocument();
1361
- * if (fDocument && !fDocument.isModern()) {
1662
+ * if (fDocument?.isTraditional()) {
1362
1663
  * const paragraph = fDocument.findParagraphByText('Continue in next column');
1363
1664
  * const offset = paragraph?.getInfo().startOffset;
1364
1665
  * if (offset != null) {
@@ -1369,7 +1670,10 @@ let FDocument = class FDocument extends FBaseInitialable {
1369
1670
  */
1370
1671
  insertColumnBreak(offset) {
1371
1672
  if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
1372
- return this.insertText(offset, DataStreamTreeTokenType.COLUMN_BREAK);
1673
+ return this._commandService.syncExecuteCommand(InsertDocumentColumnBreakCommand.id, {
1674
+ unitId: this.getId(),
1675
+ offset
1676
+ });
1373
1677
  }
1374
1678
  /**
1375
1679
  * Inserts a horizontal rule using the existing paragraph `borderBottom` mechanism.
@@ -1670,6 +1974,9 @@ FUniver.extend(FUniverDocsMixin);
1670
1974
  * limitations under the License.
1671
1975
  */
1672
1976
  var FDocsEnumMixin = class extends FEnum {
1977
+ get DocumentFlavor() {
1978
+ return DocumentFlavor;
1979
+ }
1673
1980
  get SectionType() {
1674
1981
  return SectionType;
1675
1982
  }