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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/es/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AlignTypeH, BuildTextUtils, CommandType, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DataStreamTreeTokenType, DeleteDirection, Disposable, DisposableCollection, DocumentFlavor, DrawingTypeEnum, ICommandService, IConfigService, IUndoRedoService, IUniverInstanceService, Inject, Injector, JSONX, LocaleService, MemoryCursor, ObjectRelativeFromH, ObjectRelativeFromV, Optional, PAGE_SIZE, PaperType, Plugin, PositionedObjectLayoutType, RedoCommandId, RxDisposable, TextX, TextXActionType, Tools, UndoCommandId, UniverInstanceType, UpdateDocsAttributeType, composeInterceptors, containsInteriorInsertionOffset, createIdentifier, createInterceptorKey, createParagraphId, createSectionId, generateRandomId, getBlockRangeInterval, getColumnGroupRangeInterval, getRichTextEditPath, getSectionHeaderFooterReferenceKey, getTableRangeInterval, isInternalEditorID, merge, remove, resolveSectionHeaderFooterReference, toDisposable, validateDocBodyStructure } from "@univerjs/core";
1
+ import { AlignTypeH, BuildTextUtils, ColumnSeparatorType, CommandType, CustomRangeType, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DataStreamTreeTokenType, DeleteDirection, Disposable, DisposableCollection, DocumentFlavor, DocxBreakType, DrawingTypeEnum, ICommandService, IConfigService, IUndoRedoService, IUniverInstanceService, Inject, Injector, JSONX, LocaleService, MemoryCursor, ObjectRelativeFromH, ObjectRelativeFromV, Optional, PAGE_SIZE, PageOrientType, PaperType, Plugin, PositionedObjectLayoutType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommandId, RxDisposable, SectionType, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN, TextX, TextXActionType, Tools, UndoCommandId, UniverInstanceType, UpdateDocsAttributeType, composeInterceptors, containsInteriorInsertionOffset, createIdentifier, createInterceptorKey, createParagraphId, createSectionId, generateRandomId, getBlockRangeInterval, getColumnGroupRangeInterval, getParagraphContentStartOffset, getRichTextEditPath, getSectionHeaderFooterReferenceKey, getTableRangeInterval, isInternalEditorID, merge, remove, resolveSectionHeaderFooterReference, toDisposable, validateDocBodyStructure } from "@univerjs/core";
2
2
  import { DocumentSkeleton, DocumentViewModel, IRenderManagerService, NORMAL_TEXT_SELECTION_PLUGIN_STYLE } from "@univerjs/engine-render";
3
3
  import { BehaviorSubject, Subject, takeUntil } from "rxjs";
4
4
 
@@ -12,7 +12,7 @@ const SetTextSelectionsOperation = {
12
12
  };
13
13
 
14
14
  //#endregion
