@stll/folio-core 0.61.0 → 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-edits/headless.js +13 -12
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +26 -7
- package/dist/display-list/build/paragraphPrimitives.js +15 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -5
- package/dist/display-list/types.d.ts +7 -3
- package/dist/docx/groupDrawingParser.js +22 -12
- package/dist/i18n/messages/ar.gen.js +1 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
- package/dist/i18n/messages/catalogs.gen.js +17 -0
- package/dist/i18n/messages/cs.gen.js +1 -0
- package/dist/i18n/messages/de.gen.js +1 -0
- package/dist/i18n/messages/en.gen.js +1 -0
- package/dist/i18n/messages/es.gen.js +1 -0
- package/dist/i18n/messages/et.gen.js +1 -0
- package/dist/i18n/messages/fr.gen.js +1 -0
- package/dist/i18n/messages/he.gen.js +1 -0
- package/dist/i18n/messages/hi.gen.js +1 -0
- package/dist/i18n/messages/hu.gen.js +1 -0
- package/dist/i18n/messages/lt.gen.js +1 -0
- package/dist/i18n/messages/lv.gen.js +1 -0
- package/dist/i18n/messages/messages.gen.d.ts +1 -0
- package/dist/i18n/messages/pl.gen.js +1 -0
- package/dist/i18n/messages/pt-BR.gen.js +1 -0
- package/dist/i18n/messages/sk.gen.js +1 -0
- package/dist/i18n/messages/tr.gen.js +1 -0
- package/dist/i18n/messages/zh-CN.gen.js +1 -0
- package/dist/layout-bridge/convert/endnoteLayout.d.ts +1 -1
- package/dist/layout-bridge/convert/endnoteLayout.js +1 -3
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/noteAreaFlow.d.ts +4 -4
- package/dist/layout-engine/noteAreaFlow.js +12 -6
- package/dist/layout-engine/types.d.ts +5 -2
- package/dist/layout-painter/index.d.ts +1 -1
- package/dist/managers/FindReplaceManager.d.ts +13 -6
- package/dist/managers/FindReplaceManager.js +15 -9
- package/dist/paged-layout/editorScrollRoot.d.ts +3 -1
- package/dist/paged-layout/editorScrollRoot.js +2 -2
- package/dist/pdf/images.js +1 -0
- package/dist/prosemirror/commentRangeInlineAtoms.d.ts +40 -0
- package/dist/prosemirror/commentRangeInlineAtoms.js +33 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +5 -4
- package/dist/prosemirror/conversion/toProseDoc.js +12 -19
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +4 -4
- package/dist/prosemirror/fieldRepresentation.js +4 -2
- package/dist/prosemirror/findReplaceSelection.d.ts +38 -2
- package/dist/prosemirror/findReplaceSelection.js +143 -42
- package/dist/prosemirror/inlineDisplayText.d.ts +10 -0
- package/dist/prosemirror/inlineDisplayText.js +29 -0
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
- package/dist/utils/findMatchView.d.ts +32 -0
- package/dist/utils/findMatchView.js +406 -0
- package/dist/utils/findReplace.d.ts +62 -4
- package/dist/utils/findReplace.js +359 -37
- package/dist/utils/findSearchKey.d.ts +29 -0
- package/dist/utils/findSearchKey.js +34 -0
- package/dist/utils/replaceText.js +138 -111
- package/package.json +1 -1
|
@@ -1,38 +1,33 @@
|
|
|
1
1
|
import { cloneDocumentWithParagraphPropertySources } from "../docx/paragraphPropertySource.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
|
|
5
|
-
import { resolveFindMatchRange } from "../prosemirror/findReplaceSelection.js";
|
|
6
|
-
import { schema } from "../prosemirror/schema/index.js";
|
|
7
|
-
import { EditorState } from "prosemirror-state";
|
|
2
|
+
import { getFindParagraphText } from "./findReplace.js";
|
|
3
|
+
import { panic } from "better-result";
|
|
8
4
|
//#region src/utils/replaceText.ts
|
|
9
|
-
/**
|
|
10
|
-
* Lightweight text replacement on the document model.
|
|
11
|
-
* Used by find & replace. Operates immutably.
|
|
12
|
-
*/
|
|
13
5
|
/** Replace text within a range in the document. Returns a new document. */
|
|
14
6
|
function replaceTextInDocument(doc, range, text, formatting) {
|
|
15
7
|
const newDoc = cloneDocumentWithParagraphPropertySources(doc);
|
|
16
8
|
const body = newDoc.package.document;
|
|
17
9
|
const { start, end } = range;
|
|
18
10
|
if (start.paragraphIndex === end.paragraphIndex) {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
const paragraph = getParagraphByIndex(body, start.paragraphIndex);
|
|
12
|
+
if (!paragraph) return newDoc;
|
|
13
|
+
replaceTextInParagraph({
|
|
14
|
+
paragraph,
|
|
22
15
|
startOffset: start.offset,
|
|
23
|
-
endOffset: end.offset
|
|
16
|
+
endOffset: end.offset,
|
|
17
|
+
text,
|
|
18
|
+
...formatting && { formatting }
|
|
24
19
|
});
|
|
25
|
-
if (proseRange === null) return newDoc;
|
|
26
|
-
const transaction = EditorState.create({ doc: proseDoc }).tr;
|
|
27
|
-
if (text.length > 0 && formatting !== void 0) transaction.replaceWith(proseRange.from, proseRange.to, schema.text(text, textFormattingToMarks(formatting)));
|
|
28
|
-
else transaction.insertText(text, proseRange.from, proseRange.to);
|
|
29
|
-
return fromProseDoc(transaction.doc, newDoc, { stylesheetSource: { type: "package" } });
|
|
30
20
|
} else {
|
|
31
21
|
const startParagraph = getParagraphByIndex(body, start.paragraphIndex);
|
|
32
22
|
if (!startParagraph) return newDoc;
|
|
33
|
-
const startText =
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
const startText = getFindParagraphText(startParagraph);
|
|
24
|
+
replaceTextInParagraph({
|
|
25
|
+
paragraph: startParagraph,
|
|
26
|
+
startOffset: start.offset,
|
|
27
|
+
endOffset: startText.length,
|
|
28
|
+
text,
|
|
29
|
+
...formatting && { formatting }
|
|
30
|
+
});
|
|
36
31
|
const paragraphsToRemove = [];
|
|
37
32
|
for (let i = start.paragraphIndex + 1; i <= end.paragraphIndex; i++) paragraphsToRemove.push(getTopLevelParagraphBlockIndex(body, i));
|
|
38
33
|
for (let i = paragraphsToRemove.length - 1; i >= 0; i--) {
|
|
@@ -74,107 +69,139 @@ function getParagraphByIndex(body, paragraphIndex) {
|
|
|
74
69
|
};
|
|
75
70
|
return walkBlocks(body.content);
|
|
76
71
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for (const c of child.content) if (c.type === "text") text += c.text;
|
|
84
|
-
}
|
|
85
|
-
return text;
|
|
86
|
-
}
|
|
87
|
-
function deleteTextInParagraph(paragraph, startOffset, endOffset) {
|
|
88
|
-
const result = [];
|
|
89
|
-
let currentOffset = 0;
|
|
90
|
-
for (const item of paragraph.content) if (item.type === "run") {
|
|
91
|
-
const newContent = [];
|
|
92
|
-
for (const content of item.content) if (content.type === "text") {
|
|
93
|
-
const textStart = currentOffset;
|
|
94
|
-
const textEnd = currentOffset + content.text.length;
|
|
95
|
-
if (textEnd <= startOffset || textStart >= endOffset) newContent.push(content);
|
|
96
|
-
else {
|
|
97
|
-
let newText = "";
|
|
98
|
-
if (textStart < startOffset) newText += content.text.slice(0, startOffset - textStart);
|
|
99
|
-
if (textEnd > endOffset) newText += content.text.slice(endOffset - textStart);
|
|
100
|
-
if (newText) newContent.push({
|
|
101
|
-
...content,
|
|
102
|
-
text: newText
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
currentOffset = textEnd;
|
|
106
|
-
} else newContent.push(content);
|
|
107
|
-
if (newContent.length > 0) result.push({
|
|
108
|
-
...item,
|
|
109
|
-
content: newContent
|
|
110
|
-
});
|
|
111
|
-
} else result.push(item);
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
function insertTextAtOffset(paragraph, offset, text, formatting) {
|
|
115
|
-
if (!text) return paragraph.content;
|
|
72
|
+
const itemTextLength = (item) => getFindParagraphText({
|
|
73
|
+
type: "paragraph",
|
|
74
|
+
content: [item]
|
|
75
|
+
}).length;
|
|
76
|
+
/** Walk authored offsets once, preserving wrappers and opaque source units. */
|
|
77
|
+
const replaceTextInParagraph = ({ paragraph, startOffset, endOffset, text, formatting }) => {
|
|
116
78
|
let currentOffset = 0;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
79
|
+
let inserted = false;
|
|
80
|
+
const visit = (items) => {
|
|
81
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
82
|
+
const item = items.at(itemIndex);
|
|
83
|
+
if (!item) continue;
|
|
84
|
+
switch (item.type) {
|
|
85
|
+
case "run": {
|
|
86
|
+
const before = [];
|
|
87
|
+
const after = [];
|
|
88
|
+
let splitAtInsertion = false;
|
|
89
|
+
for (const unit of item.content) {
|
|
90
|
+
const unitStart = currentOffset;
|
|
91
|
+
const unitText = getFindParagraphText({
|
|
92
|
+
type: "paragraph",
|
|
93
|
+
content: [{
|
|
94
|
+
type: "run",
|
|
95
|
+
content: [unit]
|
|
96
|
+
}]
|
|
97
|
+
});
|
|
98
|
+
const unitLength = unitText.length;
|
|
99
|
+
const unitEnd = unitStart + unitLength;
|
|
100
|
+
currentOffset = unitEnd;
|
|
101
|
+
const output = splitAtInsertion ? after : before;
|
|
102
|
+
if (unit.type === "preservedXml" || unitLength === 0) {
|
|
103
|
+
output.push(unit);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const overlaps = unitEnd > startOffset && unitStart < endOffset;
|
|
107
|
+
if (!overlaps && !(!inserted && startOffset === endOffset && startOffset >= unitStart && startOffset <= unitEnd)) {
|
|
108
|
+
output.push(unit);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (unit.type !== "text" && !overlaps) {
|
|
112
|
+
if (startOffset === unitEnd) output.push(unit);
|
|
113
|
+
inserted = true;
|
|
114
|
+
if (formatting) splitAtInsertion = true;
|
|
115
|
+
else if (text) output.push({
|
|
116
|
+
type: "text",
|
|
117
|
+
text
|
|
118
|
+
});
|
|
119
|
+
if (startOffset === unitStart) (splitAtInsertion ? after : before).push(unit);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const prefix = unitText.slice(0, Math.max(0, startOffset - unitStart));
|
|
123
|
+
const suffix = unitText.slice(Math.max(0, endOffset - unitStart));
|
|
124
|
+
if (prefix) output.push({
|
|
125
|
+
type: "text",
|
|
126
|
+
text: prefix
|
|
127
|
+
});
|
|
128
|
+
if (!inserted) {
|
|
129
|
+
inserted = true;
|
|
130
|
+
if (formatting) splitAtInsertion = true;
|
|
131
|
+
else if (text) output.push({
|
|
132
|
+
type: "text",
|
|
133
|
+
text
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (suffix) (splitAtInsertion ? after : before).push({
|
|
137
|
+
type: "text",
|
|
138
|
+
text: suffix
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (!splitAtInsertion) {
|
|
142
|
+
item.content = before;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
const replacement = [];
|
|
146
|
+
if (before.length > 0) replacement.push({
|
|
147
|
+
...item,
|
|
148
|
+
content: before
|
|
131
149
|
});
|
|
132
|
-
|
|
133
|
-
type: "text",
|
|
134
|
-
text
|
|
135
|
-
};
|
|
136
|
-
item.content.splice(ci, 1, ...newContent);
|
|
137
|
-
const insertRun = {
|
|
150
|
+
if (text) replacement.push({
|
|
138
151
|
type: "run",
|
|
139
|
-
content: [
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
type: "text",
|
|
145
|
-
text: after
|
|
152
|
+
content: [{
|
|
153
|
+
type: "text",
|
|
154
|
+
text
|
|
155
|
+
}],
|
|
156
|
+
...formatting && { formatting }
|
|
146
157
|
});
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
paragraph.content.splice(idx + 1, 0, insertRun);
|
|
155
|
-
if (afterItems.length > 0 || remaining.length > 0) paragraph.content.splice(idx + 2, 0, afterRun);
|
|
156
|
-
return paragraph.content;
|
|
158
|
+
if (after.length > 0) replacement.push({
|
|
159
|
+
...item,
|
|
160
|
+
content: after
|
|
161
|
+
});
|
|
162
|
+
items.splice(itemIndex, 1, ...replacement);
|
|
163
|
+
itemIndex += replacement.length - 1;
|
|
164
|
+
break;
|
|
157
165
|
}
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
case "hyperlink":
|
|
167
|
+
visit(item.children);
|
|
168
|
+
break;
|
|
169
|
+
case "inlineWrapper":
|
|
170
|
+
case "inlineSdt":
|
|
171
|
+
case "insertion":
|
|
172
|
+
case "deletion":
|
|
173
|
+
case "moveFrom":
|
|
174
|
+
case "moveTo":
|
|
175
|
+
visit(item.content);
|
|
176
|
+
break;
|
|
177
|
+
case "simpleField":
|
|
178
|
+
case "complexField":
|
|
179
|
+
case "preservedInline":
|
|
180
|
+
case "mathEquation":
|
|
181
|
+
case "bookmarkStart":
|
|
182
|
+
case "bookmarkEnd":
|
|
183
|
+
case "commentRangeStart":
|
|
184
|
+
case "commentRangeEnd":
|
|
185
|
+
case "commentReference":
|
|
186
|
+
case "moveFromRangeStart":
|
|
187
|
+
case "moveFromRangeEnd":
|
|
188
|
+
case "moveToRangeStart":
|
|
189
|
+
case "moveToRangeEnd":
|
|
190
|
+
currentOffset += itemTextLength(item);
|
|
191
|
+
break;
|
|
192
|
+
default: panic("Unsupported replacement paragraph content", { content: item });
|
|
160
193
|
}
|
|
161
|
-
currentOffset = textEnd;
|
|
162
194
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (
|
|
166
|
-
type: "text",
|
|
167
|
-
text
|
|
168
|
-
});
|
|
169
|
-
else paragraph.content.push({
|
|
195
|
+
};
|
|
196
|
+
visit(paragraph.content);
|
|
197
|
+
if (!inserted && startOffset === endOffset && startOffset === currentOffset && text) paragraph.content.push({
|
|
170
198
|
type: "run",
|
|
171
199
|
content: [{
|
|
172
200
|
type: "text",
|
|
173
201
|
text
|
|
174
202
|
}],
|
|
175
|
-
formatting
|
|
203
|
+
...formatting ? { formatting } : {}
|
|
176
204
|
});
|
|
177
|
-
|
|
178
|
-
}
|
|
205
|
+
};
|
|
179
206
|
//#endregion
|
|
180
207
|
export { replaceTextInDocument };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.62.0",
|
|
4
4
|
"description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"document-model",
|