@univerjs/docs 1.0.0-alpha.2 → 1.0.0-alpha.3

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
@@ -98,6 +98,184 @@ function stripBlockTokens(text) {
98
98
  return Array.from(text).map((char) => char === _univerjs_core.DataStreamTreeTokenType.PARAGRAPH ? "\n" : char).filter((char) => char !== _univerjs_core.DataStreamTreeTokenType.BLOCK_START && char !== _univerjs_core.DataStreamTreeTokenType.BLOCK_END && char !== _univerjs_core.DataStreamTreeTokenType.SECTION_BREAK).join("").replace(/\n$/, "");
99
99
  }
100
100
 
101
+ //#endregion
102
+ //#region src/facade/f-document-text-range.ts
103
+ /**
104
+ * Facade wrapper for reading and styling a fixed document text range.
105
+ *
106
+ * Offsets are fixed when the wrapper is created. Create a new range after edits
107
+ * that insert or remove content before it.
108
+ * @hideconstructor
109
+ */
110
+ var FDocumentTextRange = class {
111
+ constructor(_document, _startOffset, _endOffset, _segmentId, _injector) {
112
+ this._document = _document;
113
+ this._startOffset = _startOffset;
114
+ this._endOffset = _endOffset;
115
+ this._segmentId = _segmentId;
116
+ this._injector = _injector;
117
+ this._validateRange();
118
+ }
119
+ /**
120
+ * Returns the serializable document range.
121
+ * @example
122
+ * ```ts
123
+ * const fDocument = univerAPI.getActiveDocument();
124
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
125
+ * console.log(range?.getRange());
126
+ * ```
127
+ */
128
+ getRange() {
129
+ return {
130
+ startOffset: this._startOffset,
131
+ endOffset: this._endOffset,
132
+ segmentId: this._segmentId
133
+ };
134
+ }
135
+ /**
136
+ * Returns the plain data-stream text in this range.
137
+ * @example
138
+ * ```ts
139
+ * const fDocument = univerAPI.getActiveDocument();
140
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
141
+ * console.log(range?.getText());
142
+ * ```
143
+ */
144
+ getText() {
145
+ return this._document.getBody(this._segmentId).dataStream.slice(this._startOffset, this._endOffset);
146
+ }
147
+ /**
148
+ * Returns explicit text-style runs intersecting this range.
149
+ * Returned offsets are clipped to the range and remain document-relative.
150
+ * @example
151
+ * ```ts
152
+ * const fDocument = univerAPI.getActiveDocument();
153
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
154
+ * console.log(range?.getExplicitTextStyleRuns());
155
+ * ```
156
+ */
157
+ getExplicitTextStyleRuns() {
158
+ 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();
171
+ }
172
+ /**
173
+ * Returns top-level style properties that have the same explicit value
174
+ * across the complete range. Unstyled gaps make a property non-common.
175
+ * @example
176
+ * ```ts
177
+ * const fDocument = univerAPI.getActiveDocument();
178
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
179
+ * console.log(range?.getCommonExplicitTextStyle());
180
+ * ```
181
+ */
182
+ getCommonExplicitTextStyle() {
183
+ if (this._startOffset === this._endOffset) return {};
184
+ const [first, ...rest] = this._getStyleSegments();
185
+ const common = _univerjs_core.Tools.deepClone(first.textStyle);
186
+ for (const key of Object.keys(common)) if (rest.some((run) => !isDeepEqual(run.textStyle[key], common[key]))) delete common[key];
187
+ return common;
188
+ }
189
+ /** @deprecated Use `getCommonExplicitTextStyle()` to distinguish stored styles from effective styles. */
190
+ getCommonTextStyle() {
191
+ return this.getCommonExplicitTextStyle();
192
+ }
193
+ /**
194
+ * Returns a serializable summary suitable for an agent/tool response.
195
+ * @example
196
+ * ```ts
197
+ * const fDocument = univerAPI.getActiveDocument();
198
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
199
+ * console.log(range?.describe());
200
+ * ```
201
+ */
202
+ describe() {
203
+ const explicitTextStyleRuns = this.getExplicitTextStyleRuns();
204
+ const commonExplicitTextStyle = this.getCommonExplicitTextStyle();
205
+ return {
206
+ ...this.getRange(),
207
+ text: this.getText(),
208
+ length: this._endOffset - this._startOffset,
209
+ explicitTextStyleRuns,
210
+ commonExplicitTextStyle,
211
+ textStyleRuns: explicitTextStyleRuns,
212
+ commonTextStyle: commonExplicitTextStyle
213
+ };
214
+ }
215
+ /**
216
+ * Merges a text-style patch into every character in the range.
217
+ * Existing text-run splitting, merging, and normalization are handled by
218
+ * the document mutation pipeline.
219
+ * `style.fs` is a font size in points (pt), not CSS pixels.
220
+ * @example
221
+ * ```ts
222
+ * const fDocument = univerAPI.getActiveDocument();
223
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
224
+ * range?.setTextStyle({ fs: 10.5, bl: univerAPI.Enum.BooleanNumber.TRUE });
225
+ * ```
226
+ */
227
+ setTextStyle(style) {
228
+ if (this._startOffset === this._endOffset) return false;
229
+ return retainBodyRange(this.getRange(), {
230
+ dataStream: "",
231
+ textRuns: [{
232
+ st: 0,
233
+ ed: this._endOffset - this._startOffset,
234
+ ts: _univerjs_core.Tools.deepClone(style)
235
+ }]
236
+ }, _univerjs_core.UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
237
+ }
238
+ /**
239
+ * Replaces the range with plain text while preserving document mutation semantics.
240
+ * @example
241
+ * ```ts
242
+ * const fDocument = univerAPI.getActiveDocument();
243
+ * const range = fDocument?.findParagraphByText('Draft')?.getTextRange();
244
+ * range?.setText('Final');
245
+ * ```
246
+ */
247
+ setText(text) {
248
+ return replaceBodyRange(this.getRange(), buildPlainTextInsertBody(text), this._document.getDocumentDataModel(), this._injector);
249
+ }
250
+ _validateRange() {
251
+ const bodyLength = this._document.getBody(this._segmentId).dataStream.length;
252
+ if (!Number.isInteger(this._startOffset) || !Number.isInteger(this._endOffset) || this._startOffset < 0 || this._endOffset < this._startOffset || this._endOffset > bodyLength) throw new RangeError(`Invalid document text range [${this._startOffset}, ${this._endOffset}) for body length ${bodyLength}.`);
253
+ }
254
+ _getStyleSegments() {
255
+ const explicitRuns = this.getExplicitTextStyleRuns();
256
+ const segments = [];
257
+ let offset = this._startOffset;
258
+ for (const run of explicitRuns) {
259
+ if (offset < run.startOffset) segments.push({
260
+ startOffset: offset,
261
+ endOffset: run.startOffset,
262
+ textStyle: {}
263
+ });
264
+ segments.push(run);
265
+ offset = run.endOffset;
266
+ }
267
+ if (offset < this._endOffset) segments.push({
268
+ startOffset: offset,
269
+ endOffset: this._endOffset,
270
+ textStyle: {}
271
+ });
272
+ return segments;
273
+ }
274
+ };
275
+ function isDeepEqual(left, right) {
276
+ return JSON.stringify(left) === JSON.stringify(right);
277
+ }
278
+
101
279
  //#endregion
102
280
  //#region src/facade/f-document-paragraph.ts
103
281
  /**
@@ -155,7 +333,8 @@ var FDocumentParagraph = class {
155
333
  * ```
156
334
  */
157
335
  getInfo() {
158
- const { paragraphs = [] } = this._document.getBody(this._segmentId);
336
+ const body = this._document.getBody(this._segmentId);
337
+ const { paragraphs = [] } = body;
159
338
  const matches = paragraphs.map((paragraph, paragraphIndex) => ({
160
339
  paragraph,
161
340
  paragraphIndex
@@ -166,7 +345,7 @@ var FDocumentParagraph = class {
166
345
  return {
167
346
  paragraph,
168
347
  paragraphIndex,
169
- startOffset: paragraphIndex > 0 ? paragraphs[paragraphIndex - 1].startIndex + 1 : 0,
348
+ startOffset: (0, _univerjs_core.getParagraphContentStartOffset)(body, paragraph),
170
349
  endOffset: paragraph.startIndex
171
350
  };
172
351
  }
@@ -189,6 +368,21 @@ var FDocumentParagraph = class {
189
368
  };
190
369
  }
191
370
  /**
371
+ * Returns an agent-friendly facade for reading and styling this paragraph's text.
372
+ * @returns {FDocumentTextRange} The paragraph text range, excluding the trailing paragraph break.
373
+ * @example
374
+ * ```ts
375
+ * const fDocument = univerAPI.getActiveDocument();
376
+ * const paragraph = fDocument?.findParagraphByText('Launch');
377
+ * const range = paragraph?.getTextRange();
378
+ * console.log(range?.describe());
379
+ * ```
380
+ */
381
+ getTextRange() {
382
+ const { startOffset, endOffset } = this.getInfo();
383
+ return this._injector.createInstance(FDocumentTextRange, this._document, startOffset, endOffset, this._segmentId, this._injector);
384
+ }
385
+ /**
192
386
  * Get this paragraph's plain text.
193
387
  * @returns {string} The paragraph text without the trailing paragraph break.
194
388
  * @example
@@ -241,6 +435,7 @@ var FDocumentParagraph = class {
241
435
  }
242
436
  /**
243
437
  * Apply paragraph style to a paragraph handle or text range.
438
+ * `style.textStyle.fs` is a font size in points (pt), not CSS pixels.
244
439
  * @param {IParagraphStyle} style The Univer paragraph style patch.
245
440
  * @returns {boolean} `true` if the style was applied.
246
441
  * @example
@@ -388,6 +583,412 @@ function isParagraphFacade(value) {
388
583
  return typeof value.getId === "function" && typeof value.getSegmentId === "function" && typeof value.getInfo === "function" && typeof value.getRange === "function";
389
584
  }
390
585
 
586
+ //#endregion
587
+ //#region src/facade/f-document-section.ts
588
+ /** Error thrown when traditional section APIs are used to mutate a modern document. */
589
+ var DocsSectionUnsupportedDocumentFlavorError = class extends Error {
590
+ constructor() {
591
+ super("Section column APIs are supported only in traditional documents. Use ColumnGroup APIs for modern documents.");
592
+ this.name = "DocsSectionUnsupportedDocumentFlavorError";
593
+ }
594
+ };
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) {
608
+ this._document = _document;
609
+ this._sectionId = _sectionId;
610
+ this._injector = _injector;
611
+ }
612
+ /**
613
+ * Returns the persisted section id.
614
+ * @example
615
+ * ```ts
616
+ * const fDocument = univerAPI.getActiveDocument();
617
+ * console.log(fDocument?.getSection(0)?.getId());
618
+ * ```
619
+ */
620
+ getId() {
621
+ return this._sectionId;
622
+ }
623
+ /**
624
+ * Returns the current zero-based section index.
625
+ * @example
626
+ * ```ts
627
+ * const fDocument = univerAPI.getActiveDocument();
628
+ * console.log(fDocument?.getSection(0)?.getIndex());
629
+ * ```
630
+ */
631
+ getIndex() {
632
+ return this._resolve().index;
633
+ }
634
+ /**
635
+ * Returns the section break snapshot that terminates this section.
636
+ * @example
637
+ * ```ts
638
+ * const fDocument = univerAPI.getActiveDocument();
639
+ * console.log(fDocument?.getSection(0)?.getConfig());
640
+ * ```
641
+ */
642
+ getConfig() {
643
+ const { sectionBreak } = this._resolve();
644
+ return _univerjs_core.Tools.deepClone(sectionBreak);
645
+ }
646
+ /**
647
+ * Returns the section content range, excluding its terminating section-break token.
648
+ * @example
649
+ * ```ts
650
+ * const fDocument = univerAPI.getActiveDocument();
651
+ * console.log(fDocument?.getSection(0)?.getRange());
652
+ * ```
653
+ */
654
+ 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
+ };
662
+ }
663
+ /**
664
+ * Returns the explicit columns. An empty array means the normal single-column layout.
665
+ * Column widths and trailing spaces are in points (pt).
666
+ * @example
667
+ * ```ts
668
+ * const fDocument = univerAPI.getActiveDocument();
669
+ * console.log(fDocument?.getSection(0)?.getColumns());
670
+ * ```
671
+ */
672
+ 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 : []);
675
+ }
676
+ /**
677
+ * Returns a compact serializable section summary.
678
+ * @example
679
+ * ```ts
680
+ * const fDocument = univerAPI.getActiveDocument();
681
+ * console.log(fDocument?.getSection(0)?.describe());
682
+ * ```
683
+ */
684
+ 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 : [];
688
+ const headerFooter = {
689
+ defaultHeader: this._describeHeaderFooterReference("header", "default"),
690
+ defaultFooter: this._describeHeaderFooterReference("footer", "default"),
691
+ firstHeader: this._describeHeaderFooterReference("header", "first"),
692
+ firstFooter: this._describeHeaderFooterReference("footer", "first"),
693
+ evenHeader: this._describeHeaderFooterReference("header", "even"),
694
+ evenFooter: this._describeHeaderFooterReference("footer", "even")
695
+ };
696
+ return {
697
+ sectionId: this._sectionId,
698
+ index: this.getIndex(),
699
+ range: this.getRange(),
700
+ columnCount: columns.length || 1,
701
+ 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,
704
+ headerFooter,
705
+ config
706
+ };
707
+ }
708
+ /**
709
+ * Sets equal or explicitly sized columns for this traditional section.
710
+ * Use `columnCount = 1` to restore normal single-column layout.
711
+ * `gap` and `widths` are in points (pt).
712
+ * @example
713
+ * ```ts
714
+ * const fDocument = univerAPI.getActiveDocument();
715
+ * if (fDocument && !fDocument.isModern()) {
716
+ * fDocument.getSection(0)?.setColumns(2, { gap: 18, separator: true });
717
+ * }
718
+ * ```
719
+ */
720
+ setColumns(columnCount, options = {}) {
721
+ var _options$gap, _options$separator;
722
+ this._assertTraditionalDocument();
723
+ if (!Number.isInteger(columnCount) || columnCount < 1) throw new RangeError("Section column count must be a positive integer.");
724
+ 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();
727
+ 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;
729
+ return this._update({
730
+ columnProperties: columns,
731
+ columnSeparatorType: separator,
732
+ ...options.sectionType == null ? {} : { sectionType: options.sectionType }
733
+ });
734
+ }
735
+ /**
736
+ * Sets explicit OOXML-compatible column width and trailing-space values in points (pt).
737
+ * @example
738
+ * ```ts
739
+ * const fDocument = univerAPI.getActiveDocument();
740
+ * if (fDocument && !fDocument.isModern()) {
741
+ * fDocument.getSection(0)?.setColumnProperties([
742
+ * { width: 240, paddingEnd: 18 },
743
+ * { width: 240, paddingEnd: 0 },
744
+ * ], univerAPI.Enum.ColumnSeparatorType.BETWEEN_EACH_COLUMN);
745
+ * }
746
+ * ```
747
+ */
748
+ setColumnProperties(columns, separator = _univerjs_core.ColumnSeparatorType.NONE) {
749
+ this._assertTraditionalDocument();
750
+ if (columns.some(({ width, paddingEnd }) => width < 0 || paddingEnd < 0)) throw new RangeError("Section column widths and padding must be non-negative.");
751
+ return this._update({
752
+ columnProperties: _univerjs_core.Tools.deepClone(columns),
753
+ columnSeparatorType: separator
754
+ });
755
+ }
756
+ /**
757
+ * Sets how the next section begins.
758
+ * @example
759
+ * ```ts
760
+ * const fDocument = univerAPI.getActiveDocument();
761
+ * if (fDocument && !fDocument.isModern()) {
762
+ * fDocument.getSection(0)?.setSectionType(univerAPI.Enum.SectionType.NEXT_PAGE);
763
+ * }
764
+ * ```
765
+ */
766
+ setSectionType(sectionType) {
767
+ this._assertTraditionalDocument();
768
+ return this._update({ sectionType });
769
+ }
770
+ /**
771
+ * Ensures a header segment linked specifically to this section.
772
+ * @example
773
+ * ```ts
774
+ * const fDocument = univerAPI.getActiveDocument();
775
+ * if (fDocument && !fDocument.isModern()) {
776
+ * const segmentId = fDocument.getSection(0)?.ensureHeader();
777
+ * if (segmentId) {
778
+ * fDocument.insertText(0, 'Quarterly report', segmentId);
779
+ * }
780
+ * }
781
+ * ```
782
+ */
783
+ ensureHeader(variant = "default") {
784
+ return this._ensureHeaderFooter("header", variant);
785
+ }
786
+ /**
787
+ * Ensures a footer segment linked specifically to this section.
788
+ * @example
789
+ * ```ts
790
+ * const fDocument = univerAPI.getActiveDocument();
791
+ * if (fDocument && !fDocument.isModern()) {
792
+ * const segmentId = fDocument.getSection(0)?.ensureFooter('first');
793
+ * if (segmentId) {
794
+ * fDocument.insertText(0, 'Confidential', segmentId);
795
+ * }
796
+ * }
797
+ * ```
798
+ */
799
+ ensureFooter(variant = "default") {
800
+ return this._ensureHeaderFooter("footer", variant);
801
+ }
802
+ /**
803
+ * Returns the effective header id after resolving links to previous sections.
804
+ * @example
805
+ * ```ts
806
+ * const fDocument = univerAPI.getActiveDocument();
807
+ * console.log(fDocument?.getSection(0)?.getHeaderId('default'));
808
+ * ```
809
+ */
810
+ getHeaderId(variant = "default") {
811
+ var _this$_getHeaderFoote;
812
+ return (_this$_getHeaderFoote = this._getHeaderFooterReference("header", variant).segmentId) !== null && _this$_getHeaderFoote !== void 0 ? _this$_getHeaderFoote : null;
813
+ }
814
+ /**
815
+ * Returns the effective footer id after resolving links to previous sections.
816
+ * @example
817
+ * ```ts
818
+ * const fDocument = univerAPI.getActiveDocument();
819
+ * console.log(fDocument?.getSection(0)?.getFooterId('first'));
820
+ * ```
821
+ */
822
+ getFooterId(variant = "default") {
823
+ var _this$_getHeaderFoote2;
824
+ return (_this$_getHeaderFoote2 = this._getHeaderFooterReference("footer", variant).segmentId) !== null && _this$_getHeaderFoote2 !== void 0 ? _this$_getHeaderFoote2 : null;
825
+ }
826
+ /**
827
+ * Whether this header variant inherits the previous section's reference.
828
+ * @example
829
+ * ```ts
830
+ * const fDocument = univerAPI.getActiveDocument();
831
+ * console.log(fDocument?.getSection(1)?.isHeaderLinkedToPrevious());
832
+ * ```
833
+ */
834
+ isHeaderLinkedToPrevious(variant = "default") {
835
+ return this._getHeaderFooterReference("header", variant).linkedToPrevious;
836
+ }
837
+ /**
838
+ * Whether this footer variant inherits the previous section's reference.
839
+ * @example
840
+ * ```ts
841
+ * const fDocument = univerAPI.getActiveDocument();
842
+ * console.log(fDocument?.getSection(1)?.isFooterLinkedToPrevious('even'));
843
+ * ```
844
+ */
845
+ isFooterLinkedToPrevious(variant = "default") {
846
+ return this._getHeaderFooterReference("footer", variant).linkedToPrevious;
847
+ }
848
+ /**
849
+ * Links or unlinks this header variant. Unlinking clones the inherited header.
850
+ * @example
851
+ * ```ts
852
+ * const fDocument = univerAPI.getActiveDocument();
853
+ * if (fDocument && !fDocument.isModern()) {
854
+ * fDocument.getSection(1)?.setHeaderLinkedToPrevious(false, 'default');
855
+ * }
856
+ * ```
857
+ */
858
+ setHeaderLinkedToPrevious(linkedToPrevious, variant = "default") {
859
+ return this._setHeaderFooterLinkedToPrevious("header", variant, linkedToPrevious);
860
+ }
861
+ /**
862
+ * Links or unlinks this footer variant. Unlinking clones the inherited footer.
863
+ * @example
864
+ * ```ts
865
+ * const fDocument = univerAPI.getActiveDocument();
866
+ * if (fDocument && !fDocument.isModern()) {
867
+ * fDocument.getSection(1)?.setFooterLinkedToPrevious(true, 'even');
868
+ * }
869
+ * ```
870
+ */
871
+ setFooterLinkedToPrevious(linkedToPrevious, variant = "default") {
872
+ return this._setHeaderFooterLinkedToPrevious("footer", variant, linkedToPrevious);
873
+ }
874
+ /**
875
+ * Updates header/footer switches and margins on this section break.
876
+ * `marginHeader` and `marginFooter` are in points (pt).
877
+ * @example
878
+ * ```ts
879
+ * const fDocument = univerAPI.getActiveDocument();
880
+ * if (fDocument && !fDocument.isModern()) {
881
+ * fDocument.getSection(0)?.setHeaderFooterOptions({
882
+ * marginHeader: 36,
883
+ * marginFooter: 36,
884
+ * useFirstPageHeaderFooter: univerAPI.Enum.BooleanNumber.TRUE,
885
+ * });
886
+ * }
887
+ * ```
888
+ */
889
+ setHeaderFooterOptions(options) {
890
+ this._assertTraditionalDocument();
891
+ return this._update(options);
892
+ }
893
+ /**
894
+ * Deletes this section break. The final top-level section break cannot be removed.
895
+ * @example
896
+ * ```ts
897
+ * const fDocument = univerAPI.getActiveDocument();
898
+ * if (fDocument && !fDocument.isModern()) {
899
+ * const sections = fDocument.getSections();
900
+ * if (sections.length > 1) {
901
+ * sections[0].remove();
902
+ * }
903
+ * }
904
+ * ```
905
+ */
906
+ remove() {
907
+ this._assertTraditionalDocument();
908
+ return this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.DeleteDocumentSectionBreakCommand.id, {
909
+ unitId: this._document.getId(),
910
+ sectionId: this._sectionId
911
+ });
912
+ }
913
+ _update(patch) {
914
+ const { sectionId: _sectionId, startIndex: _startIndex, ...config } = patch;
915
+ return this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.UpdateDocumentSectionCommand.id, {
916
+ unitId: this._document.getId(),
917
+ updates: [{
918
+ sectionId: this._sectionId,
919
+ config
920
+ }]
921
+ });
922
+ }
923
+ _ensureHeaderFooter(kind, variant) {
924
+ this._assertTraditionalDocument();
925
+ const { index } = this._resolve();
926
+ const existing = this.getConfig()[(0, _univerjs_core.getSectionHeaderFooterReferenceKey)(kind, variant)];
927
+ if (typeof existing === "string" && existing) return existing;
928
+ if (index > 0) {
929
+ const segmentId = (0, _univerjs_core.generateRandomId)(6);
930
+ if (!this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.SetSectionHeaderFooterLinkCommand.id, {
931
+ unitId: this._document.getId(),
932
+ sectionId: this._sectionId,
933
+ kind,
934
+ variant,
935
+ linkedToPrevious: false,
936
+ segmentId
937
+ })) throw new Error(`Failed to create section ${kind}.`);
938
+ return segmentId;
939
+ }
940
+ const types = {
941
+ default: kind === "header" ? _univerjs_docs.HeaderFooterType.DEFAULT_HEADER : _univerjs_docs.HeaderFooterType.DEFAULT_FOOTER,
942
+ first: kind === "header" ? _univerjs_docs.HeaderFooterType.FIRST_PAGE_HEADER : _univerjs_docs.HeaderFooterType.FIRST_PAGE_FOOTER,
943
+ even: kind === "header" ? _univerjs_docs.HeaderFooterType.EVEN_PAGE_HEADER : _univerjs_docs.HeaderFooterType.EVEN_PAGE_FOOTER
944
+ };
945
+ const segmentId = (0, _univerjs_core.generateRandomId)(6);
946
+ if (!this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.CreateHeaderFooterCommand.id, {
947
+ unitId: this._document.getId(),
948
+ segmentId,
949
+ createType: types[variant],
950
+ sectionId: this._sectionId
951
+ })) throw new Error(`Failed to create section ${kind}.`);
952
+ return segmentId;
953
+ }
954
+ _getHeaderFooterReference(kind, variant) {
955
+ const { index } = this._resolve();
956
+ 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
+ }
958
+ _describeHeaderFooterReference(kind, variant) {
959
+ var _reference$segmentId;
960
+ const reference = this._getHeaderFooterReference(kind, variant);
961
+ return {
962
+ segmentId: (_reference$segmentId = reference.segmentId) !== null && _reference$segmentId !== void 0 ? _reference$segmentId : null,
963
+ linkedToPrevious: reference.linkedToPrevious
964
+ };
965
+ }
966
+ _setHeaderFooterLinkedToPrevious(kind, variant, linkedToPrevious) {
967
+ this._assertTraditionalDocument();
968
+ return this._injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.SetSectionHeaderFooterLinkCommand.id, {
969
+ unitId: this._document.getId(),
970
+ sectionId: this._sectionId,
971
+ kind,
972
+ variant,
973
+ linkedToPrevious,
974
+ ...linkedToPrevious ? {} : { segmentId: (0, _univerjs_core.generateRandomId)(6) }
975
+ });
976
+ }
977
+ _assertTraditionalDocument() {
978
+ if (this._document.getDocumentDataModel().getSnapshot().documentStyle.documentFlavor !== _univerjs_core.DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
979
+ }
980
+ _resolve() {
981
+ this._assertTraditionalDocument();
982
+ const sectionBreaks = (0, _univerjs_docs.getTopLevelSectionBreaks)(this._document.getBody());
983
+ const index = sectionBreaks.findIndex((section) => section.sectionId === this._sectionId);
984
+ if (index < 0) throw new Error(`Document section with id ${this._sectionId} not found.`);
985
+ return {
986
+ index,
987
+ sectionBreak: sectionBreaks[index]
988
+ };
989
+ }
990
+ };
991
+
391
992
  //#endregion