15
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
15
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/typeof.js
16
16
  function _typeof(o) {
17
17
  "@babel/helpers - typeof";
18
18
  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
@@ -23,7 +23,7 @@ function _typeof(o) {
23
23
  }
24
24
 
25
25
  //#endregion
26
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPrimitive.js
26
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPrimitive.js
27
27
  function toPrimitive(t, r) {
28
28
  if ("object" != _typeof(t) || !t) return t;
29
29
  var e = t[Symbol.toPrimitive];
@@ -36,14 +36,14 @@ function toPrimitive(t, r) {
36
36
  }
37
37
 
38
38
  //#endregion
39
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
39
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPropertyKey.js
40
40
  function toPropertyKey(t) {
41
41
  var i = toPrimitive(t, "string");
42
42
  return "symbol" == _typeof(i) ? i : i + "";
43
43
  }
44
44
 
45
45
  //#endregion
46
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
46
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/defineProperty.js
47
47
  function _defineProperty(e, r, t) {
48
48
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
49
49
  value: t,
@@ -54,7 +54,7 @@ function _defineProperty(e, r, t) {
54
54
  }
55
55
 
56
56
  //#endregion
57
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorateParam.js
57
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorateParam.js
58
58
  function __decorateParam(paramIndex, decorator) {
59
59
  return function(target, key) {
60
60
  decorator(target, key, paramIndex);
@@ -62,7 +62,7 @@ function __decorateParam(paramIndex, decorator) {
62
62
  }
63
63
 
64
64
  //#endregion
65
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorate.js
65
+ //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorate.js
66
66
  function __decorate(decorators, target, key, desc) {
67
67
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
68
68
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -72,6 +72,11 @@ function __decorate(decorators, target, key, desc) {
72
72
 
73
73
  //#endregion
74
74
  //#region src/services/doc-selection-manager.service.ts
75
+ /**
76
+ * Keeps a programmatically restored collapsed caret from being promoted back
77
+ * into a neighboring whole-entity selection by feature-specific UI.
78
+ */
79
+ const DOC_SELECTION_OPTION_PRESERVE_CARET = "preserveCaret";
75
80
  let DocSelectionManagerService = class DocSelectionManagerService extends RxDisposable {
76
81
  constructor(_commandService, _univerInstanceService) {
77
82
  super();
@@ -133,16 +138,6 @@ let DocSelectionManagerService = class DocSelectionManagerService extends RxDisp
133
138
  const { textRanges } = selectionInfo;
134
139
  return textRanges.find((textRange) => textRange.isActive);
135
140
  }
136
- /**
137
- *
138
- * @deprecated
139
- */
140
- getActiveRectRange() {
141
- const selectionInfo = this._getTextRanges(this._currentSelection);
142
- if (selectionInfo == null) return;
143
- const { rectRanges } = selectionInfo;
144
- return rectRanges.find((rectRange) => rectRange.isActive);
145
- }
146
141
  __TEST_ONLY_add(textRanges, isEditing = true) {
147
142
  if (this._currentSelection == null) return;
148
143
  this._addByParam({
@@ -155,12 +150,6 @@ let DocSelectionManagerService = class DocSelectionManagerService extends RxDisp
155
150
  style: NORMAL_TEXT_SELECTION_PLUGIN_STYLE
156
151
  });
157
152
  }
158
- /**
159
- * @deprecated pls use replaceDocRanges.
160
- */
161
- replaceTextRanges(docRanges, isEditing = true, options) {
162
- return this.replaceDocRanges(docRanges, this._currentSelection, isEditing, options);
163
- }
164
153
  replaceDocRanges(docRanges, params = this._currentSelection, isEditing = true, options) {
165
154
  if (params == null) return;
166
155
  const { unitId, subUnitId } = params;
@@ -211,14 +200,15 @@ let DocSelectionManagerService = class DocSelectionManagerService extends RxDisp
211
200
  _refresh(param) {
212
201
  const allTextSelectionInfo = this._getTextRanges(param);
213
202
  if (allTextSelectionInfo == null) return;
214
- const { textRanges, rectRanges } = allTextSelectionInfo;
203
+ const { textRanges, rectRanges, options } = allTextSelectionInfo;
215
204
  const docRanges = [...textRanges, ...rectRanges];
216
205
  const { unitId, subUnitId } = param;
217
206
  this._refreshSelection$.next({
218
207
  unitId,
219
208
  subUnitId,
220
209
  docRanges,
221
- isEditing: false
210
+ isEditing: false,
211
+ options
222
212
  });
223
213
  }
224
214
  _replaceByParam(insertParam) {
@@ -862,6 +852,178 @@ function buildUnlinkActions(context, kind, requestedSegmentId) {
862
852
  ], segmentId)];
863
853
  }
864
854
 
855
+ //#endregion
856
+ //#region src/commands/commands/update-document-paragraph-style.command.ts
857
+ function isValidParams(params) {
858
+ return Boolean((params === null || params === void 0 ? void 0 : params.unitId) && params.paragraphId && Number.isInteger(params.startOffset) && Number.isInteger(params.endOffset) && params.startOffset >= 0 && params.endOffset >= params.startOffset && params.style && Object.keys(params.style).length > 0);
859
+ }
860
+ function getCurrentParagraph(body, params) {
861
+ var _body$paragraphs;
862
+ const matches = ((_body$paragraphs = body.paragraphs) !== null && _body$paragraphs !== void 0 ? _body$paragraphs : []).filter((paragraph) => paragraph.paragraphId === params.paragraphId);
863
+ if (matches.length !== 1) return null;
864
+ const paragraph = matches[0];
865
+ return getParagraphContentStartOffset(body, paragraph) === params.startOffset && paragraph.startIndex === params.endOffset && body.dataStream[params.endOffset] === "\r" ? paragraph : null;
866
+ }
867
+ function createParagraphStyleTextX(body, paragraph, params) {
868
+ var _paragraph$paragraphS;
869
+ const textX = new TextX();
870
+ const initializesTextRuns = Boolean(params.style.textStyle && params.startOffset < params.endOffset && body.textRuns == null);
871
+ if (params.startOffset > 0) textX.push({
872
+ t: TextXActionType.RETAIN,
873
+ len: params.startOffset
874
+ });
875
+ if (params.style.textStyle && params.startOffset < params.endOffset && !initializesTextRuns) textX.push({
876
+ t: TextXActionType.RETAIN,
877
+ len: params.endOffset - params.startOffset,
878
+ coverType: UpdateDocsAttributeType.COVER,
879
+ body: {
880
+ dataStream: "",
881
+ textRuns: [{
882
+ st: 0,
883
+ ed: params.endOffset - params.startOffset,
884
+ ts: Tools.deepClone(params.style.textStyle)
885
+ }]
886
+ }
887
+ });
888
+ else if (params.startOffset < params.endOffset) textX.push({
889
+ t: TextXActionType.RETAIN,
890
+ len: params.endOffset - params.startOffset
891
+ });
892
+ const paragraphBody = {
893
+ dataStream: "",
894
+ paragraphs: [{
895
+ ...Tools.deepClone(paragraph),
896
+ startIndex: 0,
897
+ paragraphStyle: {
898
+ ...Tools.deepClone((_paragraph$paragraphS = paragraph.paragraphStyle) !== null && _paragraph$paragraphS !== void 0 ? _paragraph$paragraphS : {}),
899
+ ...Tools.deepClone(params.style)
900
+ }
901
+ }]
902
+ };
903
+ Object.defineProperty(paragraphBody, RESTORE_INSERTED_PARAGRAPH_IDS, {
904
+ value: true,
905
+ enumerable: true
906
+ });
907
+ textX.push({
908
+ t: TextXActionType.RETAIN,
909
+ len: 1,
910
+ coverType: UpdateDocsAttributeType.REPLACE,
911
+ body: paragraphBody
912
+ });
913
+ return {
914
+ textX,
915
+ initializesTextRuns
916
+ };
917
+ }
918
+ const UpdateDocumentParagraphStyleCommand = {
919
+ id: "doc.command.update-paragraph-style",
920
+ type: CommandType.COMMAND,
921
+ handler: (accessor, params) => {
922
+ var _params$segmentId, _documentDataModel$ge;
923
+ if (!isValidParams(params)) return false;
924
+ const instanceService = accessor.get(IUniverInstanceService);
925
+ const commandService = accessor.get(ICommandService);
926
+ const documentDataModel = instanceService.getUnit(params.unitId, UniverInstanceType.UNIVER_DOC);
927
+ const segmentId = (_params$segmentId = params.segmentId) !== null && _params$segmentId !== void 0 ? _params$segmentId : "";
928
+ const body = documentDataModel === null || documentDataModel === void 0 || (_documentDataModel$ge = documentDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _documentDataModel$ge === void 0 ? void 0 : _documentDataModel$ge.getBody();
929
+ if (!documentDataModel || !body) return false;
930
+ const paragraph = getCurrentParagraph(body, params);
931
+ if (!paragraph) return false;
932
+ const { textX, initializesTextRuns } = createParagraphStyleTextX(body, paragraph, params);
933
+ const jsonX = JSONX.getInstance();
934
+ const path = getRichTextEditPath(documentDataModel, segmentId);
935
+ let actions = jsonX.editOp(textX.serialize(), path);
936
+ if (initializesTextRuns) {
937
+ const initializeTextRunsActions = jsonX.replaceOp([...path, "textRuns"], void 0, [{
938
+ st: params.startOffset,
939
+ ed: params.endOffset,
940
+ ts: Tools.deepClone(params.style.textStyle)
941
+ }]);
942
+ actions = JSONX.compose(initializeTextRunsActions, actions);
943
+ }
944
+ return Boolean(commandService.syncExecuteCommand(RichTextEditingMutation.id, {
945
+ unitId: params.unitId,
946
+ segmentId,
947
+ actions,
948
+ textRanges: null,
949
+ noNeedSetTextRange: true,
950
+ isEditing: false,
951
+ trigger: UpdateDocumentParagraphStyleCommand.id
952
+ }));
953
+ }
954
+ };
955
+
956
+ //#endregion
957
+ //#region src/utils/section-columns.ts
958
+ function resolveSectionValue(sectionValue, documentValue, fallback) {
959
+ var _ref;
960
+ return (_ref = sectionValue !== null && sectionValue !== void 0 ? sectionValue : documentValue) !== null && _ref !== void 0 ? _ref : fallback;
961
+ }
962
+ function getEffectivePageSize(documentStyle, section) {
963
+ var _section$pageSize, _documentStyle$pageSi, _section$pageSize2, _documentStyle$pageSi2;
964
+ const fallback = PAGE_SIZE[PaperType.A4];
965
+ return {
966
+ width: resolveSectionValue(section === null || section === void 0 || (_section$pageSize = section.pageSize) === null || _section$pageSize === void 0 ? void 0 : _section$pageSize.width, documentStyle === null || documentStyle === void 0 || (_documentStyle$pageSi = documentStyle.pageSize) === null || _documentStyle$pageSi === void 0 ? void 0 : _documentStyle$pageSi.width, fallback.width),
967
+ height: resolveSectionValue(section === null || section === void 0 || (_section$pageSize2 = section.pageSize) === null || _section$pageSize2 === void 0 ? void 0 : _section$pageSize2.height, documentStyle === null || documentStyle === void 0 || (_documentStyle$pageSi2 = documentStyle.pageSize) === null || _documentStyle$pageSi2 === void 0 ? void 0 : _documentStyle$pageSi2.height, fallback.height)
968
+ };
969
+ }
970
+ function getEffectiveMargins(documentStyle, section) {
971
+ return {
972
+ top: resolveSectionValue(section === null || section === void 0 ? void 0 : section.marginTop, documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginTop, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN),
973
+ bottom: resolveSectionValue(section === null || section === void 0 ? void 0 : section.marginBottom, documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginBottom, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN),
974
+ left: resolveSectionValue(section === null || section === void 0 ? void 0 : section.marginLeft, documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginLeft, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN),
975
+ right: resolveSectionValue(section === null || section === void 0 ? void 0 : section.marginRight, documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginRight, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN)
976
+ };
977
+ }
978
+ function assertPositivePageSetup(pageSize, contentSize) {
979
+ if (![
980
+ pageSize.width,
981
+ pageSize.height,
982
+ contentSize.width,
983
+ contentSize.height
984
+ ].every((value) => Number.isFinite(value) && value > 0)) throw new RangeError("Effective section page setup must leave a positive content area and use finite positive page dimensions.");
985
+ }
986
+ /** Resolves nominal traditional page geometry without requiring a renderer. */
987
+ function getEffectiveSectionPageSetup(documentStyle, section) {
988
+ var _section$pageNumberSt;
989
+ const pageSize = getEffectivePageSize(documentStyle, section);
990
+ const margins = getEffectiveMargins(documentStyle, section);
991
+ const contentSize = {
992
+ width: getSectionContentWidth(documentStyle, section),
993
+ height: pageSize.height - margins.top - margins.bottom
994
+ };
995
+ assertPositivePageSetup(pageSize, contentSize);
996
+ const pageNumberStart = (_section$pageNumberSt = section === null || section === void 0 ? void 0 : section.pageNumberStart) !== null && _section$pageNumberSt !== void 0 ? _section$pageNumberSt : documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.pageNumberStart;
997
+ return {
998
+ pageSize,
999
+ pageOrient: resolveSectionValue(section === null || section === void 0 ? void 0 : section.pageOrient, documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.pageOrient, PageOrientType.PORTRAIT),
1000
+ margins,
1001
+ contentSize,
1002
+ ...pageNumberStart == null ? {} : { pageNumberStart }
1003
+ };
1004
+ }
1005
+ /** Returns the usable horizontal layout width for a traditional section. */
1006
+ function getSectionContentWidth(documentStyle, section) {
1007
+ var _section$pageSize3, _documentStyle$pageSi3;
1008
+ const pageWidth = resolveSectionValue(section === null || section === void 0 || (_section$pageSize3 = section.pageSize) === null || _section$pageSize3 === void 0 ? void 0 : _section$pageSize3.width, documentStyle === null || documentStyle === void 0 || (_documentStyle$pageSi3 = documentStyle.pageSize) === null || _documentStyle$pageSi3 === void 0 ? void 0 : _documentStyle$pageSi3.width, PAGE_SIZE[PaperType.A4].width);
1009
+ return Math.max(0, pageWidth - resolveSectionValue(section === null || section === void 0 ? void 0 : section.marginLeft, documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginLeft, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN) - resolveSectionValue(section === null || section === void 0 ? void 0 : section.marginRight, documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginRight, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN));
1010
+ }
1011
+ /** Creates explicit OOXML section columns from a count, gap, and optional widths. */
1012
+ function createSectionColumnProperties(documentStyle, section, columnCount, gap, widths) {
1013
+ if (columnCount <= 1) return [];
1014
+ const safeGap = Math.max(0, gap);
1015
+ const contentWidth = getSectionContentWidth(documentStyle, section);
1016
+ const availableWidth = Math.max(0, contentWidth - safeGap * (columnCount - 1));
1017
+ if (widths) {
1018
+ if (widths.some((width) => !Number.isFinite(width) || width < 0)) throw new RangeError("Section column widths must be finite and non-negative.");
1019
+ if (widths.reduce((sum, width) => sum + width, 0) > availableWidth) throw new RangeError("Section columns exceed the available page content width.");
1020
+ }
1021
+ return (widths !== null && widths !== void 0 ? widths : Array.from({ length: columnCount }, () => availableWidth / columnCount)).map((width, index) => ({
1022
+ width: Math.max(0, width),
1023
+ paddingEnd: index === columnCount - 1 ? 0 : safeGap
1024
+ }));
1025
+ }
1026
+
865
1027
  //#endregion
866
1028
  //#region src/commands/commands/update-document-section.command.ts
867
1029
  const UpdateDocumentSectionCommand = {
@@ -880,6 +1042,11 @@ const UpdateDocumentSectionCommand = {
880
1042
  const selectedIds = new Set(updates.keys());
881
1043
  const sections = getTopLevelSectionBreaks(body).filter((section) => selectedIds.has(section.sectionId)).sort((left, right) => left.startIndex - right.startIndex);
882
1044
  if (sections.length !== selectedIds.size) return false;
1045
+ const documentStyle = documentDataModel.getDocumentStyle();
1046
+ if (sections.some((section) => !isValidSectionConfig({
1047
+ ...section,
1048
+ ...updates.get(section.sectionId)
1049
+ }, documentStyle))) return false;
883
1050
  const cursor = new MemoryCursor();
884
1051
  const textX = new TextX();
885
1052
  for (const section of sections) {
@@ -923,25 +1090,70 @@ const InsertDocumentSectionBreakCommand = {
923
1090
  id: "doc.command.insert-section-break",
924
1091
  type: CommandType.COMMAND,
925
1092
  handler: (accessor, params) => {
926
- var _body$sectionBreaks, _body$tables, _body$columnGroups, _body$blockRanges, _params$config;
1093
+ var _params$config, _body$sectionBreaks;
927
1094
  if (!params) return false;
928
1095
  const context = getTraditionalDocumentContext(accessor, params.unitId);
929
- if (!context || !params.sectionId || !Number.isInteger(params.offset)) return false;
1096
+ if (!context || !params.sectionId || !Number.isInteger(params.offset) || params.nextSectionType != null && !isValidEnumValue(SectionType, params.nextSectionType)) return false;
930
1097
  const { body, documentDataModel, commandService } = context;
931
- if (params.offset < 0 || params.offset > body.dataStream.length || ((_body$sectionBreaks = body.sectionBreaks) === null || _body$sectionBreaks === void 0 ? void 0 : _body$sectionBreaks.some((section) => section.sectionId === params.sectionId)) || ((_body$tables = body.tables) === null || _body$tables === void 0 ? void 0 : _body$tables.some((range) => containsInteriorInsertionOffset(getTableRangeInterval(range), params.offset))) || ((_body$columnGroups = body.columnGroups) === null || _body$columnGroups === void 0 ? void 0 : _body$columnGroups.some((range) => containsInteriorInsertionOffset(getColumnGroupRangeInterval(range), params.offset))) || ((_body$blockRanges = body.blockRanges) === null || _body$blockRanges === void 0 ? void 0 : _body$blockRanges.some((range) => containsInteriorInsertionOffset(getBlockRangeInterval(range), params.offset)))) return false;
1098
+ const insertedSection = {
1099
+ ...Tools.deepClone((_params$config = params.config) !== null && _params$config !== void 0 ? _params$config : {}),
1100
+ sectionId: params.sectionId,
1101
+ startIndex: params.offset
1102
+ };
1103
+ if (!isValidTopLevelInsertionOffset(body, params.offset) || ((_body$sectionBreaks = body.sectionBreaks) === null || _body$sectionBreaks === void 0 ? void 0 : _body$sectionBreaks.some((section) => section.sectionId === params.sectionId)) || !isValidSectionConfig(insertedSection, documentDataModel.getDocumentStyle())) return false;
1104
+ const nextSection = params.nextSectionType == null ? void 0 : getTopLevelSectionBreaks(body).find((section) => section.startIndex >= params.offset);
1105
+ if (params.nextSectionType != null && !nextSection) return false;
932
1106
  const textX = new TextX();
933
1107
  textX.retain(params.offset);
934
1108
  textX.insert(1, {
935
1109
  dataStream: DataStreamTreeTokenType.SECTION_BREAK,
936
1110
  sectionBreaks: [{
937
- ...Tools.deepClone((_params$config = params.config) !== null && _params$config !== void 0 ? _params$config : {}),
938
- sectionId: params.sectionId,
1111
+ ...insertedSection,
939
1112
  startIndex: 0
940
1113
  }]
941
1114
  });
1115
+ if (nextSection && params.nextSectionType != null) {
1116
+ textX.retain(nextSection.startIndex - params.offset);
1117
+ textX.push({
1118
+ t: TextXActionType.RETAIN,
1119
+ len: 1,
1120
+ coverType: UpdateDocsAttributeType.REPLACE,
1121
+ body: {
1122
+ dataStream: "",
1123
+ sectionBreaks: [{
1124
+ ...Tools.deepClone(nextSection),
1125
+ sectionType: params.nextSectionType,
1126
+ startIndex: 0
1127
+ }]
1128
+ }
1129
+ });
1130
+ }
942
1131
  return executeSectionTextX(commandService, documentDataModel, textX, InsertDocumentSectionBreakCommand.id);
943
1132
  }
944
1133
  };
1134
+ const InsertDocumentColumnBreakCommand = {
1135
+ id: "doc.command.insert-column-break",
1136
+ type: CommandType.COMMAND,
1137
+ handler: (accessor, params) => {
1138
+ if (!params) return false;
1139
+ const context = getTraditionalDocumentContext(accessor, params.unitId);
1140
+ if (!context || !isValidTopLevelInsertionOffset(context.body, params.offset)) return false;
1141
+ const textX = new TextX();
1142
+ textX.retain(params.offset);
1143
+ textX.insert(1, {
1144
+ dataStream: DataStreamTreeTokenType.COLUMN_BREAK,
1145
+ customRanges: [{
1146
+ startIndex: 0,
1147
+ endIndex: 0,
1148
+ rangeId: `docx-break-${generateRandomId()}`,
1149
+ rangeType: CustomRangeType.CUSTOM,
1150
+ wholeEntity: true,
1151
+ properties: { docxBreakType: DocxBreakType.COLUMN }
1152
+ }]
1153
+ });
1154
+ return executeSectionTextX(context.commandService, context.documentDataModel, textX, InsertDocumentColumnBreakCommand.id);
1155
+ }
1156
+ };
945
1157
  const DeleteDocumentSectionBreakCommand = {
946
1158
  id: "doc.command.delete-section-break",
947
1159
  type: CommandType.COMMAND,
@@ -952,7 +1164,7 @@ const DeleteDocumentSectionBreakCommand = {
952
1164
  const sections = getTopLevelSectionBreaks(context.body);
953
1165
  if (sections.length <= 1) return false;
954
1166
  const section = sections.find((item) => item.sectionId === params.sectionId);
955
- if (!section) return false;
1167
+ if (!section || section === sections.at(-1)) return false;
956
1168
  const textX = new TextX();
957
1169
  textX.retain(section.startIndex);
958
1170
  textX.delete(1);
@@ -970,6 +1182,39 @@ function getTraditionalDocumentContext(accessor, unitId) {
970
1182
  commandService: accessor.get(ICommandService)
971
1183
  };
972
1184
  }
1185
+ function isValidTopLevelInsertionOffset(body, offset) {
1186
+ var _body$tables, _body$columnGroups, _body$blockRanges;
1187
+ return Number.isInteger(offset) && offset >= 0 && offset <= body.dataStream.length && !((_body$tables = body.tables) === null || _body$tables === void 0 ? void 0 : _body$tables.some((range) => containsInteriorInsertionOffset(getTableRangeInterval(range), offset))) && !((_body$columnGroups = body.columnGroups) === null || _body$columnGroups === void 0 ? void 0 : _body$columnGroups.some((range) => containsInteriorInsertionOffset(getColumnGroupRangeInterval(range), offset))) && !((_body$blockRanges = body.blockRanges) === null || _body$blockRanges === void 0 ? void 0 : _body$blockRanges.some((range) => containsInteriorInsertionOffset(getBlockRangeInterval(range), offset)));
1188
+ }
1189
+ function isValidSectionConfig(section, documentStyle) {
1190
+ var _section$pageSize, _ref, _section$marginTop, _ref2, _section$marginBottom, _ref3, _section$marginLeft, _ref4, _section$marginRight, _section$columnProper;
1191
+ if (section.sectionType != null && !isValidEnumValue(SectionType, section.sectionType)) return false;
1192
+ if (section.pageOrient != null && !isValidEnumValue(PageOrientType, section.pageOrient)) return false;
1193
+ if (section.columnSeparatorType != null && !isValidEnumValue(ColumnSeparatorType, section.columnSeparatorType)) return false;
1194
+ if (section.pageNumberStart != null && (!Number.isInteger(section.pageNumberStart) || section.pageNumberStart < 1)) return false;
1195
+ if (section.pageSize && (!isPositiveFinite(section.pageSize.width) || !isPositiveFinite(section.pageSize.height))) return false;
1196
+ if ([
1197
+ section.marginTop,
1198
+ section.marginBottom,
1199
+ section.marginLeft,
1200
+ section.marginRight
1201
+ ].some((margin) => margin != null && (!Number.isFinite(margin) || margin < 0))) return false;
1202
+ const pageSize = (_section$pageSize = section.pageSize) !== null && _section$pageSize !== void 0 ? _section$pageSize : documentStyle.pageSize;
1203
+ const marginTop = (_ref = (_section$marginTop = section.marginTop) !== null && _section$marginTop !== void 0 ? _section$marginTop : documentStyle.marginTop) !== null && _ref !== void 0 ? _ref : 0;
1204
+ const marginBottom = (_ref2 = (_section$marginBottom = section.marginBottom) !== null && _section$marginBottom !== void 0 ? _section$marginBottom : documentStyle.marginBottom) !== null && _ref2 !== void 0 ? _ref2 : 0;
1205
+ const marginLeft = (_ref3 = (_section$marginLeft = section.marginLeft) !== null && _section$marginLeft !== void 0 ? _section$marginLeft : documentStyle.marginLeft) !== null && _ref3 !== void 0 ? _ref3 : 0;
1206
+ const marginRight = (_ref4 = (_section$marginRight = section.marginRight) !== null && _section$marginRight !== void 0 ? _section$marginRight : documentStyle.marginRight) !== null && _ref4 !== void 0 ? _ref4 : 0;
1207
+ if ((pageSize === null || pageSize === void 0 ? void 0 : pageSize.width) != null && marginLeft + marginRight >= pageSize.width || (pageSize === null || pageSize === void 0 ? void 0 : pageSize.height) != null && marginTop + marginBottom >= pageSize.height) return false;
1208
+ const columns = (_section$columnProper = section.columnProperties) !== null && _section$columnProper !== void 0 ? _section$columnProper : [];
1209
+ if (columns.some(({ width, paddingEnd }) => !Number.isFinite(width) || !Number.isFinite(paddingEnd) || width < 0 || paddingEnd < 0)) return false;
1210
+ return columns.reduce((sum, { width, paddingEnd }) => sum + width + paddingEnd, 0) <= getSectionContentWidth(documentStyle, section);
1211
+ }
1212
+ function isPositiveFinite(value) {
1213
+ return value != null && Number.isFinite(value) && value > 0;
1214
+ }
1215
+ function isValidEnumValue(enumObject, value) {
1216
+ return Object.values(enumObject).includes(value);
1217
+ }
973
1218
  function executeSectionTextX(commandService, documentDataModel, textX, trigger) {
974
1219
  const actions = JSONX.getInstance().editOp(textX.serialize(), getRichTextEditPath(documentDataModel));
975
1220
  return Boolean(commandService.syncExecuteCommand(RichTextEditingMutation.id, {
@@ -1150,7 +1395,7 @@ function composeActions(actions) {
1150
1395
  //#endregion
1151
1396
  //#region package.json
1152
1397
  var name = "@univerjs/docs";
1153
- var version = "1.0.0-alpha.7";
1398
+ var version = "1.0.0-alpha.8";
1154
1399
 
1155
1400
  //#endregion
1156
1401
  //#region src/commands/mutations/docs-rename.mutation.ts
@@ -1228,7 +1473,7 @@ let DocCustomRangeController = class DocCustomRangeController extends Disposable
1228
1473
  const doc = this._univerInstanceService.getUnit(unitId);
1229
1474
  if (!doc) return;
1230
1475
  const transformedRanges = ranges.map((range) => this._transformCustomRange(doc, range));
1231
- if (transformedRanges.some((range, i) => ranges[i] !== range)) this._textSelectionManagerService.replaceTextRanges(transformedRanges, isEditing);
1476
+ if (transformedRanges.some((range, i) => ranges[i] !== range)) this._textSelectionManagerService.replaceDocRanges(transformedRanges, void 0, isEditing);
1232
1477
  }
1233
1478
  }));
1234
1479
  }
@@ -1452,6 +1697,82 @@ DocStateChangeManagerService = __decorate([
1452
1697
  __decorateParam(4, Optional(IDocStateChangeInterceptorService))
1453
1698
  ], DocStateChangeManagerService);
1454
1699
 
1700
+ //#endregion
1701
+ //#region src/services/doc-text-resolver.service.ts
1702
+ /**
1703
+ * Builds a consumer-facing text projection while retaining a mapping back to
1704
+ * the native document offsets.
1705
+ *
1706
+ * Consumers such as find/replace can search the projected text and then use
1707
+ * `characters` to focus the native object that supplied a matching character.
1708
+ * Resolvers must return half-open, non-overlapping replacements.
1709
+ */
1710
+ var DocTextResolverService = class extends Disposable {
1711
+ constructor(..._args) {
1712
+ super(..._args);
1713
+ _defineProperty(this, "_resolvers", /* @__PURE__ */ new Set());
1714
+ _defineProperty(this, "_textChanged$", new Subject());
1715
+ _defineProperty(this, "textChanged$", this._textChanged$.asObservable());
1716
+ }
1717
+ register(resolver) {
1718
+ this._resolvers.add(resolver);
1719
+ return toDisposable(() => this._resolvers.delete(resolver));
1720
+ }
1721
+ notifyTextChanged(unitId) {
1722
+ this._textChanged$.next(unitId);
1723
+ }
1724
+ resolve(unitId, body) {
1725
+ const replacements = this._collectReplacements(unitId, body);
1726
+ const characters = [];
1727
+ let text = "";
1728
+ let sourceOffset = 0;
1729
+ for (const replacement of replacements) {
1730
+ const sourceText = body.dataStream.slice(sourceOffset, replacement.startOffset);
1731
+ text += sourceText;
1732
+ for (let index = sourceOffset; index < replacement.startOffset; index += 1) characters.push({
1733
+ startOffset: index,
1734
+ endOffset: index + 1,
1735
+ replaceable: true
1736
+ });
1737
+ text += replacement.text;
1738
+ for (let index = 0; index < replacement.text.length; index += 1) {
1739
+ var _replacement$replacea;
1740
+ characters.push({
1741
+ startOffset: replacement.startOffset,
1742
+ endOffset: replacement.endOffset,
1743
+ replaceable: (_replacement$replacea = replacement.replaceable) !== null && _replacement$replacea !== void 0 ? _replacement$replacea : false
1744
+ });
1745
+ }
1746
+ sourceOffset = replacement.endOffset;
1747
+ }
1748
+ text += body.dataStream.slice(sourceOffset);
1749
+ for (let index = sourceOffset; index < body.dataStream.length; index += 1) characters.push({
1750
+ startOffset: index,
1751
+ endOffset: index + 1,
1752
+ replaceable: true
1753
+ });
1754
+ return {
1755
+ characters,
1756
+ text
1757
+ };
1758
+ }
1759
+ _collectReplacements(unitId, body) {
1760
+ const candidates = [...this._resolvers].flatMap((resolver) => resolver.resolve(unitId, body)).filter((replacement) => Number.isInteger(replacement.startOffset) && Number.isInteger(replacement.endOffset) && replacement.startOffset >= 0 && replacement.endOffset > replacement.startOffset && replacement.endOffset <= body.dataStream.length).sort((left, right) => left.startOffset - right.startOffset || right.endOffset - left.endOffset);
1761
+ const replacements = [];
1762
+ let previousEnd = -1;
1763
+ for (const candidate of candidates) {
1764
+ if (candidate.startOffset < previousEnd) continue;
1765
+ replacements.push(candidate);
1766
+ previousEnd = candidate.endOffset;
1767
+ }
1768
+ return replacements;
1769
+ }
1770
+ dispose() {
1771
+ this._textChanged$.complete();
1772
+ super.dispose();
1773
+ }
1774
+ };
1775
+
1455
1776
  //#endregion
1456
1777
  //#region src/plugin.ts
1457
1778
  let UniverDocsPlugin = class UniverDocsPlugin extends Plugin {
@@ -1475,8 +1796,10 @@ let UniverDocsPlugin = class UniverDocsPlugin extends Plugin {
1475
1796
  CreateHeaderFooterCommand,
1476
1797
  SetDocumentDefaultParagraphStyleCommand,
1477
1798
  SetSectionHeaderFooterLinkCommand,
1799
+ UpdateDocumentParagraphStyleCommand,
1478
1800
  UpdateDocumentSectionCommand,
1479
1801
  InsertDocumentSectionBreakCommand,
1802
+ InsertDocumentColumnBreakCommand,
1480
1803
  DeleteDocumentSectionBreakCommand,
1481
1804
  RichTextEditingMutation,
1482
1805
  DocsRenameMutation,
@@ -1492,6 +1815,7 @@ let UniverDocsPlugin = class UniverDocsPlugin extends Plugin {
1492
1815
  [DocStateChangeManagerService],
1493
1816
  [DocBlockMoveValidatorService],
1494
1817
  [DocContentInsertService],
1818
+ [DocTextResolverService],
1495
1819
  [DocCustomRangeController]
1496
1820
  ].forEach((d) => this._injector.add(d));
1497
1821
  }
@@ -1745,22 +2069,6 @@ function replaceSelectionFactory(accessor, params) {
1745
2069
  return doMutation;
1746
2070
  }
1747
2071
 
1748
- //#endregion
1749
- //#region src/utils/section-columns.ts
1750
- /** Creates explicit OOXML section columns from a count, gap, and optional widths. */
1751
- function createSectionColumnProperties(documentStyle, section, columnCount, gap, widths) {
1752
- var _ref, _section$pageSize$wid, _section$pageSize, _documentStyle$pageSi, _ref2, _section$marginLeft, _ref3, _section$marginRight;
1753
- if (columnCount <= 1) return [];
1754
- const safeGap = Math.max(0, gap);
1755
- const pageWidth = (_ref = (_section$pageSize$wid = section === null || section === void 0 || (_section$pageSize = section.pageSize) === null || _section$pageSize === void 0 ? void 0 : _section$pageSize.width) !== null && _section$pageSize$wid !== void 0 ? _section$pageSize$wid : documentStyle === null || documentStyle === void 0 || (_documentStyle$pageSi = documentStyle.pageSize) === null || _documentStyle$pageSi === void 0 ? void 0 : _documentStyle$pageSi.width) !== null && _ref !== void 0 ? _ref : PAGE_SIZE[PaperType.A4].width;
1756
- const contentWidth = Math.max(0, pageWidth - ((_ref2 = (_section$marginLeft = section === null || section === void 0 ? void 0 : section.marginLeft) !== null && _section$marginLeft !== void 0 ? _section$marginLeft : documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginLeft) !== null && _ref2 !== void 0 ? _ref2 : 72) - ((_ref3 = (_section$marginRight = section === null || section === void 0 ? void 0 : section.marginRight) !== null && _section$marginRight !== void 0 ? _section$marginRight : documentStyle === null || documentStyle === void 0 ? void 0 : documentStyle.marginRight) !== null && _ref3 !== void 0 ? _ref3 : 72));
1757
- const availableWidth = Math.max(0, contentWidth - safeGap * (columnCount - 1));
1758
- return (widths !== null && widths !== void 0 ? widths : Array.from({ length: columnCount }, () => availableWidth / columnCount)).map((width, index) => ({
1759
- width: Math.max(0, width),
1760
- paddingEnd: index === columnCount - 1 ? 0 : safeGap
1761
- }));
1762
- }
1763
-
1764
2072
  //#endregion
1765
2073
  //#region src/utils/transform-position.ts
1766
2074
  function buildDocTransform(width, height, position) {
@@ -1846,4 +2154,4 @@ function normalizeTextRange(textRange) {
1846
2154
  }
1847
2155
 
1848
2156
  //#endregion
1849
- export { CreateHeaderFooterCommand, DOC_INTERCEPTOR_POINT, DeleteDocumentSectionBreakCommand, DeleteTextCommand, DocBlockMoveValidatorService, DocContentInsertService, DocInterceptorService, DocSelectionManagerService, DocSkeletonManagerService, DocStateChangeManagerService, DocStateEmitService, EMBED_DOCS_CUSTOM_BLOCK_DEFAULT_COMPONENT_KEY, HeaderFooterType, IDocStateChangeInterceptorService, InsertDocumentSectionBreakCommand, InsertTextCommand, RichTextEditingMutation, SetDocumentDefaultParagraphStyleCommand, SetSectionHeaderFooterLinkCommand, SetTextSelectionsOperation, UniverDocsPlugin, UpdateDocumentSectionCommand, UpdateTextCommand, addCustomRangeBySelectionFactory, addCustomRangeFactory, buildDocTransform, consumeContentInsertRange, createDocsCustomBlockDrawing, createDocsCustomBlockInsertMutation, createDocsCustomBlockRemoveMutation, createEmbedDocsCustomBlockData, createInsertCustomBlockActions, createRemoveCustomBlockActions, createSectionColumnProperties, deleteCustomRangeFactory, docDrawingPositionToTransform, generateParagraphs, getContentInsertRange, getTopLevelSectionBreaks, isEmbedDocsCustomBlockData, isHeaderFooterSelection, isSheetLikeDocsCustomBlockChildType, normalizeTextRange, replaceSelectionFactory, resolveDocsCustomBlockSize, shouldUseInlineTextSelectionForDocsCustomBlockDrawing, transformToDocDrawingPosition };
2157
+ export { CreateHeaderFooterCommand, DOC_INTERCEPTOR_POINT, DOC_SELECTION_OPTION_PRESERVE_CARET, DeleteDocumentSectionBreakCommand, DeleteTextCommand, DocBlockMoveValidatorService, DocContentInsertService, DocInterceptorService, DocSelectionManagerService, DocSkeletonManagerService, DocStateChangeManagerService, DocStateEmitService, DocTextResolverService, EMBED_DOCS_CUSTOM_BLOCK_DEFAULT_COMPONENT_KEY, HeaderFooterType, IDocStateChangeInterceptorService, InsertDocumentColumnBreakCommand, InsertDocumentSectionBreakCommand, InsertTextCommand, RichTextEditingMutation, SetDocumentDefaultParagraphStyleCommand, SetSectionHeaderFooterLinkCommand, SetTextSelectionsOperation, UniverDocsPlugin, UpdateDocumentParagraphStyleCommand, UpdateDocumentSectionCommand, UpdateTextCommand, addCustomRangeBySelectionFactory, addCustomRangeFactory, buildDocTransform, consumeContentInsertRange, createDocsCustomBlockDrawing, createDocsCustomBlockInsertMutation, createDocsCustomBlockRemoveMutation, createEmbedDocsCustomBlockData, createInsertCustomBlockActions, createRemoveCustomBlockActions, createSectionColumnProperties, deleteCustomRangeFactory, docDrawingPositionToTransform, generateParagraphs, getContentInsertRange, getEffectiveSectionPageSetup, getSectionContentWidth, getTopLevelSectionBreaks, isEmbedDocsCustomBlockData, isHeaderFooterSelection, isSheetLikeDocsCustomBlockChildType, normalizeTextRange, replaceSelectionFactory, resolveDocsCustomBlockSize, shouldUseInlineTextSelectionForDocsCustomBlockDrawing, transformToDocDrawingPosition };