@univerjs/docs 1.0.0-alpha.1 → 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.
Files changed (32) hide show
  1. package/lib/cjs/facade.js +1156 -868
  2. package/lib/cjs/index.js +723 -18
  3. package/lib/es/facade.js +1154 -867
  4. package/lib/es/index.js +701 -19
  5. package/lib/facade.js +1154 -867
  6. package/lib/index.js +701 -19
  7. package/lib/types/commands/commands/create-header-footer.command.d.ts +45 -0
  8. package/lib/types/commands/commands/set-document-default-paragraph-style.command.d.ts +24 -0
  9. package/lib/types/commands/commands/set-section-header-footer-link.command.d.ts +26 -0
  10. package/lib/types/commands/commands/update-document-section.command.d.ts +38 -0
  11. package/lib/types/embed-host-anchor.d.ts +61 -0
  12. package/lib/types/facade/f-document-paragraph.d.ts +87 -100
  13. package/lib/types/facade/f-document-section.d.ts +281 -0
  14. package/lib/types/facade/f-document-text-range.d.ts +136 -0
  15. package/lib/types/facade/f-document.d.ts +316 -26
  16. package/lib/types/facade/f-enum.d.ts +32 -0
  17. package/lib/types/facade/f-types.d.ts +16 -0
  18. package/lib/types/facade/index.d.ts +11 -6
  19. package/lib/types/facade/utils.d.ts +15 -1
  20. package/lib/types/index.d.ts +15 -1
  21. package/lib/types/utils/paragraphs.d.ts +18 -0
  22. package/lib/types/utils/section-columns.d.ts +18 -0
  23. package/lib/types/utils/sections.d.ts +18 -0
  24. package/lib/types/utils/util.d.ts +19 -0
  25. package/lib/umd/facade.js +3 -1
  26. package/lib/umd/index.js +2 -1
  27. package/package.json +5 -5
  28. package/lib/types/facade/f-document-block-range.d.ts +0 -132
  29. package/lib/types/facade/f-document-body.d.ts +0 -276
  30. package/lib/types/facade/f-document-custom-block.d.ts +0 -57
  31. package/lib/types/facade/f-document-element.d.ts +0 -193
  32. package/lib/types/facade/f-document-table.d.ts +0 -57
package/lib/es/facade.js CHANGED
@@ -1,240 +1,278 @@
1
- import { DocumentBlockType, ICommandService, IResourceLoaderService, IUniverInstanceService, Inject, Injector, JSONX, PresetListType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommand, TextX, TextXActionType, UndoCommand, UniverInstanceType, UpdateDocsAttributeType, createParagraphId, getRichTextEditPath } from "@univerjs/core";
2
- import { FBase, FBaseInitialable, FUniver } from "@univerjs/core/facade";
3
- import { RichTextEditingMutation } from "@univerjs/docs";
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";
2
+ import { FBaseInitialable, FEnum, FUniver } from "@univerjs/core/facade";
3
+ import { CreateHeaderFooterCommand, DeleteDocumentSectionBreakCommand, HeaderFooterType, InsertDocumentSectionBreakCommand, RichTextEditingMutation, SetSectionHeaderFooterLinkCommand, UpdateDocumentSectionCommand, createSectionColumnProperties, generateParagraphs, getTopLevelSectionBreaks } from "@univerjs/docs";
4
4
 