392
993
  //#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
393
994
  function _typeof(o) {
@@ -630,6 +1231,180 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
630
1231
  }, buildPlainTextInsertBody(text), this._documentDataModel, this._injector);
631
1232
  }
632
1233
  /**
1234
+ * Returns document-level header/footer switches and margins. Margin values are in points (pt).
1235
+ * @example
1236
+ * ```ts
1237
+ * const fDocument = univerAPI.getActiveDocument();
1238
+ * console.log(fDocument?.getHeaderFooterOptions());
1239
+ * ```
1240
+ */
1241
+ getHeaderFooterOptions() {
1242
+ const style = this._documentDataModel.getSnapshot().documentStyle;
1243
+ return {
1244
+ marginHeader: style.marginHeader,
1245
+ marginFooter: style.marginFooter,
1246
+ useFirstPageHeaderFooter: style.useFirstPageHeaderFooter,
1247
+ evenAndOddHeaders: style.evenAndOddHeaders
1248
+ };
1249
+ }
1250
+ /**
1251
+ * Updates document-level header/footer switches and margins in a traditional document.
1252
+ * `marginHeader` and `marginFooter` are in points (pt).
1253
+ * @example
1254
+ * ```ts
1255
+ * const fDocument = univerAPI.getActiveDocument();
1256
+ * if (fDocument && !fDocument.isModern()) {
1257
+ * fDocument.setHeaderFooterOptions({ marginHeader: 36, marginFooter: 36 });
1258
+ * }
1259
+ * ```
1260
+ */
1261
+ setHeaderFooterOptions(options) {
1262
+ if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
1263
+ return this._commandService.syncExecuteCommand(_univerjs_docs.CreateHeaderFooterCommand.id, {
1264
+ unitId: this.getId(),
1265
+ headerFooterProps: options
1266
+ });
1267
+ }
1268
+ /**
1269
+ * Creates a facade for reading and styling a document text range.
1270
+ * The end offset is exclusive, and offsets are scoped to the selected body segment.
1271
+ * @param {number} startOffset The inclusive start offset.
1272
+ * @param {number} endOffset The exclusive end offset.
1273
+ * @param {string} segmentId The header/footer segment id, or an empty string for the main body.
1274
+ * @returns {FDocumentTextRange} A fixed text-range facade.
1275
+ * @example
1276
+ * ```ts
1277
+ * const range = univerAPI.getActiveDocument()?.getTextRange(0, 5);
1278
+ * console.log(range?.describe());
1279
+ * range?.setTextStyle({ bl: 1 });
1280
+ * ```
1281
+ */
1282
+ getTextRange(startOffset, endOffset, segmentId = "") {
1283
+ return this._injector.createInstance(FDocumentTextRange, this, startOffset, endOffset, segmentId, this._injector);
1284
+ }
1285
+ /**
1286
+ * Returns traditional document sections backed by persisted SectionBreak ids.
1287
+ * Modern documents use ColumnGroup instead and return an empty array from this read API.
1288
+ * @example
1289
+ * ```ts
1290
+ * const fDocument = univerAPI.getActiveDocument();
1291
+ * const sections = fDocument?.getSections() ?? [];
1292
+ * console.log(sections.map((section) => section.describe()));
1293
+ * ```
1294
+ */
1295
+ getSections() {
1296
+ 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));
1298
+ }
1299
+ /**
1300
+ * Returns a traditional section by zero-based index, or `null` in modern documents.
1301
+ * @example
1302
+ * ```ts
1303
+ * const fDocument = univerAPI.getActiveDocument();
1304
+ * const firstSection = fDocument?.getSection(0);
1305
+ * console.log(firstSection?.describe());
1306
+ * ```
1307
+ */
1308
+ 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;
1311
+ }
1312
+ /**
1313
+ * Returns the traditional section containing a data-stream offset, or `null` in modern documents.
1314
+ * @example
1315
+ * ```ts
1316
+ * const fDocument = univerAPI.getActiveDocument();
1317
+ * const paragraph = fDocument?.findParagraphByText('Launch');
1318
+ * const offset = paragraph?.getInfo().startOffset;
1319
+ * const section = offset == null ? null : fDocument?.getSectionAt(offset);
1320
+ * console.log(section?.getId());
1321
+ * ```
1322
+ */
1323
+ getSectionAt(offset) {
1324
+ var _this$getSections$fin;
1325
+ return (_this$getSections$fin = this.getSections().find((section) => {
1326
+ const range = section.getRange();
1327
+ return offset >= range.startOffset && offset <= range.endOffset;
1328
+ })) !== null && _this$getSections$fin !== void 0 ? _this$getSections$fin : null;
1329
+ }
1330
+ /**
1331
+ * 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).
1334
+ * @example
1335
+ * ```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());
1342
+ * }
1343
+ * ```
1344
+ */
1345
+ insertSectionBreak(offset, config = {}) {
1346
+ var _this$getBody$section;
1347
+ 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)));
1349
+ return this._commandService.syncExecuteCommand(_univerjs_docs.InsertDocumentSectionBreakCommand.id, {
1350
+ unitId: this.getId(),
1351
+ offset,
1352
+ sectionId,
1353
+ config
1354
+ }) ? this._injector.createInstance(FDocumentSection, this, sectionId, this._injector) : null;
1355
+ }
1356
+ /**
1357
+ * Inserts a column-break token in a traditional document.
1358
+ * Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
1359
+ * @example
1360
+ * ```ts
1361
+ * const fDocument = univerAPI.getActiveDocument();
1362
+ * if (fDocument && !fDocument.isModern()) {
1363
+ * const paragraph = fDocument.findParagraphByText('Continue in next column');
1364
+ * const offset = paragraph?.getInfo().startOffset;
1365
+ * if (offset != null) {
1366
+ * fDocument.insertColumnBreak(offset);
1367
+ * }
1368
+ * }
1369
+ * ```
1370
+ */
1371
+ insertColumnBreak(offset) {
1372
+ if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== _univerjs_core.DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
1373
+ return this.insertText(offset, _univerjs_core.DataStreamTreeTokenType.COLUMN_BREAK);
1374
+ }
1375
+ /**
1376
+ * Inserts a horizontal rule using the existing paragraph `borderBottom` mechanism.
1377
+ * The returned paragraph can be inspected or removed with normal paragraph APIs.
1378
+ * Border width and padding are in points (pt).
1379
+ * @example
1380
+ * ```ts
1381
+ * const fDocument = univerAPI.getActiveDocument();
1382
+ * const paragraph = fDocument?.findParagraphByText('Summary');
1383
+ * const offset = paragraph?.getInfo().startOffset;
1384
+ * const rule = offset == null ? null : fDocument?.insertHorizontalRule(offset);
1385
+ * console.log(rule?.getId());
1386
+ * ```
1387
+ */
1388
+ insertHorizontalRule(offset, border = {
1389
+ padding: 5,
1390
+ color: { rgb: "#CDD0D8" },
1391
+ width: 1,
1392
+ dashStyle: _univerjs_core.DashStyleType.SOLID
1393
+ }, segmentId = "") {
1394
+ var _body$paragraphs;
1395
+ const body = this.getBody(segmentId);
1396
+ const paragraphs = (0, _univerjs_docs.generateParagraphs)(_univerjs_core.DataStreamTreeTokenType.PARAGRAPH, void 0, border, (_body$paragraphs = body.paragraphs) === null || _body$paragraphs === void 0 ? void 0 : _body$paragraphs.map((paragraph) => paragraph.paragraphId));
1397
+ const paragraphId = paragraphs[0].paragraphId;
1398
+ return replaceBodyRange({
1399
+ startOffset: offset,
1400
+ endOffset: offset,
1401
+ segmentId
1402
+ }, {
1403
+ dataStream: _univerjs_core.DataStreamTreeTokenType.PARAGRAPH,
1404
+ paragraphs
1405
+ }, this._documentDataModel, this._injector) ? this.getParagraph(paragraphId, segmentId) : null;
1406
+ }
1407
+ /**
633
1408
  * Get all paragraphs in the document body or header/footer body by the segment id.
634
1409
  * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
635
1410
  * @returns {FDocumentParagraph[]} An array of paragraph facade instances.
@@ -749,6 +1524,7 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
749
1524
  /**
750
1525
  * Append a plain-text paragraph at the end of the body.
751
1526
  * @param {string} text The paragraph text. Defaults to an empty paragraph.
1527
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
752
1528
  * @returns {FDocumentParagraph} The appended paragraph wrapper.
753
1529
  * @example
754
1530
  * ```ts
@@ -798,10 +1574,11 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
798
1574
  }
799
1575
  _getParagraphInsertOffset(index, segmentId = "") {
800
1576
  if (index <= 0) return 0;
801
- const { dataStream, paragraphs = [] } = this.getBody(segmentId);
1577
+ const body = this.getBody(segmentId);
1578
+ const { dataStream, paragraphs = [] } = body;
802
1579
  if (paragraphs.length === 0) return Math.max(0, dataStream.length - 1);
803
1580
  if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
804
- return paragraphs[index - 1].startIndex + 1;
1581
+ return (0, _univerjs_core.getParagraphContentStartOffset)(body, paragraphs[index]);
805
1582
  }
806
1583
  _ensureHeaderFooter(kind, pageIndex) {
807
1584
  if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
@@ -877,6 +1654,35 @@ var FUniverDocsMixin = class extends _univerjs_core_facade.FUniver {
877
1654
  _univerjs_core_facade.FUniver.extend(FUniverDocsMixin);
878
1655
 
879
1656
  //#endregion
1657
+ //#region src/facade/f-enum.ts
1658
+ /**
1659
+ * Copyright 2023-present DreamNum Co., Ltd.
1660
+ *
1661
+ * Licensed under the Apache License, Version 2.0 (the "License");
1662
+ * you may not use this file except in compliance with the License.
1663
+ * You may obtain a copy of the License at
1664
+ *
1665
+ * http://www.apache.org/licenses/LICENSE-2.0
1666
+ *
1667
+ * Unless required by applicable law or agreed to in writing, software
1668
+ * distributed under the License is distributed on an "AS IS" BASIS,
1669
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1670
+ * See the License for the specific language governing permissions and
1671
+ * limitations under the License.
1672
+ */
1673
+ var FDocsEnumMixin = class extends _univerjs_core_facade.FEnum {
1674
+ get SectionType() {
1675
+ return _univerjs_core.SectionType;
1676
+ }
1677
+ get ColumnSeparatorType() {
1678
+ return _univerjs_core.ColumnSeparatorType;
1679
+ }
1680
+ };
1681
+ _univerjs_core_facade.FEnum.extend(FDocsEnumMixin);
1682
+
1683
+ //#endregion
1684
+ exports.DocsSectionUnsupportedDocumentFlavorError = DocsSectionUnsupportedDocumentFlavorError;
1685
+ exports.FDocsEnumMixin = FDocsEnumMixin;
880
1686
  Object.defineProperty(exports, 'FDocument', {
881
1687
  enumerable: true,
882
1688
  get: function () {
@@ -884,5 +1690,7 @@ Object.defineProperty(exports, 'FDocument', {
884
1690
  }
885
1691
  });
886
1692
  exports.FDocumentParagraph = FDocumentParagraph;
1693
+ exports.FDocumentSection = FDocumentSection;
1694
+ exports.FDocumentTextRange = FDocumentTextRange;
887
1695
  exports.isParagraphFacade = isParagraphFacade;
888
1696
  exports.stripBlockTokens = stripBlockTokens;