5
- //#region src/facade/f-document-element.ts
5
+ //#region src/facade/utils.ts
6
+ function cloneParagraphStyle(paragraphStyle) {
7
+ return paragraphStyle == null ? paragraphStyle : JSON.parse(JSON.stringify(paragraphStyle));
8
+ }
9
+ function normalizePlainTextDataStream(dataStream) {
10
+ return dataStream.replace(/\r\n/g, "\r").replace(/\n/g, "\r");
11
+ }
12
+ function getRemovedLeadingParagraphBreakLength(dataStream, removeLeadingParagraphBreak) {
13
+ const normalized = normalizePlainTextDataStream(dataStream);
14
+ if (removeLeadingParagraphBreak && normalized.length > 1 && normalized.startsWith("\r")) return 1;
15
+ return 0;
16
+ }
17
+ function buildPlainTextInsertBody(dataStream, options = {}) {
18
+ const normalizedDataStream = normalizePlainTextDataStream(dataStream).slice(getRemovedLeadingParagraphBreakLength(dataStream, options.removeLeadingParagraphBreak));
19
+ const body = {
20
+ dataStream: normalizedDataStream,
21
+ customDecorations: [],
22
+ customRanges: [],
23
+ textRuns: []
24
+ };
25
+ const paragraphs = [];
26
+ const existingParagraphIds = /* @__PURE__ */ new Set();
27
+ for (let index = 0; index < normalizedDataStream.length; index++) if (normalizedDataStream[index] === "\r") paragraphs.push({
28
+ startIndex: index,
29
+ paragraphId: createParagraphId(existingParagraphIds),
30
+ ...options.paragraphStyle == null ? {} : { paragraphStyle: cloneParagraphStyle(options.paragraphStyle) }
31
+ });
32
+ if (paragraphs.length > 0) body.paragraphs = paragraphs;
33
+ return body;
34
+ }
35
+ function replaceBodyRange(range, insertBody, docDataModel, injector) {
36
+ const { startOffset, endOffset, segmentId } = range;
37
+ const textX = new TextX();
38
+ if (startOffset > 0) textX.push({
39
+ t: TextXActionType.RETAIN,
40
+ len: startOffset
41
+ });
42
+ if (endOffset > startOffset) textX.push({
43
+ t: TextXActionType.DELETE,
44
+ len: endOffset - startOffset
45
+ });
46
+ if (insertBody.dataStream.length > 0) textX.push({
47
+ t: TextXActionType.INSERT,
48
+ body: insertBody,
49
+ len: insertBody.dataStream.length
50
+ });
51
+ const actions = JSONX.getInstance().editOp(textX.serialize(), getRichTextEditPath(docDataModel, segmentId));
52
+ const result = injector.get(ICommandService).syncExecuteCommand(RichTextEditingMutation.id, {
53
+ unitId: docDataModel.getUnitId(),
54
+ segmentId,
55
+ actions,
56
+ textRanges: [],
57
+ isEditing: false
58
+ });
59
+ return Boolean((result === null || result === void 0 ? void 0 : result.actions) && result.actions.length > 0);
60
+ }
61
+ function retainBodyRange(range, updateBody, coverType, docDataModel, injector) {
62
+ var _updateBody$textRuns, _docDataModel$getSelf;
63
+ const { startOffset, endOffset, segmentId } = range;
64
+ const commandService = injector.get(ICommandService);
65
+ if (((_updateBody$textRuns = updateBody.textRuns) === null || _updateBody$textRuns === void 0 ? void 0 : _updateBody$textRuns.length) && ((_docDataModel$getSelf = docDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _docDataModel$getSelf === void 0 || (_docDataModel$getSelf = _docDataModel$getSelf.getBody()) === null || _docDataModel$getSelf === void 0 ? void 0 : _docDataModel$getSelf.textRuns) == null) {
66
+ const actions = JSONX.getInstance().replaceOp([...getRichTextEditPath(docDataModel, segmentId), "textRuns"], void 0, []);
67
+ commandService.syncExecuteCommand(RichTextEditingMutation.id, {
68
+ unitId: docDataModel.getUnitId(),
69
+ segmentId,
70
+ actions,
71
+ textRanges: [],
72
+ isEditing: false
73
+ });
74
+ }
75
+ const textX = new TextX();
76
+ if (startOffset > 0) textX.push({
77
+ t: TextXActionType.RETAIN,
78
+ len: startOffset
79
+ });
80
+ textX.push({
81
+ t: TextXActionType.RETAIN,
82
+ body: updateBody,
83
+ coverType,
84
+ len: endOffset - startOffset
85
+ });
86
+ const actions = JSONX.getInstance().editOp(textX.serialize(), getRichTextEditPath(docDataModel, segmentId));
87
+ const result = commandService.syncExecuteCommand(RichTextEditingMutation.id, {
88
+ unitId: docDataModel.getUnitId(),
89
+ segmentId,
90
+ actions,
91
+ textRanges: [],
92
+ isEditing: false
93
+ });
94
+ return Boolean((result === null || result === void 0 ? void 0 : result.actions) && result.actions.length > 0);
95
+ }
96
+ function stripBlockTokens(text) {
97
+ return Array.from(text).map((char) => char === DataStreamTreeTokenType.PARAGRAPH ? "\n" : char).filter((char) => char !== DataStreamTreeTokenType.BLOCK_START && char !== DataStreamTreeTokenType.BLOCK_END && char !== DataStreamTreeTokenType.SECTION_BREAK).join("").replace(/\n$/, "");
98
+ }
99
+
100
+ //#endregion
101
+ //#region src/facade/f-document-text-range.ts
6
102
  /**
7
- * A generic top-level document body element.
8
- *
9
- * Use this wrapper when you need to inspect an element type first, navigate to
10
- * neighboring elements, or cast the element to a more specific facade wrapper.
11
- *
12
- * Paragraph keys are persisted `paragraphId` values. Tables, block ranges, and
13
- * custom blocks use their persisted ids.
103
+ * Facade wrapper for reading and styling a fixed document text range.
14
104
  *
105
+ * Offsets are fixed when the wrapper is created. Create a new range after edits
106
+ * that insert or remove content before it.
15
107
  * @hideconstructor
16
108
  */
17
- var FDocumentElement = class extends FBase {
18
- constructor(_body, _bodyEdit, _info, _injector) {
19
- super();
20
- this._body = _body;
21
- this._bodyEdit = _bodyEdit;
22
- this._info = _info;
109
+ var FDocumentTextRange = class {
110
+ constructor(_document, _startOffset, _endOffset, _segmentId, _injector) {
111
+ this._document = _document;
112
+ this._startOffset = _startOffset;
113
+ this._endOffset = _endOffset;
114
+ this._segmentId = _segmentId;
23
115
  this._injector = _injector;
116
+ this._validateRange();
24
117
  }
25
118
  /**
26
- * Get the document element type.
27
- * @returns {DocumentBlockType} The element type, such as `paragraph`, `table`, `blockRange`, or `customBlock`.
28
- * @example
29
- * ```ts
30
- * const fDocument = univerAPI.getActiveDocument();
31
- * const fDocumentBody = fDocument.getBody();
32
- * const element = fDocumentBody.getElement(0);
33
- * console.log(element?.getType());
34
- * ```
35
- */
36
- getType() {
37
- return this._info.type;
38
- }
39
- /**
40
- * Whether this element is a paragraph.
41
- * @returns {boolean} `true` if this element is a paragraph.
42
- * @example
43
- * ```ts
44
- * const fDocument = univerAPI.getActiveDocument();
45
- * const fDocumentBody = fDocument.getBody();
46
- * const element = fDocumentBody.getElement(0);
47
- * console.log(element?.isParagraph());
48
- * ```
49
- */
50
- isParagraph() {
51
- return this._info.type === DocumentBlockType.PARAGRAPH;
52
- }
53
- /**
54
- * Whether this element is a table.
55
- * @returns {boolean} `true` if this element is a table.
119
+ * Returns the serializable document range.
56
120
  * @example
57
121
  * ```ts
58
122
  * const fDocument = univerAPI.getActiveDocument();
59
- * const fDocumentBody = fDocument.getBody();
60
- * const element = fDocumentBody.getElement(0);
61
- * console.log(element?.isTable());
123
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
124
+ * console.log(range?.getRange());
62
125
  * ```
63
126
  */
64
- isTable() {
65
- return this._info.type === DocumentBlockType.TABLE;
66
- }
67
- /**
68
- * Whether this element is a block range, such as a callout, quote, or code block.
69
- * @returns {boolean} `true` if this element is a block range.
70
- * @example
71
- * ```ts
72
- * const fDocument = univerAPI.getActiveDocument();
73
- * const fDocumentBody = fDocument.getBody();
74
- * const element = fDocumentBody.getElement(0);
75
- * console.log(element?.isBlockRange());
76
- * ```
77
- */
78
- isBlockRange() {
79
- return this._info.type === DocumentBlockType.BLOCK_RANGE;
127
+ getRange() {
128
+ return {
129
+ startOffset: this._startOffset,
130
+ endOffset: this._endOffset,
131
+ segmentId: this._segmentId
132
+ };
80
133
  }
81
134
  /**
82
- * Whether this element is a custom block.
83
- * @returns {boolean} `true` if this element is a custom block.
135
+ * Returns the plain data-stream text in this range.
84
136
  * @example
85
137
  * ```ts
86
138
  * const fDocument = univerAPI.getActiveDocument();
87
- * const fDocumentBody = fDocument.getBody();
88
- * const element = fDocumentBody.getElement(0);
89
- * console.log(element?.isCustomBlock());
139
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
140
+ * console.log(range?.getText());
90
141
  * ```
91
142
  */
92
- isCustomBlock() {
93
- return this._info.type === DocumentBlockType.CUSTOM_BLOCK;
143
+ getText() {
144
+ return this._document.getBody(this._segmentId).dataStream.slice(this._startOffset, this._endOffset);
94
145
  }
95
146
  /**
96
- * Get the facade key used to resolve this element.
97
- * @returns {string} The paragraph `paragraphId` or persisted table/block/custom block id.
147
+ * Returns explicit text-style runs intersecting this range.
148
+ * Returned offsets are clipped to the range and remain document-relative.
98
149
  * @example
99
150
  * ```ts
100
151
  * const fDocument = univerAPI.getActiveDocument();
101
- * const fDocumentBody = fDocument.getBody();
102
- * const element = fDocumentBody.getElement(0);
103
- * console.log(element?.getKey());
152
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
153
+ * console.log(range?.getExplicitTextStyleRuns());
104
154
  * ```
105
155
  */
106
- getKey() {
107
- return this._info.key;
156
+ getExplicitTextStyleRuns() {
157
+ const { textRuns = [] } = this._document.getBody(this._segmentId);
158
+ return textRuns.filter((run) => run.st < this._endOffset && run.ed > this._startOffset).map((run) => {
159
+ var _run$ts;
160
+ return {
161
+ startOffset: Math.max(run.st, this._startOffset),
162
+ endOffset: Math.min(run.ed, this._endOffset),
163
+ textStyle: Tools.deepClone((_run$ts = run.ts) !== null && _run$ts !== void 0 ? _run$ts : {})
164
+ };
165
+ });
108
166
  }
109
- /**
110
- * Get the parent body facade that owns this element.
111
- * @returns {FDocumentBody} The document body facade.
112
- * @example
113
- * ```ts
114
- * const fDocument = univerAPI.getActiveDocument();
115
- * const fDocumentBody = fDocument.getBody();
116
- * const element = fDocumentBody.getElement(0);
117
- * console.log(element?.getParent());
118
- * ```
119
- */
120
- getParent() {
121
- return this._body;
167
+ /** @deprecated Use `getExplicitTextStyleRuns()` to distinguish stored styles from effective styles. */
168
+ getTextStyleRuns() {
169
+ return this.getExplicitTextStyleRuns();
122
170
  }
123
171
  /**
124
- * Get the resolved element info for this wrapper.
125
- * @returns {IFDocumentElementInfo} The resolved element info, including type, key, position, and priority.
172
+ * Returns top-level style properties that have the same explicit value
173
+ * across the complete range. Unstyled gaps make a property non-common.
126
174
  * @example
127
175
  * ```ts
128
176
  * const fDocument = univerAPI.getActiveDocument();
129
- * const fDocumentBody = fDocument.getBody();
130
- * const element = fDocumentBody.getElement(0);
131
- * console.log(element?.getResolvedInfo());
177
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
178
+ * console.log(range?.getCommonExplicitTextStyle());
132
179
  * ```
133
180
  */
134
- getResolvedInfo() {
135
- return this._info;
181
+ getCommonExplicitTextStyle() {
182
+ if (this._startOffset === this._endOffset) return {};
183
+ const [first, ...rest] = this._getStyleSegments();
184
+ const common = Tools.deepClone(first.textStyle);
185
+ for (const key of Object.keys(common)) if (rest.some((run) => !isDeepEqual(run.textStyle[key], common[key]))) delete common[key];
186
+ return common;
136
187
  }
137
- /**
138
- * Get the next sibling element in the current body order.
139
- * @returns {FDocumentElement | null} The next sibling wrapper, or `null` when this is the last child.
140
- * @example
141
- * ```ts
142
- * const fDocument = univerAPI.getActiveDocument();
143
- * const fDocumentBody = fDocument.getBody();
144
- * const element = fDocumentBody.getElement(0);
145
- * console.log(element?.getNextSibling());
146
- * ```
147
- */
148
- getNextSibling() {
149
- return this._createSibling(1);
188
+ /** @deprecated Use `getCommonExplicitTextStyle()` to distinguish stored styles from effective styles. */
189
+ getCommonTextStyle() {
190
+ return this.getCommonExplicitTextStyle();
150
191
  }
151
192
  /**
152
- * Get the previous sibling element in the current body order.
153
- * @returns {FDocumentElement | null} The previous sibling wrapper, or `null` when this is the first child.
193
+ * Returns a serializable summary suitable for an agent/tool response.
154
194
  * @example
155
195
  * ```ts
156
196
  * const fDocument = univerAPI.getActiveDocument();
157
- * const fDocumentBody = fDocument.getBody();
158
- * const element = fDocumentBody.getElement(1);
159
- * console.log(element?.getPreviousSibling());
197
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
198
+ * console.log(range?.describe());
160
199
  * ```
161
200
  */
162
- getPreviousSibling() {
163
- return this._createSibling(-1);
201
+ describe() {
202
+ const explicitTextStyleRuns = this.getExplicitTextStyleRuns();
203
+ const commonExplicitTextStyle = this.getCommonExplicitTextStyle();
204
+ return {
205
+ ...this.getRange(),
206
+ text: this.getText(),
207
+ length: this._endOffset - this._startOffset,
208
+ explicitTextStyleRuns,
209
+ commonExplicitTextStyle,
210
+ textStyleRuns: explicitTextStyleRuns,
211
+ commonTextStyle: commonExplicitTextStyle
212
+ };
164
213
  }
165
214
  /**
166
- * Get the sibling element at a relative offset from this element.
167
- * @param {number} offset The relative offset from this element. Use `1` for the next sibling, `-1` for the previous sibling, and so on.
168
- * @returns {FDocumentElement | null} The sibling wrapper at the specified offset, or `null` when the offset is out of range.
215
+ * Merges a text-style patch into every character in the range.
216
+ * Existing text-run splitting, merging, and normalization are handled by
217
+ * the document mutation pipeline.
218
+ * `style.fs` is a font size in points (pt), not CSS pixels.
169
219
  * @example
170
220
  * ```ts
171
221
  * const fDocument = univerAPI.getActiveDocument();
172
- * const fDocumentBody = fDocument.getBody();
173
- * const element = fDocumentBody.getElement(0);
174
- *
175
- * // Get the third sibling after this element
176
- * const nextThirdSibling = element?.getSibling(3);
177
- * console.log(nextThirdSibling?.getType());
222
+ * const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
223
+ * range?.setTextStyle({ fs: 10.5, bl: univerAPI.Enum.BooleanNumber.TRUE });
178
224
  * ```
179
225
  */
180
- getSibling(offset) {
181
- return this._createSibling(offset);
226
+ setTextStyle(style) {
227
+ if (this._startOffset === this._endOffset) return false;
228
+ return retainBodyRange(this.getRange(), {
229
+ dataStream: "",
230
+ textRuns: [{
231
+ st: 0,
232
+ ed: this._endOffset - this._startOffset,
233
+ ts: Tools.deepClone(style)
234
+ }]
235
+ }, UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
182
236
  }
183
237
  /**
184
- * Remove this element from its parent body.
185
- * @returns {boolean} `true` if the element content was removed.
238
+ * Replaces the range with plain text while preserving document mutation semantics.
186
239
  * @example
187
240
  * ```ts
188
241
  * const fDocument = univerAPI.getActiveDocument();
189
- * const fDocumentBody = fDocument.getBody();
190
- * const element = fDocumentBody.getElement(0);
191
- * const removed = element?.remove();
192
- * console.log(removed);
242
+ * const range = fDocument?.findParagraphByText('Draft')?.getTextRange();
243
+ * range?.setText('Final');
193
244
  * ```
194
245
  */
195
- remove() {
196
- if (this.isParagraph()) return this._body.removeParagraph(this.asParagraph());
197
- if (this.isBlockRange()) return this._body.removeBlockRange(this.asBlockRange());
198
- if (this.isTable()) return this._body.removeTable(this.asTable());
199
- return this._body.removeCustomBlock(this.asCustomBlock());
200
- }
201
- _createSibling(offset) {
202
- if (offset === 0) throw new Error("Offset cannot be zero.");
203
- const index = this._body.getElementIndex(this);
204
- return this._body.getElement(index + offset);
246
+ setText(text) {
247
+ return replaceBodyRange(this.getRange(), buildPlainTextInsertBody(text), this._document.getDocumentDataModel(), this._injector);
248
+ }
249
+ _validateRange() {
250
+ const bodyLength = this._document.getBody(this._segmentId).dataStream.length;
251
+ 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}.`);
252
+ }
253
+ _getStyleSegments() {
254
+ const explicitRuns = this.getExplicitTextStyleRuns();
255
+ const segments = [];
256
+ let offset = this._startOffset;
257
+ for (const run of explicitRuns) {
258
+ if (offset < run.startOffset) segments.push({
259
+ startOffset: offset,
260
+ endOffset: run.startOffset,
261
+ textStyle: {}
262
+ });
263
+ segments.push(run);
264
+ offset = run.endOffset;
265
+ }
266
+ if (offset < this._endOffset) segments.push({
267
+ startOffset: offset,
268
+ endOffset: this._endOffset,
269
+ textStyle: {}
270
+ });
271
+ return segments;
205
272
  }
206
273
  };
207
-
208
- //#endregion
209
- //#region src/facade/utils.ts
210
- function cloneParagraphStyle(paragraphStyle) {
211
- return paragraphStyle == null ? paragraphStyle : JSON.parse(JSON.stringify(paragraphStyle));
212
- }
213
- function normalizePlainTextDataStream(dataStream) {
214
- return dataStream.replace(/\r\n/g, "\r").replace(/\n/g, "\r");
215
- }
216
- function getRemovedLeadingParagraphBreakLength(dataStream, removeLeadingParagraphBreak) {
217
- const normalized = normalizePlainTextDataStream(dataStream);
218
- if (removeLeadingParagraphBreak && normalized.length > 1 && normalized.startsWith("\r")) return 1;
219
- return 0;
220
- }
221
- function buildPlainTextInsertBody(dataStream, options = {}) {
222
- const normalizedDataStream = normalizePlainTextDataStream(dataStream).slice(getRemovedLeadingParagraphBreakLength(dataStream, options.removeLeadingParagraphBreak));
223
- const body = {
224
- dataStream: normalizedDataStream,
225
- customDecorations: [],
226
- customRanges: [],
227
- textRuns: []
228
- };
229
- const paragraphs = [];
230
- const existingParagraphIds = /* @__PURE__ */ new Set();
231
- for (let index = 0; index < normalizedDataStream.length; index++) if (normalizedDataStream[index] === "\r") paragraphs.push({
232
- startIndex: index,
233
- paragraphId: createParagraphId(existingParagraphIds),
234
- ...options.paragraphStyle == null ? {} : { paragraphStyle: cloneParagraphStyle(options.paragraphStyle) }
235
- });
236
- if (paragraphs.length > 0) body.paragraphs = paragraphs;
237
- return body;
274
+ function isDeepEqual(left, right) {
275
+ return JSON.stringify(left) === JSON.stringify(right);
238
276
  }
239
277
 
240
278
  //#endregion
@@ -248,14 +286,12 @@ function buildPlainTextInsertBody(dataStream, options = {}) {
248
286
  *
249
287
  * @hideconstructor
250
288
  */
251
- var FDocumentParagraph = class extends FDocumentElement {
252
- constructor(body, bodyEdit, info, injector) {
253
- super(body, bodyEdit, info, injector);
254
- this.body = body;
255
- this.bodyEdit = bodyEdit;
256
- this.info = info;
257
- this.injector = injector;
258
- if (this.getType() !== DocumentBlockType.PARAGRAPH) throw new Error(`Element type is not a paragraph: ${this.getType()}`);
289
+ var FDocumentParagraph = class {
290
+ constructor(_document, _paragraphId, _segmentId = "", _injector) {
291
+ this._document = _document;
292
+ this._paragraphId = _paragraphId;
293
+ this._segmentId = _segmentId;
294
+ this._injector = _injector;
259
295
  }
260
296
  /**
261
297
  * Get the persisted paragraph id.
@@ -263,46 +299,52 @@ var FDocumentParagraph = class extends FDocumentElement {
263
299
  * @example
264
300
  * ```ts
265
301
  * const fDocument = univerAPI.getActiveDocument();
266
- * const fDocumentBody = fDocument.getBody();
267
- * const element = fDocumentBody.getElement(0);
268
- *
269
- * if (element?.isParagraph()) {
270
- * const paragraph = element.asParagraph();
271
- * console.log(paragraph.getParagraphId());
272
- * }
302
+ * const paragraph = fDocument.getParagraphs()[0];
303
+ * console.log(paragraph?.getId());
273
304
  * ```
274
305
  */
275
- getParagraphId() {
276
- return this.getKey();
306
+ getId() {
307
+ return this._paragraphId;
277
308
  }
278
309
  /**
279
- * Get the resolved paragraph info for this wrapper.
280
- * @returns {IFDocumentResolvedParagraph} The resolved paragraph info, including the paragraph object, its index, and its text range.
310
+ * Get the segment id of this paragraph.
311
+ * The main body paragraphs have an empty string segment id.
312
+ * The header and footer paragraphs have a non-empty string segment id.
313
+ * @returns {string} The segment id.
281
314
  * @example
282
315
  * ```ts
283
316
  * const fDocument = univerAPI.getActiveDocument();
284
- * const fDocumentBody = fDocument.getBody();
285
- * const element = fDocumentBody.getElement(0);
286
- *
287
- * if (element?.isParagraph()) {
288
- * const paragraph = element.asParagraph();
289
- * console.log(paragraph.getResolvedParagraphInfo());
290
- * }
317
+ * const paragraph = fDocument.getParagraphs()[0];
318
+ * console.log(paragraph?.getSegmentId());
319
+ * ```
320
+ */
321
+ getSegmentId() {
322
+ return this._segmentId;
323
+ }
324
+ /**
325
+ * Get this paragraph's metadata.
326
+ * @returns {IFDocumentParagraphInfo} The paragraph info.
327
+ * @example
328
+ * ```ts
329
+ * const fDocument = univerAPI.getActiveDocument();
330
+ * const paragraph = fDocument.getParagraphs()[0];
331
+ * console.log(paragraph?.getInfo());
291
332
  * ```
292
333
  */
293
- getResolvedParagraphInfo() {
294
- const { paragraphs = [] } = this._body.getBody();
334
+ getInfo() {
335
+ const body = this._document.getBody(this._segmentId);
336
+ const { paragraphs = [] } = body;
295
337
  const matches = paragraphs.map((paragraph, paragraphIndex) => ({
296
338
  paragraph,
297
339
  paragraphIndex
298
- })).filter(({ paragraph }) => paragraph.paragraphId === this.getKey());
299
- if (matches.length === 0) throw new Error(`Document paragraph with id ${this.getKey()} not found`);
300
- if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this.getKey()} found`);
340
+ })).filter(({ paragraph }) => paragraph.paragraphId === this._paragraphId);
341
+ if (matches.length === 0) throw new Error(`Document paragraph with id ${this._paragraphId} not found`);
342
+ if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this._paragraphId} found`);
301
343
  const { paragraph, paragraphIndex } = matches[0];
302
344
  return {
303
345
  paragraph,
304
346
  paragraphIndex,
305
- startOffset: paragraphIndex > 0 ? paragraphs[paragraphIndex - 1].startIndex + 1 : 0,
347
+ startOffset: getParagraphContentStartOffset(body, paragraph),
306
348
  endOffset: paragraph.startIndex
307
349
  };
308
350
  }
@@ -312,42 +354,46 @@ var FDocumentParagraph = class extends FDocumentElement {
312
354
  * @example
313
355
  * ```ts
314
356
  * const fDocument = univerAPI.getActiveDocument();
315
- * const fDocumentBody = fDocument.getBody();
316
- * const element = fDocumentBody.getElement(0);
317
- *
318
- * if (element?.isParagraph()) {
319
- * const paragraph = element.asParagraph();
320
- * const range = paragraph.getRange();
321
- * fDocumentBody.setTextStyle(range, { bl: 1 });
322
- * }
357
+ * const paragraph = fDocument.getParagraphs()[0];
358
+ * console.log(paragraph?.getRange());
323
359
  * ```
324
360
  */
325
361
  getRange() {
326
- const { startOffset, endOffset } = this.getResolvedParagraphInfo();
362
+ const { startOffset, endOffset } = this.getInfo();
327
363
  return {
328
364
  startOffset,
329
365
  endOffset,
330
- segmentId: this._body.getSegmentId()
366
+ segmentId: this._segmentId
331
367
  };
332
368
  }
333
369
  /**
370
+ * Returns an agent-friendly facade for reading and styling this paragraph's text.
371
+ * @returns {FDocumentTextRange} The paragraph text range, excluding the trailing paragraph break.
372
+ * @example
373
+ * ```ts
374
+ * const fDocument = univerAPI.getActiveDocument();
375
+ * const paragraph = fDocument?.findParagraphByText('Launch');
376
+ * const range = paragraph?.getTextRange();
377
+ * console.log(range?.describe());
378
+ * ```
379
+ */
380
+ getTextRange() {
381
+ const { startOffset, endOffset } = this.getInfo();
382
+ return this._injector.createInstance(FDocumentTextRange, this._document, startOffset, endOffset, this._segmentId, this._injector);
383
+ }
384
+ /**
334
385
  * Get this paragraph's plain text.
335
386
  * @returns {string} The paragraph text without the trailing paragraph break.
336
387
  * @example
337
388
  * ```ts
338
389
  * const fDocument = univerAPI.getActiveDocument();
339
- * const fDocumentBody = fDocument.getBody();
340
- * const element = fDocumentBody.getElement(0);
341
- *
342
- * if (element?.isParagraph()) {
343
- * const paragraph = element.asParagraph();
344
- * console.log(paragraph.getText());
345
- * }
390
+ * const paragraph = fDocument.getParagraphs()[0];
391
+ * console.log(paragraph?.getText());
346
392
  * ```
347
393
  */
348
394
  getText() {
349
- const { dataStream } = this._body.getBody();
350
- const { startOffset, endOffset } = this.getResolvedParagraphInfo();
395
+ const { dataStream } = this._document.getBody(this._segmentId);
396
+ const { startOffset, endOffset } = this.getInfo();
351
397
  return dataStream.slice(startOffset, endOffset);
352
398
  }
353
399
  /**
@@ -357,22 +403,18 @@ var FDocumentParagraph = class extends FDocumentElement {
357
403
  * @example
358
404
  * ```ts
359
405
  * const fDocument = univerAPI.getActiveDocument();
360
- * const fDocumentBody = fDocument.getBody();
361
- * const element = fDocumentBody.getElement(0);
362
- *
363
- * if (element?.isParagraph()) {
364
- * const paragraph = element.asParagraph();
365
- * const success = paragraph.setText('Updated title');
366
- * console.log(success ? 'Text updated' : 'Failed to update text');
367
- * }
406
+ * const paragraph = fDocument.getParagraphs()[0];
407
+ * paragraph?.setText('New text');
408
+ * console.log(paragraph?.getText());
368
409
  * ```
369
410
  */
370
411
  setText(text) {
371
- const { startOffset, endOffset } = this.getResolvedParagraphInfo();
372
- return this._bodyEdit.replaceRange({
412
+ const { startOffset, endOffset } = this.getInfo();
413
+ return replaceBodyRange({
373
414
  startOffset,
374
- endOffset
375
- }, buildPlainTextInsertBody(text));
415
+ endOffset,
416
+ segmentId: this._segmentId
417
+ }, buildPlainTextInsertBody(text), this._document.getDocumentDataModel(), this._injector);
376
418
  }
377
419
  /**
378
420
  * Append plain text before this paragraph's trailing paragraph break.
@@ -381,38 +423,52 @@ var FDocumentParagraph = class extends FDocumentElement {
381
423
  * @example
382
424
  * ```ts
383
425
  * const fDocument = univerAPI.getActiveDocument();
384
- * const fDocumentBody = fDocument.getBody();
385
- * const element = fDocumentBody.getElement(0);
386
- *
387
- * if (element?.isParagraph()) {
388
- * const paragraph = element.asParagraph();
389
- * const success = paragraph.appendText(' Appended text');
390
- * console.log(success ? 'Text appended' : 'Failed to append text');
391
- * }
426
+ * const paragraph = fDocument.getParagraphs()[0];
427
+ * paragraph?.appendText(' Appended text');
428
+ * console.log(paragraph?.getText());
392
429
  * ```
393
430
  */
394
431
  appendText(text) {
395
- const { endOffset } = this.getResolvedParagraphInfo();
396
- return this._body.insertText(endOffset, text);
432
+ const { endOffset } = this.getInfo();
433
+ return this._document.insertText(endOffset, text, this._segmentId);
397
434
  }
398
435
  /**
399
436
  * Apply paragraph style to a paragraph handle or text range.
437
+ * `style.textStyle.fs` is a font size in points (pt), not CSS pixels.
400
438
  * @param {IParagraphStyle} style The Univer paragraph style patch.
401
439
  * @returns {boolean} `true` if the style was applied.
402
440
  * @example
403
441
  * ```ts
404
442
  * const fDocument = univerAPI.getActiveDocument();
405
- * const fDocumentBody = fDocument.getBody();
406
- * const element = fDocumentBody.getElement(0);
407
- *
408
- * if (element?.isParagraph()) {
409
- * const paragraph = element.asParagraph();
410
- * paragraph.setStyle({ horizontalAlign: 2 });
411
- * }
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,
453
+ * });
454
+ * console.log(paragraph?.getInfo().paragraph.paragraphStyle);
412
455
  * ```
413
456
  */
414
457
  setStyle(style) {
415
- const { paragraph, endOffset } = this.getResolvedParagraphInfo();
458
+ const { paragraph, startOffset, endOffset } = this.getInfo();
459
+ let result = true;
460
+ if (style.textStyle && startOffset < endOffset) result = retainBodyRange({
461
+ startOffset,
462
+ 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);
416
472
  const updateBody = {
417
473
  dataStream: "",
418
474
  paragraphs: [{
@@ -425,10 +481,11 @@ var FDocumentParagraph = class extends FDocumentElement {
425
481
  }]
426
482
  };
427
483
  this._preserveExplicitParagraphIds(updateBody);
428
- return this._bodyEdit.retainRange({
484
+ return retainBodyRange({
429
485
  startOffset: endOffset,
430
- endOffset: endOffset + 1
431
- }, updateBody, UpdateDocsAttributeType.REPLACE);
486
+ endOffset: endOffset + 1,
487
+ segmentId: this._segmentId
488
+ }, updateBody, UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector) && result;
432
489
  }
433
490
  /**
434
491
  * Check whether this paragraph is a bullet, ordered, or checklist item.
@@ -436,17 +493,12 @@ var FDocumentParagraph = class extends FDocumentElement {
436
493
  * @example
437
494
  * ```ts
438
495
  * const fDocument = univerAPI.getActiveDocument();
439
- * const fDocumentBody = fDocument.getBody();
440
- * const element = fDocumentBody.getElement(0);
441
- *
442
- * if (element?.isParagraph()) {
443
- * const paragraph = element.asParagraph();
444
- * console.log(paragraph.isListItem() ? 'This is a list item' : 'This is not a list item');
445
- * }
496
+ * const paragraph = fDocument.getParagraphs()[0];
497
+ * console.log(paragraph?.isListItem());
446
498
  * ```
447
499
  */
448
500
  isListItem() {
449
- const { paragraph } = this.getResolvedParagraphInfo();
501
+ const { paragraph } = this.getInfo();
450
502
  return Boolean(paragraph.bullet);
451
503
  }
452
504
  /**
@@ -455,18 +507,13 @@ var FDocumentParagraph = class extends FDocumentElement {
455
507
  * @example
456
508
  * ```ts
457
509
  * const fDocument = univerAPI.getActiveDocument();
458
- * const fDocumentBody = fDocument.getBody();
459
- * const element = fDocumentBody.getElement(0);
460
- *
461
- * if (element?.isParagraph()) {
462
- * const paragraph = element.asParagraph();
463
- * console.log(paragraph.isTask() ? 'This is a task item' : 'This is not a task item');
464
- * }
510
+ * const paragraph = fDocument.getParagraphs()[0];
511
+ * console.log(paragraph?.isTask());
465
512
  * ```
466
513
  */
467
514
  isTask() {
468
515
  var _paragraph$bullet;
469
- const { paragraph } = this.getResolvedParagraphInfo();
516
+ const { paragraph } = this.getInfo();
470
517
  const listType = (_paragraph$bullet = paragraph.bullet) === null || _paragraph$bullet === void 0 ? void 0 : _paragraph$bullet.listType;
471
518
  return listType === PresetListType.CHECK_LIST || listType === PresetListType.CHECK_LIST_CHECKED;
472
519
  }
@@ -477,22 +524,17 @@ var FDocumentParagraph = class extends FDocumentElement {
477
524
  * @example
478
525
  * ```ts
479
526
  * const fDocument = univerAPI.getActiveDocument();
480
- * const fDocumentBody = fDocument.getBody();
481
- * const element = fDocumentBody.getElement(0);
527
+ * const paragraph = fDocument.getParagraphs()[0];
482
528
  *
483
- * if (element?.isParagraph()) {
484
- * const paragraph = element.asParagraph();
485
- *
486
- * if (paragraph.isTask()) {
487
- * const success = paragraph.setTaskChecked(true);
488
- * console.log(success ? 'Task checked' : 'Failed to check task');
489
- * }
529
+ * if (paragraph.isTask()) {
530
+ * const success = paragraph.setTaskChecked(true);
531
+ * console.log(success ? 'Task checked' : 'Failed to check task');
490
532
  * }
491
533
  * ```
492
534
  */
493
535
  setTaskChecked(checked) {
494
536
  if (!this.isTask()) return false;
495
- const { paragraph, endOffset } = this.getResolvedParagraphInfo();
537
+ const { paragraph, endOffset } = this.getInfo();
496
538
  const bullet = paragraph.bullet;
497
539
  const updateBody = {
498
540
  dataStream: "",
@@ -506,494 +548,488 @@ var FDocumentParagraph = class extends FDocumentElement {
506
548
  }]
507
549
  };
508
550
  this._preserveExplicitParagraphIds(updateBody);
509
- return this._bodyEdit.retainRange({
551
+ return retainBodyRange({
510
552
  startOffset: endOffset,
511
- endOffset: endOffset + 1
512
- }, updateBody, UpdateDocsAttributeType.REPLACE);
553
+ endOffset: endOffset + 1,
554
+ segmentId: this._segmentId
555
+ }, updateBody, UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector);
556
+ }
557
+ /**
558
+ * Remove this paragraph.
559
+ * @returns {boolean} `true` if the paragraph was removed.
560
+ * @example
561
+ * ```ts
562
+ * const fDocument = univerAPI.getActiveDocument();
563
+ * const paragraph = fDocument.getParagraphs()[0];
564
+ * const success = paragraph?.remove();
565
+ * console.log(success ? 'Paragraph removed' : 'Failed to remove paragraph');
566
+ * ```
567
+ */
568
+ remove() {
569
+ const { startOffset, endOffset } = this.getInfo();
570
+ return this._document.deleteRange({
571
+ startOffset,
572
+ endOffset: endOffset + 1,
573
+ segmentId: this._segmentId
574
+ });
513
575
  }
514
576
  _preserveExplicitParagraphIds(body) {
515
577
  body[RESTORE_INSERTED_PARAGRAPH_IDS] = true;
516
578
  }
517
579
  };
518
- var FDocumentParagraphMixin = class extends FDocumentElement {
519
- asParagraph() {
520
- if (this.getType() !== DocumentBlockType.PARAGRAPH) throw new Error(`Element type is not a paragraph: ${this.getType()}`);
521
- return this._injector.createInstance(FDocumentParagraph, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
522
- }
523
- };
524
- FDocumentElement.extend(FDocumentParagraphMixin);
525
-
526
- //#endregion
527
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
528
- function _typeof(o) {
529
- "@babel/helpers - typeof";
530
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
531
- return typeof o;
532
- } : function(o) {
533
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
534
- }, _typeof(o);
580
+ function isParagraphFacade(value) {
581
+ if (typeof value !== "object" || value === null) return false;
582
+ return typeof value.getId === "function" && typeof value.getSegmentId === "function" && typeof value.getInfo === "function" && typeof value.getRange === "function";
535
583
  }
536
584
 
537
585
  //#endregion
538
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPrimitive.js
539
- function toPrimitive(t, r) {
540
- if ("object" != _typeof(t) || !t) return t;
541
- var e = t[Symbol.toPrimitive];
542
- if (void 0 !== e) {
543
- var i = e.call(t, r || "default");
544
- if ("object" != _typeof(i)) return i;
545
- throw new TypeError("@@toPrimitive must return a primitive value.");
586
+ //#region src/facade/f-document-section.ts
587
+ /** Error thrown when traditional section APIs are used to mutate a modern document. */
588
+ var DocsSectionUnsupportedDocumentFlavorError = class extends Error {
589
+ constructor() {
590
+ super("Section column APIs are supported only in traditional documents. Use ColumnGroup APIs for modern documents.");
591
+ this.name = "DocsSectionUnsupportedDocumentFlavorError";
546
592
  }
547
- return ("string" === r ? String : Number)(t);
548
- }
549
-
550
- //#endregion
551
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
552
- function toPropertyKey(t) {
553
- var i = toPrimitive(t, "string");
554
- return "symbol" == _typeof(i) ? i : i + "";
555
- }
556
-
557
- //#endregion
558
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
559
- function _defineProperty(e, r, t) {
560
- return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
561
- value: t,
562
- enumerable: !0,
563
- configurable: !0,
564
- writable: !0
565
- }) : e[r] = t, e;
566
- }
567
-
568
- //#endregion
569
- //#region src/facade/f-document-body.ts
593
+ };
570
594
  /**
571
- * A Facade API object bounded to a document body or header/footer segment.
572
- * It provides Google Docs-like element access and range editing methods.
573
- *
574
- * Paragraph elements use their persisted `paragraphId`. Tables, block ranges, and
575
- * custom blocks use their persisted ids.
576
- *
577
- * @hideconstructor
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
+ * ```
578
604
  */
579
- var FDocumentBody = class {
580
- constructor(_documentDataModel, _injector, _segmentId = "") {
581
- this._documentDataModel = _documentDataModel;
605
+ var FDocumentSection = class {
606
+ constructor(_document, _sectionId, _injector) {
607
+ this._document = _document;
608
+ this._sectionId = _sectionId;
582
609
  this._injector = _injector;
583
- this._segmentId = _segmentId;
584
- _defineProperty(this, "_bodyEdit", void 0);
585
- this._bodyEdit = {
586
- replaceRange: this._replaceBodyRange.bind(this),
587
- retainRange: this._retainBodyRange.bind(this)
588
- };
589
610
  }
590
611
  /**
591
- * Get the segment id of this document body facade.
592
- * The main body has an empty string segment id.
593
- * The header and footer FDocumentBody instances have their respective segment ids.
594
- * @returns {string} The segment id of this document body facade.
612
+ * Returns the persisted section id.
595
613
  * @example
596
614
  * ```ts
597
615
  * const fDocument = univerAPI.getActiveDocument();
598
- * const fDocumentBody = fDocument.getBody();
599
- * console.log(fDocumentBody.getSegmentId());
616
+ * console.log(fDocument?.getSection(0)?.getId());
600
617
  * ```
601
618
  */
602
- getSegmentId() {
603
- return this._segmentId;
619
+ getId() {
620
+ return this._sectionId;
604
621
  }
605
622
  /**
606
- * Get the underlying document body snapshot.
607
- * @returns {IDocumentBody} The document body snapshot.
623
+ * Returns the current zero-based section index.
608
624
  * @example
609
625
  * ```ts
610
626
  * const fDocument = univerAPI.getActiveDocument();
611
- * const fDocumentBody = fDocument.getBody();
612
- * console.log(fDocumentBody.getBody());
627
+ * console.log(fDocument?.getSection(0)?.getIndex());
613
628
  * ```
614
629
  */
615
- getBody() {
616
- const body = this._documentDataModel.getSelfOrHeaderFooterModel(this._segmentId).getBody();
617
- if (!body) throw new Error("The document body is empty");
618
- return body;
630
+ getIndex() {
631
+ return this._resolve().index;
619
632
  }
620
633
  /**
621
- * Get a list of top-level child elements in the body.
622
- * @returns {FDocumentElement[]} The list of top-level document elements.
634
+ * Returns the section break snapshot that terminates this section.
623
635
  * @example
624
636
  * ```ts
625
637
  * const fDocument = univerAPI.getActiveDocument();
626
- * const fDocumentBody = fDocument.getBody();
627
- * const elements = fDocumentBody.getElements();
628
- * console.log(elements);
638
+ * console.log(fDocument?.getSection(0)?.getConfig());
629
639
  * ```
630
640
  */
631
- getElements() {
632
- return this._getChildren().map((child) => {
633
- return this._injector.createInstance(FDocumentElement, this, this._bodyEdit, child, this._injector);
634
- });
641
+ getConfig() {
642
+ const { sectionBreak } = this._resolve();
643
+ return Tools.deepClone(sectionBreak);
635
644
  }
636
645
  /**
637
- * Get a top-level child element by child index.
638
- * @param {number} index The zero-based child index.
639
- * @returns {FDocumentElement} The top-level child element wrapper.
646
+ * Returns the section content range, excluding its terminating section-break token.
640
647
  * @example
641
648
  * ```ts
642
649
  * const fDocument = univerAPI.getActiveDocument();
643
- * const fDocumentBody = fDocument.getBody();
644
- * const element = fDocumentBody.getElement(0);
645
- * console.log(element);
650
+ * console.log(fDocument?.getSection(0)?.getRange());
646
651
  * ```
647
652
  */
648
- getElement(index) {
649
- var _this$getElements$ind;
650
- return (_this$getElements$ind = this.getElements()[index]) !== null && _this$getElements$ind !== void 0 ? _this$getElements$ind : null;
653
+ 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
+ };
651
661
  }
652
662
  /**
653
- * Get the current child index of an element handle.
654
- * The index is resolved from the element key, so a paragraph handle keeps pointing
655
- * to the same paragraph after facade edits insert content before it.
656
- * @param {FDocumentElement} element The element handle to locate.
657
- * @returns {number} The current zero-based child index.
663
+ * Returns the explicit columns. An empty array means the normal single-column layout.
664
+ * Column widths and trailing spaces are in points (pt).
658
665
  * @example
659
666
  * ```ts
660
667
  * const fDocument = univerAPI.getActiveDocument();
661
- * const fDocumentBody = fDocument.getBody();
662
- * const element = fDocumentBody.getElement(0);
663
- * console.log(fDocumentBody.getElementIndex(element));
668
+ * console.log(fDocument?.getSection(0)?.getColumns());
664
669
  * ```
665
670
  */
666
- getElementIndex(element) {
667
- const { type, key } = element.getResolvedInfo();
668
- const index = this._getChildren().findIndex((child) => child.type === type && child.key === key);
669
- if (index < 0) throw new Error("Doc element is stale");
670
- return index;
671
+ 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 : []);
671
674
  }
672
675
  /**
673
- * Insert plain text at a document body offset.
674
- * @param {number} index The zero-based insertion offset.
675
- * @param {string} text The plain text to insert.
676
- * @returns {boolean} `true` if the edit was applied.
676
+ * Returns a compact serializable section summary.
677
677
  * @example
678
678
  * ```ts
679
679
  * const fDocument = univerAPI.getActiveDocument();
680
- * const fDocumentBody = fDocument.getBody();
681
- * fDocumentBody.insertText(0, 'Hello ');
680
+ * console.log(fDocument?.getSection(0)?.describe());
682
681
  * ```
683
682
  */
684
- insertText(index, text) {
685
- return this._replaceBodyRange({
686
- startOffset: index,
687
- endOffset: index
688
- }, buildPlainTextInsertBody(text));
683
+ describe() {
684
+ var _config$columnPropert, _config$columnSeparat, _config$sectionType;
685
+ const config = this.getConfig();
686
+ const columns = (_config$columnPropert = config.columnProperties) !== null && _config$columnPropert !== void 0 ? _config$columnPropert : [];
687
+ const headerFooter = {
688
+ defaultHeader: this._describeHeaderFooterReference("header", "default"),
689
+ defaultFooter: this._describeHeaderFooterReference("footer", "default"),
690
+ firstHeader: this._describeHeaderFooterReference("header", "first"),
691
+ firstFooter: this._describeHeaderFooterReference("footer", "first"),
692
+ evenHeader: this._describeHeaderFooterReference("header", "even"),
693
+ evenFooter: this._describeHeaderFooterReference("footer", "even")
694
+ };
695
+ return {
696
+ sectionId: this._sectionId,
697
+ index: this.getIndex(),
698
+ range: this.getRange(),
699
+ columnCount: columns.length || 1,
700
+ columns: Tools.deepClone(columns),
701
+ columnSeparatorType: (_config$columnSeparat = config.columnSeparatorType) !== null && _config$columnSeparat !== void 0 ? _config$columnSeparat : ColumnSeparatorType.NONE,
702
+ sectionType: (_config$sectionType = config.sectionType) !== null && _config$sectionType !== void 0 ? _config$sectionType : SectionType.SECTION_TYPE_UNSPECIFIED,
703
+ headerFooter,
704
+ config
705
+ };
689
706
  }
690
707
  /**
691
- * Apply text style to a body range.
692
- * @param {IFDocumentTextRange} range The range to style.
693
- * @param {ITextStyle} style The Univer text style patch.
694
- * @returns {boolean} `true` if the style was applied.
708
+ * Sets equal or explicitly sized columns for this traditional section.
709
+ * Use `columnCount = 1` to restore normal single-column layout.
710
+ * `gap` and `widths` are in points (pt).
695
711
  * @example
696
712
  * ```ts
697
713
  * const fDocument = univerAPI.getActiveDocument();
698
- * const fDocumentBody = fDocument.getBody();
699
- * fDocumentBody.setTextStyle({ startOffset: 0, endOffset: 5 }, { bl: 1 });
714
+ * if (fDocument && !fDocument.isModern()) {
715
+ * fDocument.getSection(0)?.setColumns(2, { gap: 18, separator: true });
716
+ * }
700
717
  * ```
701
718
  */
702
- setTextStyle(range, style) {
703
- const updateBody = {
704
- dataStream: "",
705
- textRuns: [{
706
- st: 0,
707
- ed: range.endOffset - range.startOffset,
708
- ts: style
709
- }]
710
- };
711
- return this._retainBodyRange(range, updateBody, UpdateDocsAttributeType.COVER);
719
+ setColumns(columnCount, options = {}) {
720
+ var _options$gap, _options$separator;
721
+ this._assertTraditionalDocument();
722
+ if (!Number.isInteger(columnCount) || columnCount < 1) throw new RangeError("Section column count must be a positive integer.");
723
+ if (options.widths && options.widths.length !== columnCount) throw new RangeError("Section column widths must match the column count.");
724
+ const gap = Math.max(0, (_options$gap = options.gap) !== null && _options$gap !== void 0 ? _options$gap : 18);
725
+ const config = this.getConfig();
726
+ const columns = createSectionColumnProperties(this._document.getDocumentDataModel().getSnapshot().documentStyle, config, columnCount, gap, options.widths);
727
+ 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;
728
+ return this._update({
729
+ columnProperties: columns,
730
+ columnSeparatorType: separator,
731
+ ...options.sectionType == null ? {} : { sectionType: options.sectionType }
732
+ });
712
733
  }
713
734
  /**
714
- * Insert a plain-text paragraph before the paragraph at the given paragraph index.
715
- * @param {number} index The zero-based paragraph insertion index.
716
- * @param {string} text The paragraph text. Defaults to an empty paragraph.
717
- * @returns {FDocumentParagraph} The inserted paragraph wrapper.
735
+ * Sets explicit OOXML-compatible column width and trailing-space values in points (pt).
718
736
  * @example
719
737
  * ```ts
720
738
  * const fDocument = univerAPI.getActiveDocument();
721
- * const fDocumentBody = fDocument.getBody();
722
- * const paragraph = fDocumentBody.insertParagraph(0, 'Document title');
723
- * paragraph.appendText(' suffix');
739
+ * if (fDocument && !fDocument.isModern()) {
740
+ * fDocument.getSection(0)?.setColumnProperties([
741
+ * { width: 240, paddingEnd: 18 },
742
+ * { width: 240, paddingEnd: 0 },
743
+ * ], univerAPI.Enum.ColumnSeparatorType.BETWEEN_EACH_COLUMN);
744
+ * }
724
745
  * ```
725
746
  */
726
- insertParagraph(index, text = "") {
727
- var _paragraphs;
728
- const offset = this._getParagraphInsertOffset(index);
729
- if (!this._replaceBodyRange({
730
- startOffset: offset,
731
- endOffset: offset
732
- }, buildPlainTextInsertBody(`${text}\r`))) throw new Error("Failed to insert paragraph.");
733
- const { paragraphs = [] } = this.getBody();
734
- const paragraph = paragraphs[index];
735
- if (!paragraph) throw new Error("Failed to insert paragraph.");
736
- const info = this._resolveParagraphInfo(paragraph, index, (_paragraphs = paragraphs[index - 1]) === null || _paragraphs === void 0 ? void 0 : _paragraphs.startIndex);
737
- return this._injector.createInstance(FDocumentParagraph, this, this._bodyEdit, info, this._injector);
747
+ setColumnProperties(columns, separator = ColumnSeparatorType.NONE) {
748
+ this._assertTraditionalDocument();
749
+ if (columns.some(({ width, paddingEnd }) => width < 0 || paddingEnd < 0)) throw new RangeError("Section column widths and padding must be non-negative.");
750
+ return this._update({
751
+ columnProperties: Tools.deepClone(columns),
752
+ columnSeparatorType: separator
753
+ });
738
754
  }
739
755
  /**
740
- * Append a plain-text paragraph at the end of the body.
741
- * @param {string} text The paragraph text. Defaults to an empty paragraph.
742
- * @returns {FDocumentParagraph} The appended paragraph wrapper.
756
+ * Sets how the next section begins.
743
757
  * @example
744
758
  * ```ts
745
759
  * const fDocument = univerAPI.getActiveDocument();
746
- * const fDocumentBody = fDocument.getBody();
747
- * const paragraph = fDocumentBody.appendParagraph('Summary');
748
- * console.log(paragraph.getText());
760
+ * if (fDocument && !fDocument.isModern()) {
761
+ * fDocument.getSection(0)?.setSectionType(univerAPI.Enum.SectionType.NEXT_PAGE);
762
+ * }
749
763
  * ```
750
764
  */
751
- appendParagraph(text = "") {
752
- const { paragraphs = [] } = this.getBody();
753
- return this.insertParagraph(paragraphs.length, text);
765
+ setSectionType(sectionType) {
766
+ this._assertTraditionalDocument();
767
+ return this._update({ sectionType });
754
768
  }
755
769
  /**
756
- * Delete a range from the body.
757
- * @param {IFDocumentTextRange} range The text range to delete.
758
- * @returns {boolean} `true` if the range was deleted.
770
+ * Ensures a header segment linked specifically to this section.
759
771
  * @example
760
772
  * ```ts
761
773
  * const fDocument = univerAPI.getActiveDocument();
762
- * const fDocumentBody = fDocument.getBody();
763
- * fDocumentBody.deleteRange({ startOffset: 0, endOffset: 5 });
774
+ * if (fDocument && !fDocument.isModern()) {
775
+ * const segmentId = fDocument.getSection(0)?.ensureHeader();
776
+ * if (segmentId) {
777
+ * fDocument.insertText(0, 'Quarterly report', segmentId);
778
+ * }
779
+ * }
764
780
  * ```
765
781
  */
766
- deleteRange(range) {
767
- return this._replaceBodyRange(range, { dataStream: "" });
782
+ ensureHeader(variant = "default") {
783
+ return this._ensureHeaderFooter("header", variant);
768
784
  }
769
785
  /**
770
- * Remove a paragraph by paragraph id.
771
- * @param {FDocumentParagraph} paragraph The paragraph handle to remove.
772
- * @returns {boolean} `true` if the paragraph was removed.
786
+ * Ensures a footer segment linked specifically to this section.
773
787
  * @example
774
788
  * ```ts
775
789
  * const fDocument = univerAPI.getActiveDocument();
776
- * const fDocumentBody = fDocument.getBody();
777
- * const element = fDocumentBody.getElement(0);
778
- *
779
- * if (element?.isParagraph()) {
780
- * const paragraph = element.asParagraph();
781
- * const removed = fDocumentBody.removeParagraph(paragraph);
782
- * console.log(removed ? 'Paragraph removed' : 'Failed to remove paragraph');
790
+ * if (fDocument && !fDocument.isModern()) {
791
+ * const segmentId = fDocument.getSection(0)?.ensureFooter('first');
792
+ * if (segmentId) {
793
+ * fDocument.insertText(0, 'Confidential', segmentId);
794
+ * }
783
795
  * }
784
796
  * ```
785
797
  */
786
- removeParagraph(paragraph) {
787
- const { startOffset, endOffset } = paragraph.getResolvedParagraphInfo();
788
- return this.deleteRange({
789
- startOffset,
790
- endOffset: endOffset + 1
791
- });
798
+ ensureFooter(variant = "default") {
799
+ return this._ensureHeaderFooter("footer", variant);
792
800
  }
793
801
  /**
794
- * Remove a callout, quote, or code block range and its content.
795
- * @param {FDocumentBlockRange} blockRange The block range handle to remove.
796
- * @returns {boolean} `true` if the block range content was removed.
802
+ * Returns the effective header id after resolving links to previous sections.
797
803
  * @example
798
804
  * ```ts
799
805
  * const fDocument = univerAPI.getActiveDocument();
800
- * const fDocumentBody = fDocument.getBody();
801
- * const element = fDocumentBody.getElement(0);
802
- *
803
- * if (element?.isBlockRange()) {
804
- * const blockRange = element.asBlockRange();
805
- * const removed = fDocumentBody.removeBlockRange(blockRange);
806
- * console.log(removed ? 'Block range removed' : 'Failed to remove block range');
806
+ * console.log(fDocument?.getSection(0)?.getHeaderId('default'));
807
+ * ```
808
+ */
809
+ getHeaderId(variant = "default") {
810
+ var _this$_getHeaderFoote;
811
+ return (_this$_getHeaderFoote = this._getHeaderFooterReference("header", variant).segmentId) !== null && _this$_getHeaderFoote !== void 0 ? _this$_getHeaderFoote : null;
812
+ }
813
+ /**
814
+ * Returns the effective footer id after resolving links to previous sections.
815
+ * @example
816
+ * ```ts
817
+ * const fDocument = univerAPI.getActiveDocument();
818
+ * console.log(fDocument?.getSection(0)?.getFooterId('first'));
819
+ * ```
820
+ */
821
+ getFooterId(variant = "default") {
822
+ var _this$_getHeaderFoote2;
823
+ return (_this$_getHeaderFoote2 = this._getHeaderFooterReference("footer", variant).segmentId) !== null && _this$_getHeaderFoote2 !== void 0 ? _this$_getHeaderFoote2 : null;
824
+ }
825
+ /**
826
+ * Whether this header variant inherits the previous section's reference.
827
+ * @example
828
+ * ```ts
829
+ * const fDocument = univerAPI.getActiveDocument();
830
+ * console.log(fDocument?.getSection(1)?.isHeaderLinkedToPrevious());
831
+ * ```
832
+ */
833
+ isHeaderLinkedToPrevious(variant = "default") {
834
+ return this._getHeaderFooterReference("header", variant).linkedToPrevious;
835
+ }
836
+ /**
837
+ * Whether this footer variant inherits the previous section's reference.
838
+ * @example
839
+ * ```ts
840
+ * const fDocument = univerAPI.getActiveDocument();
841
+ * console.log(fDocument?.getSection(1)?.isFooterLinkedToPrevious('even'));
842
+ * ```
843
+ */
844
+ isFooterLinkedToPrevious(variant = "default") {
845
+ return this._getHeaderFooterReference("footer", variant).linkedToPrevious;
846
+ }
847
+ /**
848
+ * Links or unlinks this header variant. Unlinking clones the inherited header.
849
+ * @example
850
+ * ```ts
851
+ * const fDocument = univerAPI.getActiveDocument();
852
+ * if (fDocument && !fDocument.isModern()) {
853
+ * fDocument.getSection(1)?.setHeaderLinkedToPrevious(false, 'default');
807
854
  * }
808
855
  * ```
809
856
  */
810
- removeBlockRange(blockRange) {
811
- const { startIndex, endIndex } = blockRange.getBlockRange();
812
- return this.deleteRange({
813
- startOffset: startIndex,
814
- endOffset: endIndex + 1
815
- });
857
+ setHeaderLinkedToPrevious(linkedToPrevious, variant = "default") {
858
+ return this._setHeaderFooterLinkedToPrevious("header", variant, linkedToPrevious);
816
859
  }
817
860
  /**
818
- * Remove a table marker and its content range.
819
- * @returns {boolean} `true` if the table range was removed.
861
+ * Links or unlinks this footer variant. Unlinking clones the inherited footer.
820
862
  * @example
821
863
  * ```ts
822
864
  * const fDocument = univerAPI.getActiveDocument();
823
- * const fDocumentBody = fDocument.getBody();
824
- * const element = fDocumentBody.getElement(0);
825
- *
826
- * if (element?.isTable()) {
827
- * const table = element.asTable();
828
- * const removed = fDocumentBody.removeTable(table);
829
- * console.log(removed ? 'Table removed' : 'Failed to remove table');
865
+ * if (fDocument && !fDocument.isModern()) {
866
+ * fDocument.getSection(1)?.setFooterLinkedToPrevious(true, 'even');
830
867
  * }
831
868
  * ```
832
869
  */
833
- removeTable(table) {
834
- const { startIndex, endIndex } = table.getTable();
835
- return this.deleteRange({
836
- startOffset: startIndex,
837
- endOffset: endIndex + 1
838
- });
870
+ setFooterLinkedToPrevious(linkedToPrevious, variant = "default") {
871
+ return this._setHeaderFooterLinkedToPrevious("footer", variant, linkedToPrevious);
839
872
  }
840
873
  /**
841
- * Remove a custom block marker and its placeholder character.
842
- * @param {FDocumentCustomBlock} customBlock The custom block handle to remove.
843
- * @returns {boolean} `true` if the custom block placeholder was removed.
874
+ * Updates header/footer switches and margins on this section break.
875
+ * `marginHeader` and `marginFooter` are in points (pt).
844
876
  * @example
845
877
  * ```ts
846
878
  * const fDocument = univerAPI.getActiveDocument();
847
- * const fDocumentBody = fDocument.getBody();
848
- * const element = fDocumentBody.getElement(0);
849
- *
850
- * if (element?.isCustomBlock()) {
851
- * const customBlock = element.asCustomBlock();
852
- * const removed = fDocumentBody.removeCustomBlock(customBlock);
853
- * console.log(removed ? 'Custom block removed' : 'Failed to remove custom block');
879
+ * if (fDocument && !fDocument.isModern()) {
880
+ * fDocument.getSection(0)?.setHeaderFooterOptions({
881
+ * marginHeader: 36,
882
+ * marginFooter: 36,
883
+ * useFirstPageHeaderFooter: univerAPI.Enum.BooleanNumber.TRUE,
884
+ * });
854
885
  * }
855
886
  * ```
856
887
  */
857
- removeCustomBlock(customBlock) {
858
- const { startIndex } = customBlock.getCustomBlock();
859
- return this.deleteRange({
860
- startOffset: startIndex,
861
- endOffset: startIndex + 1
862
- });
888
+ setHeaderFooterOptions(options) {
889
+ this._assertTraditionalDocument();
890
+ return this._update(options);
863
891
  }
864
892
  /**
865
- * Resolve an element key to its current child metadata.
866
- * @param {FDocumentElement} element The element handle to resolve.
867
- * @returns {IFDocumentElementInfo} The current child metadata used by the facade.
893
+ * Deletes this section break. The final top-level section break cannot be removed.
868
894
  * @example
869
895
  * ```ts
870
896
  * const fDocument = univerAPI.getActiveDocument();
871
- * const fDocumentBody = fDocument.getBody();
872
- * const element = fDocumentBody.getElement(0);
873
- * const resolved = fDocumentBody.resolveElement(element);
874
- * console.log(resolved);
875
- * ```
876
- */
877
- resolveElement(element) {
878
- const { type, key } = element.getResolvedInfo();
879
- const child = this._getChildren().find((item) => item.type === type && item.key === key);
880
- if (!child) throw new Error("Doc element is stale");
881
- return child;
882
- }
883
- _getChildren() {
884
- const { paragraphs, blockRanges, tables, customBlocks } = this.getBody();
885
- const children = [];
886
- if (paragraphs) for (let i = 0; i < paragraphs.length; i++) {
887
- var _paragraphs2;
888
- const paragraph = paragraphs[i];
889
- const info = this._resolveParagraphInfo(paragraph, i, (_paragraphs2 = paragraphs[i - 1]) === null || _paragraphs2 === void 0 ? void 0 : _paragraphs2.startIndex);
890
- children.push(info);
891
- }
892
- if (blockRanges) for (let i = 0; i < blockRanges.length; i++) {
893
- const blockRange = blockRanges[i];
894
- children.push({
895
- type: DocumentBlockType.BLOCK_RANGE,
896
- key: blockRange.blockId,
897
- position: blockRange.startIndex,
898
- priority: 0
899
- });
900
- }
901
- if (tables) for (let i = 0; i < tables.length; i++) {
902
- const table = tables[i];
903
- children.push({
904
- type: DocumentBlockType.TABLE,
905
- key: table.tableId,
906
- position: table.startIndex,
907
- priority: 1
908
- });
909
- }
910
- if (customBlocks) for (let i = 0; i < customBlocks.length; i++) {
911
- const customBlock = customBlocks[i];
912
- children.push({
913
- type: DocumentBlockType.CUSTOM_BLOCK,
914
- key: customBlock.blockId,
915
- position: customBlock.startIndex,
916
- priority: 2
917
- });
918
- }
919
- return children.sort((a, b) => a.position - b.position || a.priority - b.priority);
897
+ * if (fDocument && !fDocument.isModern()) {
898
+ * const sections = fDocument.getSections();
899
+ * if (sections.length > 1) {
900
+ * sections[0].remove();
901
+ * }
902
+ * }
903
+ * ```
904
+ */
905
+ remove() {
906
+ this._assertTraditionalDocument();
907
+ return this._injector.get(ICommandService).syncExecuteCommand(DeleteDocumentSectionBreakCommand.id, {
908
+ unitId: this._document.getId(),
909
+ sectionId: this._sectionId
910
+ });
920
911
  }
921
- _resolveParagraphInfo(paragraph, paragraphIndex, previousParagraphStartIndex) {
912
+ _update(patch) {
913
+ const { sectionId: _sectionId, startIndex: _startIndex, ...config } = patch;
914
+ return this._injector.get(ICommandService).syncExecuteCommand(UpdateDocumentSectionCommand.id, {
915
+ unitId: this._document.getId(),
916
+ updates: [{
917
+ sectionId: this._sectionId,
918
+ config
919
+ }]
920
+ });
921
+ }
922
+ _ensureHeaderFooter(kind, variant) {
923
+ this._assertTraditionalDocument();
924
+ const { index } = this._resolve();
925
+ const existing = this.getConfig()[getSectionHeaderFooterReferenceKey(kind, variant)];
926
+ if (typeof existing === "string" && existing) return existing;
927
+ if (index > 0) {
928
+ const segmentId = generateRandomId(6);
929
+ if (!this._injector.get(ICommandService).syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
930
+ unitId: this._document.getId(),
931
+ sectionId: this._sectionId,
932
+ kind,
933
+ variant,
934
+ linkedToPrevious: false,
935
+ segmentId
936
+ })) throw new Error(`Failed to create section ${kind}.`);
937
+ return segmentId;
938
+ }
939
+ const types = {
940
+ default: kind === "header" ? HeaderFooterType.DEFAULT_HEADER : HeaderFooterType.DEFAULT_FOOTER,
941
+ first: kind === "header" ? HeaderFooterType.FIRST_PAGE_HEADER : HeaderFooterType.FIRST_PAGE_FOOTER,
942
+ even: kind === "header" ? HeaderFooterType.EVEN_PAGE_HEADER : HeaderFooterType.EVEN_PAGE_FOOTER
943
+ };
944
+ const segmentId = generateRandomId(6);
945
+ if (!this._injector.get(ICommandService).syncExecuteCommand(CreateHeaderFooterCommand.id, {
946
+ unitId: this._document.getId(),
947
+ segmentId,
948
+ createType: types[variant],
949
+ sectionId: this._sectionId
950
+ })) throw new Error(`Failed to create section ${kind}.`);
951
+ return segmentId;
952
+ }
953
+ _getHeaderFooterReference(kind, variant) {
954
+ const { index } = this._resolve();
955
+ return resolveSectionHeaderFooterReference(this._document.getDocumentDataModel().getSnapshot().documentStyle, getTopLevelSectionBreaks(this._document.getBody()), index, getSectionHeaderFooterReferenceKey(kind, variant));
956
+ }
957
+ _describeHeaderFooterReference(kind, variant) {
958
+ var _reference$segmentId;
959
+ const reference = this._getHeaderFooterReference(kind, variant);
922
960
  return {
923
- type: DocumentBlockType.PARAGRAPH,
924
- key: this._getParagraphId(paragraph, paragraphIndex),
925
- position: paragraphIndex > 0 ? previousParagraphStartIndex + 1 : 0,
926
- priority: 3
961
+ segmentId: (_reference$segmentId = reference.segmentId) !== null && _reference$segmentId !== void 0 ? _reference$segmentId : null,
962
+ linkedToPrevious: reference.linkedToPrevious
927
963
  };
928
964
  }
929
- _getParagraphId(paragraph, paragraphIndex) {
930
- if (!paragraph) throw new Error(`Paragraph index ${paragraphIndex} is out of range.`);
931
- if (!paragraph.paragraphId) throw new Error(`Paragraph at index ${paragraphIndex} is missing paragraphId.`);
932
- return paragraph.paragraphId;
933
- }
934
- _getParagraphInsertOffset(index) {
935
- if (index <= 0) return 0;
936
- const { dataStream, paragraphs = [] } = this.getBody();
937
- if (paragraphs.length === 0) return Math.max(0, dataStream.length - 1);
938
- if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
939
- return paragraphs[index - 1].startIndex + 1;
940
- }
941
- _replaceBodyRange(range, insertBody) {
942
- const { startOffset, endOffset } = range;
943
- const textX = new TextX();
944
- if (startOffset > 0) textX.push({
945
- t: TextXActionType.RETAIN,
946
- len: startOffset
947
- });
948
- if (endOffset > startOffset) textX.push({
949
- t: TextXActionType.DELETE,
950
- len: endOffset - startOffset
951
- });
952
- if (insertBody.dataStream.length > 0) textX.push({
953
- t: TextXActionType.INSERT,
954
- body: insertBody,
955
- len: insertBody.dataStream.length
956
- });
957
- return this._executeTextX(textX);
958
- }
959
- _retainBodyRange(range, body, coverType) {
960
- var _body$textRuns;
961
- if (((_body$textRuns = body.textRuns) === null || _body$textRuns === void 0 ? void 0 : _body$textRuns.length) && this.getBody().textRuns == null) this._ensureTextRuns();
962
- const textX = new TextX();
963
- if (range.startOffset > 0) textX.push({
964
- t: TextXActionType.RETAIN,
965
- len: range.startOffset
965
+ _setHeaderFooterLinkedToPrevious(kind, variant, linkedToPrevious) {
966
+ this._assertTraditionalDocument();
967
+ return this._injector.get(ICommandService).syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
968
+ unitId: this._document.getId(),
969
+ sectionId: this._sectionId,
970
+ kind,
971
+ variant,
972
+ linkedToPrevious,
973
+ ...linkedToPrevious ? {} : { segmentId: generateRandomId(6) }
966
974
  });
967
- textX.push({
968
- t: TextXActionType.RETAIN,
969
- body,
970
- coverType,
971
- len: range.endOffset - range.startOffset
972
- });
973
- return this._executeTextX(textX);
974
975
  }
975
- _ensureTextRuns() {
976
- const actions = JSONX.getInstance().replaceOp([...getRichTextEditPath(this._documentDataModel, this._segmentId), "textRuns"], void 0, []);
977
- this._injector.get(ICommandService).syncExecuteCommand(RichTextEditingMutation.id, {
978
- unitId: this._documentDataModel.getUnitId(),
979
- segmentId: this._segmentId,
980
- actions,
981
- textRanges: [],
982
- isEditing: false
983
- });
976
+ _assertTraditionalDocument() {
977
+ if (this._document.getDocumentDataModel().getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
984
978
  }
985
- _executeTextX(textX) {
986
- const actions = JSONX.getInstance().editOp(textX.serialize(), getRichTextEditPath(this._documentDataModel, this._segmentId));
987
- return this._injector.get(ICommandService).syncExecuteCommand(RichTextEditingMutation.id, {
988
- unitId: this._documentDataModel.getUnitId(),
989
- segmentId: this._segmentId,
990
- actions,
991
- textRanges: [],
992
- isEditing: false
993
- }) !== false;
979
+ _resolve() {
980
+ this._assertTraditionalDocument();
981
+ const sectionBreaks = getTopLevelSectionBreaks(this._document.getBody());
982
+ const index = sectionBreaks.findIndex((section) => section.sectionId === this._sectionId);
983
+ if (index < 0) throw new Error(`Document section with id ${this._sectionId} not found.`);
984
+ return {
985
+ index,
986
+ sectionBreak: sectionBreaks[index]
987
+ };
994
988
  }
995
989
  };
996
990
 
991
+ //#endregion
992
+ //#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
993
+ function _typeof(o) {
994
+ "@babel/helpers - typeof";
995
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
996
+ return typeof o;
997
+ } : function(o) {
998
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
999
+ }, _typeof(o);
1000
+ }
1001
+
1002
+ //#endregion
1003
+ //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPrimitive.js
1004
+ function toPrimitive(t, r) {
1005
+ if ("object" != _typeof(t) || !t) return t;
1006
+ var e = t[Symbol.toPrimitive];
1007
+ if (void 0 !== e) {
1008
+ var i = e.call(t, r || "default");
1009
+ if ("object" != _typeof(i)) return i;
1010
+ throw new TypeError("@@toPrimitive must return a primitive value.");
1011
+ }
1012
+ return ("string" === r ? String : Number)(t);
1013
+ }
1014
+
1015
+ //#endregion
1016
+ //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
1017
+ function toPropertyKey(t) {
1018
+ var i = toPrimitive(t, "string");
1019
+ return "symbol" == _typeof(i) ? i : i + "";
1020
+ }
1021
+
1022
+ //#endregion
1023
+ //#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
1024
+ function _defineProperty(e, r, t) {
1025
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
1026
+ value: t,
1027
+ enumerable: !0,
1028
+ configurable: !0,
1029
+ writable: !0
1030
+ }) : e[r] = t, e;
1031
+ }
1032
+
997
1033
  //#endregion
998
1034
  //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorateParam.js
999
1035
  function __decorateParam(paramIndex, decorator) {
@@ -1026,42 +1062,42 @@ let FDocument = class FDocument extends FBaseInitialable {
1026
1062
  }
1027
1063
  /**
1028
1064
  * Get the document data model of the document.
1065
+ * @param {string} segmentId The segment id used to get the header/footer data model. Defaults to an empty string for the document data model of the document.
1029
1066
  * @returns {DocumentDataModel} The document data model.
1030
1067
  * @example
1031
1068
  * ```typescript
1032
1069
  * const fDocument = univerAPI.getActiveDocument();
1033
- * const documentDataModel = fDocument.getDocumentDataModel();
1034
- * console.log(documentDataModel);
1070
+ * console.log(fDocument.getDocumentDataModel());
1071
+ *
1072
+ * const headerSegmentId = fDocument.ensurePageHeader();
1073
+ * console.log(fDocument.getDocumentDataModel(headerSegmentId));
1035
1074
  * ```
1036
1075
  */
1037
- getDocumentDataModel() {
1038
- return this._documentDataModel;
1076
+ getDocumentDataModel(segmentId = "") {
1077
+ const documentDataModel = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId);
1078
+ if (!documentDataModel) throw new Error(segmentId === "" ? "Document data model is not found." : `Document data model is not found in the segment: ${segmentId}`);
1079
+ return documentDataModel;
1039
1080
  }
1040
1081
  /**
1041
- * Get the document body facade.
1042
- *
1043
- * The returned body facade provides synchronous Google Docs-like element APIs
1044
- * for reading and editing top-level document body elements. Paragraph elements
1045
- * use their persisted `paragraphId` values. Persisted elements, such as tables
1046
- * and custom blocks, use their existing ids.
1047
- *
1048
- * @returns {FDocumentBody} The document body API instance.
1082
+ * Get the document body or header/footer body by the segment id.
1083
+ * The main body has an empty segment id.
1084
+ * The header and footer body have their respective segment ids.
1085
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
1086
+ * @returns {IDocumentBody} The document body.
1049
1087
  * @example
1050
1088
  * ```typescript
1051
1089
  * const fDocument = univerAPI.getActiveDocument();
1052
- * const fDocumentBody = fDocument.getBody();
1053
- * console.log(fDocumentBody.getBody());
1090
+ * console.log(fDocument.getBody()); // Get the main body
1054
1091
  *
1055
- * const element = fDocumentBody.getElement(0);
1056
- * if (element.isParagraph()) {
1057
- * const paragraph = element.asParagraph();
1058
- * paragraph.appendText(' updated');
1059
- * console.log(paragraph.getText());
1060
- * }
1092
+ * const footerSegmentId = fDocument.ensurePageFooter();
1093
+ * console.log(fDocument.getBody(footerSegmentId)); // Get the footer body
1061
1094
  * ```
1062
1095
  */
1063
- getBody() {
1064
- return this._injector.createInstance(FDocumentBody, this._documentDataModel, this._injector);
1096
+ getBody(segmentId = "") {
1097
+ var _this$_documentDataMo;
1098
+ const body = (_this$_documentDataMo = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _this$_documentDataMo === void 0 ? void 0 : _this$_documentDataMo.getBody();
1099
+ if (!body) throw new Error(segmentId === "" ? "Body is not found in the document." : `Body is not found in the segment: ${segmentId}`);
1100
+ return body;
1065
1101
  }
1066
1102
  dispose() {
1067
1103
  super.dispose();
@@ -1072,8 +1108,7 @@ let FDocument = class FDocument extends FBaseInitialable {
1072
1108
  * @example
1073
1109
  * ```typescript
1074
1110
  * const fDocument = univerAPI.getActiveDocument();
1075
- * const unitId = fDocument.getId();
1076
- * console.log(unitId);
1111
+ * console.log(fDocument.getId());
1077
1112
  * ```
1078
1113
  */
1079
1114
  getId() {
@@ -1085,14 +1120,25 @@ let FDocument = class FDocument extends FBaseInitialable {
1085
1120
  * @example
1086
1121
  * ```typescript
1087
1122
  * const fDocument = univerAPI.getActiveDocument();
1088
- * const name = fDocument.getName();
1089
- * console.log(name);
1123
+ * console.log(fDocument.getName());
1090
1124
  * ```
1091
1125
  */
1092
1126
  getName() {
1093
1127
  return this._documentDataModel.getTitle() || "";
1094
1128
  }
1095
1129
  /**
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.
1132
+ * @example
1133
+ * ```typescript
1134
+ * const fDocument = univerAPI.getActiveDocument();
1135
+ * console.log(fDocument.isModern());
1136
+ * ```
1137
+ */
1138
+ isModern() {
1139
+ return this._documentDataModel.getSnapshot().documentStyle.documentFlavor === DocumentFlavor.MODERN;
1140
+ }
1141
+ /**
1096
1142
  * Save the document snapshot data, including the document content and resource data, etc.
1097
1143
  * @returns {IDocumentData} The document snapshot data.
1098
1144
  * @example
@@ -1133,264 +1179,505 @@ let FDocument = class FDocument extends FBaseInitialable {
1133
1179
  this._univerInstanceService.focusUnit(this.id);
1134
1180
  return this._commandService.syncExecuteCommand(RedoCommand.id);
1135
1181
  }
1136
- };
1137
- FDocument = __decorate([
1138
- __decorateParam(1, Inject(Injector)),
1139
- __decorateParam(2, IUniverInstanceService),
1140
- __decorateParam(3, Inject(IResourceLoaderService)),
1141
- __decorateParam(4, ICommandService)
1142
- ], FDocument);
1143
-
1144
- //#endregion
1145
- //#region src/facade/f-univer.ts
1146
- var FUniverDocsMixin = class extends FUniver {
1147
- createDocument(data) {
1148
- const document = this._injector.get(IUniverInstanceService).createUnit(UniverInstanceType.UNIVER_DOC, data);
1149
- return this._injector.createInstance(FDocument, document);
1182
+ /**
1183
+ * Ensure the page header segment exists and return its segment id.
1184
+ * @param {number} pageIndex The zero-based page index. Defaults to the first page.
1185
+ * @returns {string} The header segment id.
1186
+ * @example
1187
+ * ```ts
1188
+ * const fDocument = univerAPI.getActiveDocument();
1189
+ * const headerSegmentId = fDocument.ensurePageHeader();
1190
+ * fDocument.insertText(0, 'Header text', headerSegmentId);
1191
+ * ```
1192
+ */
1193
+ ensurePageHeader(pageIndex = 0) {
1194
+ return this._ensureHeaderFooter("header", pageIndex);
1150
1195
  }
1151
- getActiveDocument() {
1152
- const document = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC);
1153
- if (!document) return null;
1154
- return this._injector.createInstance(FDocument, document);
1196
+ /**
1197
+ * Ensure the page footer segment exists and return its segment id.
1198
+ * @param {number} pageIndex The zero-based page index. Defaults to the first page.
1199
+ * @returns {string} The footer segment id.
1200
+ * @example
1201
+ * ```ts
1202
+ * const fDocument = univerAPI.getActiveDocument();
1203
+ * const footerSegmentId = fDocument.ensurePageFooter();
1204
+ * fDocument.insertText(0, 'Footer text', footerSegmentId);
1205
+ * ```
1206
+ */
1207
+ ensurePageFooter(pageIndex = 0) {
1208
+ return this._ensureHeaderFooter("footer", pageIndex);
1155
1209
  }
1156
- getDocument(id) {
1157
- const document = this._univerInstanceService.getUnit(id, UniverInstanceType.UNIVER_DOC);
1158
- if (!document) return null;
1159
- return this._injector.createInstance(FDocument, document);
1210
+ /**
1211
+ * Insert plain text at a document body offset.
1212
+ * @param {number} index The zero-based insertion offset.
1213
+ * @param {string} text The plain text to insert.
1214
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
1215
+ * @returns {boolean} `true` if the edit was applied.
1216
+ * @example
1217
+ * ```ts
1218
+ * const fDocument = univerAPI.getActiveDocument();
1219
+ * fDocument.insertText(0, 'Hello ');
1220
+ *
1221
+ * const headerSegmentId = fDocument.ensurePageHeader();
1222
+ * fDocument.insertText(0, 'Header text', headerSegmentId);
1223
+ * ```
1224
+ */
1225
+ insertText(index, text, segmentId = "") {
1226
+ return replaceBodyRange({
1227
+ startOffset: index,
1228
+ endOffset: index,
1229
+ segmentId
1230
+ }, buildPlainTextInsertBody(text), this._documentDataModel, this._injector);
1160
1231
  }
1161
- };
1162
- FUniver.extend(FUniverDocsMixin);
1163
-
1164
- //#endregion
1165
- //#region src/facade/f-document-block-range.ts
1166
- /**
1167
- * A facade wrapper for document block ranges, such as callout, quote, and code blocks.
1168
- *
1169
- * Block range identity is backed by the persisted `IDocumentBlockRange.blockId`,
1170
- * so wrappers can be re-resolved after text is inserted before the block range.
1171
- *
1172
- * @hideconstructor
1173
- */
1174
- var FDocumentBlockRange = class extends FDocumentElement {
1175
- constructor(body, bodyEdit, info, injector) {
1176
- super(body, bodyEdit, info, injector);
1177
- this.body = body;
1178
- this.bodyEdit = bodyEdit;
1179
- this.info = info;
1180
- this.injector = injector;
1181
- if (this.getType() !== DocumentBlockType.BLOCK_RANGE) throw new Error(`Element type is not a block range: ${this.getType()}`);
1232
+ /**
1233
+ * Returns document-level header/footer switches and margins. Margin values are in points (pt).
1234
+ * @example
1235
+ * ```ts
1236
+ * const fDocument = univerAPI.getActiveDocument();
1237
+ * console.log(fDocument?.getHeaderFooterOptions());
1238
+ * ```
1239
+ */
1240
+ getHeaderFooterOptions() {
1241
+ const style = this._documentDataModel.getSnapshot().documentStyle;
1242
+ return {
1243
+ marginHeader: style.marginHeader,
1244
+ marginFooter: style.marginFooter,
1245
+ useFirstPageHeaderFooter: style.useFirstPageHeaderFooter,
1246
+ evenAndOddHeaders: style.evenAndOddHeaders
1247
+ };
1182
1248
  }
1183
1249
  /**
1184
- * Get the top-level block range data model.
1185
- * @returns {IDocumentBlockRange} The block range data model.
1250
+ * Updates document-level header/footer switches and margins in a traditional document.
1251
+ * `marginHeader` and `marginFooter` are in points (pt).
1186
1252
  * @example
1187
1253
  * ```ts
1188
1254
  * const fDocument = univerAPI.getActiveDocument();
1189
- * const fDocumentBody = fDocument.getBody();
1190
- * const element = fDocumentBody.getElement(0);
1191
- *
1192
- * if (element?.isBlockRange()) {
1193
- * const blockRange = element.asBlockRange();
1194
- * console.log(blockRange.getBlockRange());
1255
+ * if (fDocument && !fDocument.isModern()) {
1256
+ * fDocument.setHeaderFooterOptions({ marginHeader: 36, marginFooter: 36 });
1195
1257
  * }
1196
1258
  * ```
1197
1259
  */
1198
- getBlockRange() {
1199
- const { blockRanges = [] } = this._body.getBody();
1200
- const blockRange = blockRanges.find((blockRange) => blockRange.blockId === this.getKey());
1201
- if (!blockRange) throw new Error(`Block range not found: ${this.getKey()}`);
1202
- return blockRange;
1260
+ setHeaderFooterOptions(options) {
1261
+ if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
1262
+ return this._commandService.syncExecuteCommand(CreateHeaderFooterCommand.id, {
1263
+ unitId: this.getId(),
1264
+ headerFooterProps: options
1265
+ });
1203
1266
  }
1204
1267
  /**
1205
- * Get the block range type.
1206
- * @returns {DocumentBlockRangeType} The block type, such as callout, quote, or code.
1268
+ * Creates a facade for reading and styling a document text range.
1269
+ * The end offset is exclusive, and offsets are scoped to the selected body segment.
1270
+ * @param {number} startOffset The inclusive start offset.
1271
+ * @param {number} endOffset The exclusive end offset.
1272
+ * @param {string} segmentId The header/footer segment id, or an empty string for the main body.
1273
+ * @returns {FDocumentTextRange} A fixed text-range facade.
1274
+ * @example
1275
+ * ```ts
1276
+ * const range = univerAPI.getActiveDocument()?.getTextRange(0, 5);
1277
+ * console.log(range?.describe());
1278
+ * range?.setTextStyle({ bl: 1 });
1279
+ * ```
1280
+ */
1281
+ getTextRange(startOffset, endOffset, segmentId = "") {
1282
+ return this._injector.createInstance(FDocumentTextRange, this, startOffset, endOffset, segmentId, this._injector);
1283
+ }
1284
+ /**
1285
+ * Returns traditional document sections backed by persisted SectionBreak ids.
1286
+ * Modern documents use ColumnGroup instead and return an empty array from this read API.
1207
1287
  * @example
1208
1288
  * ```ts
1209
1289
  * const fDocument = univerAPI.getActiveDocument();
1210
- * const fDocumentBody = fDocument.getBody();
1211
- * const element = fDocumentBody.getElement(0);
1212
- *
1213
- * if (element?.isBlockRange()) {
1214
- * const blockRange = element.asBlockRange();
1215
- * console.log(blockRange.getBlockType());
1216
- * }
1290
+ * const sections = fDocument?.getSections() ?? [];
1291
+ * console.log(sections.map((section) => section.describe()));
1217
1292
  * ```
1218
1293
  */
1219
- getBlockType() {
1220
- return this.getBlockRange().blockType;
1294
+ getSections() {
1295
+ 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));
1221
1297
  }
1222
1298
  /**
1223
- * Get the plain text inside this block range.
1224
- * @returns {string} The block range text.
1299
+ * Returns a traditional section by zero-based index, or `null` in modern documents.
1225
1300
  * @example
1226
1301
  * ```ts
1227
1302
  * const fDocument = univerAPI.getActiveDocument();
1228
- * const fDocumentBody = fDocument.getBody();
1229
- * const element = fDocumentBody.getElement(0);
1230
- *
1231
- * if (element?.isBlockRange()) {
1232
- * const blockRange = element.asBlockRange();
1233
- * console.log(blockRange.getText());
1303
+ * const firstSection = fDocument?.getSection(0);
1304
+ * console.log(firstSection?.describe());
1305
+ * ```
1306
+ */
1307
+ getSection(index) {
1308
+ var _this$getSections$ind;
1309
+ return (_this$getSections$ind = this.getSections()[index]) !== null && _this$getSections$ind !== void 0 ? _this$getSections$ind : null;
1310
+ }
1311
+ /**
1312
+ * Returns the traditional section containing a data-stream offset, or `null` in modern documents.
1313
+ * @example
1314
+ * ```ts
1315
+ * const fDocument = univerAPI.getActiveDocument();
1316
+ * const paragraph = fDocument?.findParagraphByText('Launch');
1317
+ * const offset = paragraph?.getInfo().startOffset;
1318
+ * const section = offset == null ? null : fDocument?.getSectionAt(offset);
1319
+ * console.log(section?.getId());
1320
+ * ```
1321
+ */
1322
+ getSectionAt(offset) {
1323
+ var _this$getSections$fin;
1324
+ return (_this$getSections$fin = this.getSections().find((section) => {
1325
+ const range = section.getRange();
1326
+ return offset >= range.startOffset && offset <= range.endOffset;
1327
+ })) !== null && _this$getSections$fin !== void 0 ? _this$getSections$fin : null;
1328
+ }
1329
+ /**
1330
+ * 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).
1333
+ * @example
1334
+ * ```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());
1234
1341
  * }
1235
1342
  * ```
1236
1343
  */
1237
- getText() {
1238
- const { dataStream } = this._body.getBody();
1239
- const { startIndex, endIndex } = this.getBlockRange();
1240
- return dataStream.slice(startIndex, endIndex);
1344
+ insertSectionBreak(offset, config = {}) {
1345
+ var _this$getBody$section;
1346
+ if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
1347
+ 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
+ return this._commandService.syncExecuteCommand(InsertDocumentSectionBreakCommand.id, {
1349
+ unitId: this.getId(),
1350
+ offset,
1351
+ sectionId,
1352
+ config
1353
+ }) ? this._injector.createInstance(FDocumentSection, this, sectionId, this._injector) : null;
1241
1354
  }
1242
1355
  /**
1243
- * Replace the plain text inside this block range.
1244
- * @param {string} text The replacement text.
1245
- * @returns {boolean} `true` if the block range text was replaced.
1356
+ * Inserts a column-break token in a traditional document.
1357
+ * Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
1246
1358
  * @example
1247
1359
  * ```ts
1248
1360
  * const fDocument = univerAPI.getActiveDocument();
1249
- * const fDocumentBody = fDocument.getBody();
1250
- * const element = fDocumentBody.getElement(0);
1251
- *
1252
- * if (element?.isBlockRange()) {
1253
- * const blockRange = element.asBlockRange();
1254
- * blockRange.setText('Updated block text');
1255
- * console.log(blockRange.getText());
1361
+ * if (fDocument && !fDocument.isModern()) {
1362
+ * const paragraph = fDocument.findParagraphByText('Continue in next column');
1363
+ * const offset = paragraph?.getInfo().startOffset;
1364
+ * if (offset != null) {
1365
+ * fDocument.insertColumnBreak(offset);
1366
+ * }
1256
1367
  * }
1257
1368
  * ```
1258
1369
  */
1259
- setText(text) {
1260
- const blockRange = this.getBlockRange();
1261
- const { startIndex, endIndex } = blockRange;
1262
- const updateBody = buildPlainTextInsertBody(`${text}\r`);
1263
- updateBody.blockRanges = [{
1264
- ...blockRange,
1265
- startIndex: 0,
1266
- endIndex: text.length
1267
- }];
1268
- return this._bodyEdit.replaceRange({
1269
- startOffset: startIndex,
1270
- endOffset: endIndex + 1
1271
- }, updateBody);
1272
- }
1273
- /**
1274
- * Remove this block range wrapper from the body.
1275
- *
1276
- * This currently removes the block range and its content, matching
1277
- * `remove()`.
1278
- *
1279
- * @returns {boolean} `true` if the block range content was removed.
1370
+ insertColumnBreak(offset) {
1371
+ if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
1372
+ return this.insertText(offset, DataStreamTreeTokenType.COLUMN_BREAK);
1373
+ }
1374
+ /**
1375
+ * Inserts a horizontal rule using the existing paragraph `borderBottom` mechanism.
1376
+ * The returned paragraph can be inspected or removed with normal paragraph APIs.
1377
+ * Border width and padding are in points (pt).
1378
+ * @example
1379
+ * ```ts
1380
+ * const fDocument = univerAPI.getActiveDocument();
1381
+ * const paragraph = fDocument?.findParagraphByText('Summary');
1382
+ * const offset = paragraph?.getInfo().startOffset;
1383
+ * const rule = offset == null ? null : fDocument?.insertHorizontalRule(offset);
1384
+ * console.log(rule?.getId());
1385
+ * ```
1386
+ */
1387
+ insertHorizontalRule(offset, border = {
1388
+ padding: 5,
1389
+ color: { rgb: "#CDD0D8" },
1390
+ width: 1,
1391
+ dashStyle: DashStyleType.SOLID
1392
+ }, segmentId = "") {
1393
+ var _body$paragraphs;
1394
+ const body = this.getBody(segmentId);
1395
+ const paragraphs = generateParagraphs(DataStreamTreeTokenType.PARAGRAPH, void 0, border, (_body$paragraphs = body.paragraphs) === null || _body$paragraphs === void 0 ? void 0 : _body$paragraphs.map((paragraph) => paragraph.paragraphId));
1396
+ const paragraphId = paragraphs[0].paragraphId;
1397
+ return replaceBodyRange({
1398
+ startOffset: offset,
1399
+ endOffset: offset,
1400
+ segmentId
1401
+ }, {
1402
+ dataStream: DataStreamTreeTokenType.PARAGRAPH,
1403
+ paragraphs
1404
+ }, this._documentDataModel, this._injector) ? this.getParagraph(paragraphId, segmentId) : null;
1405
+ }
1406
+ /**
1407
+ * Get all paragraphs in the document body or header/footer body by the segment id.
1408
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
1409
+ * @returns {FDocumentParagraph[]} An array of paragraph facade instances.
1280
1410
  * @example
1281
1411
  * ```ts
1282
1412
  * const fDocument = univerAPI.getActiveDocument();
1283
- * const fDocumentBody = fDocument.getBody();
1284
- * const element = fDocumentBody.getElement(0);
1413
+ * const paragraphs = fDocument.getParagraphs();
1414
+ * console.log(paragraphs);
1285
1415
  *
1286
- * if (element?.isBlockRange()) {
1287
- * const blockRange = element.asBlockRange();
1288
- * const removed = blockRange.unwrap();
1289
- * console.log(removed ? 'Block range removed' : 'Failed to remove block range');
1290
- * }
1416
+ * const headerSegmentId = fDocument.ensurePageHeader();
1417
+ * const headerParagraphs = fDocument.getParagraphs(headerSegmentId);
1418
+ * console.log(headerParagraphs);
1291
1419
  * ```
1292
1420
  */
1293
- unwrap() {
1294
- return this.remove();
1421
+ getParagraphs(segmentId = "") {
1422
+ const { paragraphs = [] } = this.getBody(segmentId);
1423
+ return paragraphs.map((paragraph) => this._createFDocumentParagraph(paragraph.paragraphId, segmentId));
1295
1424
  }
1296
- };
1297
- var FDocumentBlockRangeMixin = class extends FDocumentElement {
1298
- asBlockRange() {
1299
- if (this.getType() !== DocumentBlockType.BLOCK_RANGE) throw new Error(`Element type is not a block range: ${this.getType()}`);
1300
- return this._injector.createInstance(FDocumentBlockRange, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
1425
+ /**
1426
+ * Get a paragraph by its paragraph id and segment id.
1427
+ * @param {string} paragraphId The paragraph id.
1428
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
1429
+ * @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
1430
+ * @example
1431
+ * ```ts
1432
+ * const fDocument = univerAPI.getActiveDocument();
1433
+ * const paragraph = fDocument.getParagraph('paragraph-01');
1434
+ * console.log(paragraph);
1435
+ *
1436
+ * const headerSegmentId = fDocument.ensurePageHeader();
1437
+ * const headerParagraph = fDocument.getParagraph('header-paragraph-01', headerSegmentId);
1438
+ * console.log(headerParagraph);
1439
+ * ```
1440
+ */
1441
+ getParagraph(paragraphId, segmentId = "") {
1442
+ const { paragraphs = [] } = this.getBody(segmentId);
1443
+ if (!paragraphs.find((paragraph) => paragraph.paragraphId === paragraphId)) return null;
1444
+ return this._createFDocumentParagraph(paragraphId, segmentId);
1301
1445
  }
1302
- };
1303
- FDocumentElement.extend(FDocumentBlockRangeMixin);
1304
-
1305
- //#endregion
1306
- //#region src/facade/f-document-custom-block.ts
1307
- /**
1308
- * A facade wrapper for document top-level custom blocks.
1309
- * @hideconstructor
1310
- */
1311
- var FDocumentCustomBlock = class extends FDocumentElement {
1312
- constructor(body, bodyEdit, info, injector) {
1313
- super(body, bodyEdit, info, injector);
1314
- this.body = body;
1315
- this.bodyEdit = bodyEdit;
1316
- this.info = info;
1317
- this.injector = injector;
1318
- if (this.getType() !== DocumentBlockType.CUSTOM_BLOCK) throw new Error(`Element type is not a custom block: ${this.getType()}`);
1446
+ /**
1447
+ * Find a paragraph by its text content and segment id.
1448
+ * @param {string} text The text content to search for.
1449
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
1450
+ * @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
1451
+ * @example
1452
+ * ```ts
1453
+ * const fDocument = univerAPI.getActiveDocument();
1454
+ * const paragraph = fDocument.findParagraphByText('Hello');
1455
+ * console.log(paragraph);
1456
+ *
1457
+ * const footerSegmentId = fDocument.ensurePageFooter();
1458
+ * const footerParagraph = fDocument.findParagraphByText('Page', footerSegmentId);
1459
+ * console.log(footerParagraph);
1460
+ * ```
1461
+ */
1462
+ findParagraphByText(text, segmentId = "") {
1463
+ return this.findParagraphs({
1464
+ text,
1465
+ segmentId
1466
+ })[0] || null;
1319
1467
  }
1320
1468
  /**
1321
- * Get the custom block marker.
1322
- * @returns {ICustomBlock} The custom block marker.
1469
+ * Find paragraphs by a query object, which can include text content, paragraph id, and segment id.
1470
+ * @param {string | IFDocumentParagraphQuery} query The query object or text content to search for.
1471
+ * @returns {FDocumentParagraph[]} An array of paragraph facade instances that match the query.
1323
1472
  * @example
1324
1473
  * ```ts
1325
1474
  * const fDocument = univerAPI.getActiveDocument();
1326
- * const fDocumentBody = fDocument.getBody();
1327
- * const element = fDocumentBody.getElement(0);
1475
+ * const paragraphsWithText = fDocument.findParagraphs('Hello');
1476
+ * console.log(paragraphsWithText);
1328
1477
  *
1329
- * if (element?.isCustomBlock()) {
1330
- * const customBlock = element.asCustomBlock();
1331
- * console.log(customBlock.getCustomBlock());
1332
- * }
1478
+ * const paragraphsWithId = fDocument.findParagraphs({ paragraphId: 'paragraph-01' });
1479
+ * console.log(paragraphsWithId);
1480
+ *
1481
+ * const headerSegmentId = fDocument.ensurePageHeader();
1482
+ * const paragraphsWithSegment = fDocument.findParagraphs({ segmentId: headerSegmentId });
1483
+ * console.log(paragraphsWithSegment);
1333
1484
  * ```
1334
1485
  */
1335
- getCustomBlock() {
1336
- const { customBlocks = [] } = this._body.getBody();
1337
- const block = customBlocks.find((item) => item.blockId === this.getKey());
1338
- if (!block) throw new Error("Doc custom block is stale");
1339
- return block;
1486
+ findParagraphs(query) {
1487
+ const { text, paragraphId, segmentId = "" } = typeof query === "string" ? { text: query } : query;
1488
+ return this.getParagraphs(segmentId).filter((paragraph) => {
1489
+ if (paragraphId && paragraph.getId() !== paragraphId) return false;
1490
+ if (text && !paragraph.getText().includes(text)) return false;
1491
+ return true;
1492
+ });
1340
1493
  }
1341
- };
1342
- var FDocumentCustomBlockMixin = class extends FDocumentElement {
1343
- asCustomBlock() {
1344
- if (this.getType() !== DocumentBlockType.CUSTOM_BLOCK) throw new Error(`Element type is not a custom block: ${this.getType()}`);
1345
- return this._injector.createInstance(FDocumentCustomBlock, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
1494
+ /**
1495
+ * Insert a plain-text paragraph before the paragraph at the given paragraph index.
1496
+ * @param {number} index The zero-based paragraph insertion index.
1497
+ * @param {string} text The paragraph text. Defaults to an empty paragraph.
1498
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
1499
+ * @returns {FDocumentParagraph} The inserted paragraph facade instance.
1500
+ * @example
1501
+ * ```ts
1502
+ * const fDocument = univerAPI.getActiveDocument();
1503
+ * const paragraph = fDocument.insertParagraph(0, 'Document title');
1504
+ * paragraph.appendText(' suffix');
1505
+ *
1506
+ * const headerSegmentId = fDocument.ensurePageHeader();
1507
+ * const headerParagraph = fDocument.insertParagraph(0, 'Header title', headerSegmentId);
1508
+ * headerParagraph.appendText(' suffix');
1509
+ * ```
1510
+ */
1511
+ insertParagraph(index, text = "", segmentId = "") {
1512
+ const offset = this._getParagraphInsertOffset(index, segmentId);
1513
+ if (!replaceBodyRange({
1514
+ startOffset: offset,
1515
+ endOffset: offset,
1516
+ segmentId
1517
+ }, buildPlainTextInsertBody(`${text}\r`), this._documentDataModel, this._injector)) throw new Error("Failed to insert paragraph.");
1518
+ const { paragraphs = [] } = this.getBody(segmentId);
1519
+ const paragraph = paragraphs[index];
1520
+ if (!paragraph) throw new Error("Failed to insert paragraph.");
1521
+ return this._createFDocumentParagraph(paragraph.paragraphId, segmentId);
1346
1522
  }
1347
- };
1348
- FDocumentElement.extend(FDocumentCustomBlockMixin);
1349
-
1350
- //#endregion
1351
- //#region src/facade/f-document-table.ts
1352
- /**
1353
- * A facade wrapper for document top-level tables.
1354
- * @hideconstructor
1355
- */
1356
- var FDocumentTable = class extends FDocumentElement {
1357
- constructor(body, bodyEdit, info, injector) {
1358
- super(body, bodyEdit, info, injector);
1359
- this.body = body;
1360
- this.bodyEdit = bodyEdit;
1361
- this.info = info;
1362
- this.injector = injector;
1363
- if (this.getType() !== DocumentBlockType.TABLE) throw new Error(`Element type is not a table: ${this.getType()}`);
1523
+ /**
1524
+ * Append a plain-text paragraph at the end of the body.
1525
+ * @param {string} text The paragraph text. Defaults to an empty paragraph.
1526
+ * @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
1527
+ * @returns {FDocumentParagraph} The appended paragraph wrapper.
1528
+ * @example
1529
+ * ```ts
1530
+ * const fDocument = univerAPI.getActiveDocument();
1531
+ * const paragraph = fDocument.appendParagraph('Summary');
1532
+ * console.log(paragraph.getText());
1533
+ *
1534
+ * const footerSegmentId = fDocument.ensurePageFooter();
1535
+ * const footerParagraph = fDocument.appendParagraph('Confidential', footerSegmentId);
1536
+ * console.log(footerParagraph.getText());
1537
+ * ```
1538
+ */
1539
+ appendParagraph(text = "", segmentId = "") {
1540
+ const { paragraphs = [] } = this.getBody(segmentId);
1541
+ return this.insertParagraph(paragraphs.length, text, segmentId);
1364
1542
  }
1365
1543
  /**
1366
- * Get the table marker.
1367
- * @returns {ICustomTable} The table marker.
1544
+ * Delete a range from the body.
1545
+ * @param {IFDocumentTextRange} range The text range to delete.
1546
+ * @returns {boolean} `true` if the range was deleted.
1368
1547
  * @example
1369
1548
  * ```ts
1370
1549
  * const fDocument = univerAPI.getActiveDocument();
1371
- * const fDocumentBody = fDocument.getBody();
1372
- * const element = fDocumentBody.getElement(0);
1550
+ * fDocument.deleteRange({ startOffset: 0, endOffset: 5 });
1373
1551
  *
1374
- * if (element?.isTable()) {
1375
- * const table = element.asTable();
1376
- * console.log(table.getTable());
1377
- * }
1552
+ * const headerSegmentId = fDocument.ensurePageHeader();
1553
+ * fDocument.deleteRange({ startOffset: 0, endOffset: 5, segmentId: headerSegmentId });
1378
1554
  * ```
1379
1555
  */
1380
- getTable() {
1381
- const { tables = [] } = this._body.getBody();
1382
- const table = tables.find((item) => item.tableId === this.getKey());
1383
- if (!table) throw new Error("Doc table is stale");
1384
- return table;
1556
+ deleteRange(range) {
1557
+ const normalizedRange = this._normalizeDeleteRange(range);
1558
+ if (normalizedRange.startOffset >= normalizedRange.endOffset) return false;
1559
+ return replaceBodyRange(normalizedRange, { dataStream: "" }, this._documentDataModel, this._injector);
1560
+ }
1561
+ _createFDocumentParagraph(paragraphId, segmentId = "") {
1562
+ return this._injector.createInstance(FDocumentParagraph, this, paragraphId, segmentId, this._injector);
1563
+ }
1564
+ _normalizeDeleteRange(range) {
1565
+ const body = this.getBody(range.segmentId);
1566
+ const protectedEndOffset = body.dataStream.endsWith("\r\n") ? Math.max(0, body.dataStream.length - 2) : body.dataStream.length;
1567
+ const endOffset = Math.min(Math.max(range.endOffset, 0), protectedEndOffset);
1568
+ return {
1569
+ ...range,
1570
+ startOffset: Math.min(Math.max(range.startOffset, 0), endOffset),
1571
+ endOffset
1572
+ };
1573
+ }
1574
+ _getParagraphInsertOffset(index, segmentId = "") {
1575
+ if (index <= 0) return 0;
1576
+ const body = this.getBody(segmentId);
1577
+ const { dataStream, paragraphs = [] } = body;
1578
+ if (paragraphs.length === 0) return Math.max(0, dataStream.length - 1);
1579
+ if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
1580
+ return getParagraphContentStartOffset(body, paragraphs[index]);
1581
+ }
1582
+ _ensureHeaderFooter(kind, pageIndex) {
1583
+ if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
1584
+ const { createType, segmentId: existingSegmentId } = this._getHeaderFooterCreateInfo(kind, pageIndex);
1585
+ if (existingSegmentId) return existingSegmentId;
1586
+ const segmentId = generateRandomId(6);
1587
+ if (!this._commandService.syncExecuteCommand(CreateHeaderFooterCommand.id, {
1588
+ unitId: this.getId(),
1589
+ segmentId,
1590
+ createType
1591
+ })) throw new Error(`Failed to create page ${kind}.`);
1592
+ return segmentId;
1593
+ }
1594
+ _getHeaderFooterCreateInfo(kind, pageIndex) {
1595
+ var _documentStyle$defaul, _documentStyle$defaul2;
1596
+ const { documentStyle } = this._documentDataModel.getSnapshot();
1597
+ const isFirstPage = pageIndex === 0;
1598
+ const isEvenPage = (pageIndex + 1) % 2 === 0;
1599
+ if (isFirstPage && documentStyle.useFirstPageHeaderFooter === BooleanNumber.TRUE) {
1600
+ var _documentStyle$firstP, _documentStyle$firstP2;
1601
+ return kind === "header" ? {
1602
+ createType: HeaderFooterType.FIRST_PAGE_HEADER,
1603
+ segmentId: (_documentStyle$firstP = documentStyle.firstPageHeaderId) !== null && _documentStyle$firstP !== void 0 ? _documentStyle$firstP : ""
1604
+ } : {
1605
+ createType: HeaderFooterType.FIRST_PAGE_FOOTER,
1606
+ segmentId: (_documentStyle$firstP2 = documentStyle.firstPageFooterId) !== null && _documentStyle$firstP2 !== void 0 ? _documentStyle$firstP2 : ""
1607
+ };
1608
+ }
1609
+ if (isEvenPage && documentStyle.evenAndOddHeaders === BooleanNumber.TRUE) {
1610
+ var _documentStyle$evenPa, _documentStyle$evenPa2;
1611
+ return kind === "header" ? {
1612
+ createType: HeaderFooterType.EVEN_PAGE_HEADER,
1613
+ segmentId: (_documentStyle$evenPa = documentStyle.evenPageHeaderId) !== null && _documentStyle$evenPa !== void 0 ? _documentStyle$evenPa : ""
1614
+ } : {
1615
+ createType: HeaderFooterType.EVEN_PAGE_FOOTER,
1616
+ segmentId: (_documentStyle$evenPa2 = documentStyle.evenPageFooterId) !== null && _documentStyle$evenPa2 !== void 0 ? _documentStyle$evenPa2 : ""
1617
+ };
1618
+ }
1619
+ return kind === "header" ? {
1620
+ createType: HeaderFooterType.DEFAULT_HEADER,
1621
+ segmentId: (_documentStyle$defaul = documentStyle.defaultHeaderId) !== null && _documentStyle$defaul !== void 0 ? _documentStyle$defaul : ""
1622
+ } : {
1623
+ createType: HeaderFooterType.DEFAULT_FOOTER,
1624
+ segmentId: (_documentStyle$defaul2 = documentStyle.defaultFooterId) !== null && _documentStyle$defaul2 !== void 0 ? _documentStyle$defaul2 : ""
1625
+ };
1626
+ }
1627
+ };
1628
+ FDocument = __decorate([
1629
+ __decorateParam(1, Inject(Injector)),
1630
+ __decorateParam(2, IUniverInstanceService),
1631
+ __decorateParam(3, Inject(IResourceLoaderService)),
1632
+ __decorateParam(4, ICommandService)
1633
+ ], FDocument);
1634
+
1635
+ //#endregion
1636
+ //#region src/facade/f-univer.ts
1637
+ var FUniverDocsMixin = class extends FUniver {
1638
+ createDocument(data) {
1639
+ const document = this._injector.get(IUniverInstanceService).createUnit(UniverInstanceType.UNIVER_DOC, data);
1640
+ return this._injector.createInstance(FDocument, document);
1641
+ }
1642
+ getActiveDocument() {
1643
+ const document = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC);
1644
+ if (!document) return null;
1645
+ return this._injector.createInstance(FDocument, document);
1646
+ }
1647
+ getDocument(id) {
1648
+ const document = this._univerInstanceService.getUnit(id, UniverInstanceType.UNIVER_DOC);
1649
+ if (!document) return null;
1650
+ return this._injector.createInstance(FDocument, document);
1385
1651
  }
1386
1652
  };
1387
- var FDocumentTableMixin = class extends FDocumentElement {
1388
- asTable() {
1389
- if (this.getType() !== DocumentBlockType.TABLE) throw new Error(`Element type is not a table: ${this.getType()}`);
1390
- return this._injector.createInstance(FDocumentTable, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
1653
+ FUniver.extend(FUniverDocsMixin);
1654
+
1655
+ //#endregion
1656
+ //#region src/facade/f-enum.ts
1657
+ /**
1658
+ * Copyright 2023-present DreamNum Co., Ltd.
1659
+ *
1660
+ * Licensed under the Apache License, Version 2.0 (the "License");
1661
+ * you may not use this file except in compliance with the License.
1662
+ * You may obtain a copy of the License at
1663
+ *
1664
+ * http://www.apache.org/licenses/LICENSE-2.0
1665
+ *
1666
+ * Unless required by applicable law or agreed to in writing, software
1667
+ * distributed under the License is distributed on an "AS IS" BASIS,
1668
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1669
+ * See the License for the specific language governing permissions and
1670
+ * limitations under the License.
1671
+ */
1672
+ var FDocsEnumMixin = class extends FEnum {
1673
+ get SectionType() {
1674
+ return SectionType;
1675
+ }
1676
+ get ColumnSeparatorType() {
1677
+ return ColumnSeparatorType;
1391
1678
  }
1392
1679
  };
1393
- FDocumentElement.extend(FDocumentTableMixin);
1680
+ FEnum.extend(FDocsEnumMixin);
1394
1681
 
1395
1682
  //#endregion
1396
- export { FDocument, FDocumentBlockRange, FDocumentBody, FDocumentCustomBlock, FDocumentElement, FDocumentParagraph, FDocumentTable };
1683
+ export { DocsSectionUnsupportedDocumentFlavorError, FDocsEnumMixin, FDocument, FDocumentParagraph, FDocumentSection, FDocumentTextRange, isParagraphFacade, stripBlockTokens };