@stll/folio-core 0.60.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/README.md +13 -0
- package/dist/ai-edits/apply.js +139 -32
- package/dist/ai-edits/headless.d.ts +3 -0
- package/dist/ai-edits/headless.js +70 -75
- package/dist/ai-edits/note-story-inventory.d.ts +7 -0
- package/dist/ai-edits/note-story-inventory.js +11 -0
- package/dist/ai-edits/read.js +16 -9
- package/dist/ai-edits/revisionStretches.js +52 -1
- package/dist/ai-edits/table-row-column-mutations.js +6 -1
- package/dist/compare/reproducible-package.js +2 -1
- package/dist/compare/verification.js +1 -0
- package/dist/compat/eigenpal.d.ts +3 -1
- package/dist/controller/canonicalClipboard.js +2 -1
- package/dist/controller/canonicalListRendering.d.ts +4 -6
- package/dist/controller/canonicalListRendering.js +3 -157
- package/dist/controller/headerFooterEditorManager.d.ts +1 -0
- package/dist/controller/headerFooterEditorManager.js +11 -0
- package/dist/controller/hiddenEditorManager.d.ts +1 -1
- package/dist/controller/hiddenEditorManager.js +3 -1
- package/dist/controller/layoutPipeline.d.ts +3 -1
- package/dist/controller/layoutPipeline.js +13 -4
- package/dist/controller/layoutSession.d.ts +2 -1
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +28 -12
- 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/canonicalStoryRepack.js +3 -2
- package/dist/docx/commentTextParagraph.d.ts +6 -0
- package/dist/docx/commentTextParagraph.js +15 -0
- package/dist/docx/conformance.js +6 -1
- package/dist/docx/diagramPreview.js +2 -1
- package/dist/docx/documentParser.d.ts +13 -1
- package/dist/docx/documentParser.js +1 -1
- package/dist/docx/encryption/compoundFile.d.ts +0 -8
- package/dist/docx/encryption/compoundFile.js +2 -1
- package/dist/docx/encryption/cryptoBytes.d.ts +2 -2
- package/dist/docx/encryption/cryptoBytes.js +3 -18
- package/dist/docx/encryption/encryptionInfo.d.ts +0 -5
- package/dist/docx/encryption/encryptionInfo.js +2 -1
- package/dist/docx/ensureParaIds.js +2 -1
- package/dist/docx/groupDrawingParser.js +28 -13
- package/dist/docx/listModelNormalization.d.ts +10 -0
- package/dist/docx/listModelNormalization.js +166 -0
- package/dist/docx/metadataPrivacy.js +3 -2
- package/dist/docx/metafileRaster.js +2 -1
- package/dist/docx/packageParts.js +6 -5
- package/dist/docx/paragraphParser.js +6 -4
- package/dist/docx/parser.js +5 -4
- package/dist/docx/preservedRunContent.js +11 -2
- package/dist/docx/removeHeaderFooterParts.js +8 -7
- package/dist/docx/replyToComment.js +3 -13
- package/dist/docx/rezip.js +88 -89
- package/dist/docx/runParser.js +12 -6
- package/dist/docx/runPropertyPresence.d.ts +11 -0
- package/dist/docx/runPropertyPresence.js +14 -0
- package/dist/docx/selectiveSave.js +15 -14
- package/dist/docx/serializer/runSerializer.js +3 -2
- package/dist/docx/serializer/tableSerializer.js +2 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +2 -2
- package/dist/docx/server/boundedArchive.js +2 -1
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +2 -1
- package/dist/docx/server/inspectDocxPackage.js +5 -1
- package/dist/docx/server/validateDocxConformance.js +2 -1
- package/dist/docx/tableParser.js +7 -4
- package/dist/docx/tableRowPropertyPresence.d.ts +9 -0
- package/dist/docx/tableRowPropertyPresence.js +15 -0
- package/dist/docx/unzip.js +2 -1
- package/dist/docx/xmlEncoding.js +6 -5
- package/dist/fonts/fontsourceFaces.js +2 -1
- package/dist/fonts/sfnt/parse.js +6 -9
- package/dist/fonts/sfnt/subset.js +2 -1
- package/dist/fonts/sfnt/tables.js +2 -3
- package/dist/fonts/sfnt/woff.js +2 -1
- 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/index.d.ts +3 -1
- package/dist/internal/revisionResolutionInline.d.ts +2 -1
- package/dist/internal/revisionResolutionInline.js +22 -1
- package/dist/internal/wholeStoryRevisionResolution.js +24 -7
- package/dist/layout-bridge/convert/endnoteLayout.d.ts +1 -1
- package/dist/layout-bridge/convert/endnoteLayout.js +1 -3
- package/dist/layout-bridge/convert/flowConversionShared.d.ts +2 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +4 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +13 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +12 -15
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -1
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/measure/crossRunWords.js +12 -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/AutoSaveManager.js +2 -1
- package/dist/managers/EditorModeManager.d.ts +10 -1
- package/dist/managers/EditorModeManager.js +15 -1
- package/dist/managers/FindReplaceManager.d.ts +13 -6
- package/dist/managers/FindReplaceManager.js +15 -9
- package/dist/managers/TableSelectionManager.d.ts +1 -1
- package/dist/managers/autoSaveCodec.js +2 -6
- package/dist/managers/reviewDisplayMode.d.ts +8 -0
- package/dist/managers/reviewDisplayMode.js +15 -0
- package/dist/paged-layout/editorScrollRoot.d.ts +3 -1
- package/dist/paged-layout/editorScrollRoot.js +2 -2
- package/dist/paged-layout/pageText.d.ts +11 -2
- package/dist/paged-layout/pageText.js +8 -3
- package/dist/pdf/fonts.js +5 -14
- package/dist/pdf/images.js +4 -2
- package/dist/pdf/objects.d.ts +0 -11
- package/dist/pdf/objects.js +7 -9
- package/dist/pdf/writePdf.js +2 -1
- package/dist/prosemirror/commands/comments.js +51 -13
- package/dist/prosemirror/commentRangeInlineAtoms.d.ts +40 -0
- package/dist/prosemirror/commentRangeInlineAtoms.js +33 -0
- package/dist/prosemirror/containerFinalParagraph.d.ts +8 -8
- package/dist/prosemirror/containerFinalParagraph.js +8 -8
- package/dist/prosemirror/conversion/fromProseDoc.js +14 -8
- package/dist/prosemirror/conversion/toProseDoc.js +16 -23
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +16 -2
- package/dist/prosemirror/fieldRepresentation.js +4 -2
- package/dist/prosemirror/findReplaceSelection.d.ts +48 -2
- package/dist/prosemirror/findReplaceSelection.js +153 -38
- package/dist/prosemirror/inlineDisplayText.d.ts +10 -0
- package/dist/prosemirror/inlineDisplayText.js +29 -0
- package/dist/prosemirror/markupViewProjection.d.ts +10 -1
- package/dist/prosemirror/markupViewProjection.js +21 -3
- package/dist/prosemirror/plugins/transactionInvariants.js +6 -1
- package/dist/prosemirror/replacedAnnotations.d.ts +15 -1
- package/dist/prosemirror/replacedAnnotations.js +71 -12
- package/dist/prosemirror/runFormattingReconciliation.d.ts +3 -1
- package/dist/prosemirror/runFormattingReconciliation.js +10 -2
- package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +5 -7
- package/dist/prosemirror/runIdentityAcrossRevisions.js +66 -38
- package/dist/prosemirror/runPropertyChangeResolution.js +13 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
- package/dist/utils/base64.d.ts +1 -31
- package/dist/utils/base64.js +19 -33
- package/dist/utils/clipboard.js +5 -4
- package/dist/utils/colorResolver.js +11 -2
- package/dist/utils/findMatchView.d.ts +32 -0
- package/dist/utils/findMatchView.js +406 -0
- package/dist/utils/findReplace.d.ts +67 -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 -94
- package/dist/utils/sliceText.d.ts +2 -0
- package/dist/utils/sliceText.js +2 -0
- package/dist/utils/textEncoding.d.ts +2 -0
- package/dist/utils/textEncoding.js +2 -0
- package/dist/utils/tiffConverter.d.ts +0 -9
- package/dist/utils/tiffConverter.js +2 -4
- package/package.json +51 -25
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { mergeTextFormatting } from "../utils/textFormattingMerge.js";
|
|
2
|
-
import { expectCharacterStyleMarkAttrs } from "./attrs/index.js";
|
|
2
|
+
import { expectCharacterStyleMarkAttrs, expectRunIdentityMarkAttrs } from "./attrs/index.js";
|
|
3
3
|
import { textFormattingToMarks } from "./extensions/marks/markUtils.js";
|
|
4
4
|
import { marksToTextFormatting } from "./runFormattingFromMarks.js";
|
|
5
5
|
import { RUN_FORMATTING_MARK_NAMES } from "./runFormattingMarkNames.js";
|
|
6
|
+
import { RUN_IDENTITY_MARK_NAME } from "./runIdentity.js";
|
|
6
7
|
import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, paragraphFormattingForRun, resolveEffectiveRunStyleFormatting } from "./runStyleFormatting.js";
|
|
7
8
|
import { Mark } from "prosemirror-model";
|
|
8
9
|
//#region src/prosemirror/runFormattingReconciliation.ts
|
|
@@ -14,6 +15,13 @@ const readAuthoredRunFormatting = ({ context, marks, styleResolver }) => marksTo
|
|
|
14
15
|
paragraphMarkPrecedesStyle: context.paragraphMarkPrecedesStyle,
|
|
15
16
|
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
16
17
|
});
|
|
18
|
+
/** Preserve the authored distinction between an absent and empty property set in revisions. */
|
|
19
|
+
const readAuthoredRunPropertySnapshot = (options) => {
|
|
20
|
+
const formatting = readAuthoredRunFormatting(options);
|
|
21
|
+
if (Object.keys(formatting).length > 0) return formatting;
|
|
22
|
+
const identity = options.marks.find(({ type }) => type.name === RUN_IDENTITY_MARK_NAME);
|
|
23
|
+
return identity && expectRunIdentityMarkAttrs(identity).emptyFormatting ? formatting : void 0;
|
|
24
|
+
};
|
|
17
25
|
/**
|
|
18
26
|
* Rebuild a run's physical formatting marks from its authored properties and
|
|
19
27
|
* current style context. This is the inverse of {@link readAuthoredRunFormatting}:
|
|
@@ -54,4 +62,4 @@ const reconcileRunFormattingMarks = ({ authoredFormatting, context, node, styleR
|
|
|
54
62
|
]);
|
|
55
63
|
};
|
|
56
64
|
//#endregion
|
|
57
|
-
export { readAuthoredRunFormatting, reconcileRunFormattingMarks };
|
|
65
|
+
export { readAuthoredRunFormatting, readAuthoredRunPropertySnapshot, reconcileRunFormattingMarks };
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Node } from "prosemirror-model";
|
|
2
2
|
//#region src/prosemirror/runIdentityAcrossRevisions.d.ts
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
declare const continueRunIdentitiesAcrossRevisions: (nodes: readonly Node[]) => readonly Node[];
|
|
3
|
+
/** The continuation policy covers every declared source-carrier mark. */
|
|
4
|
+
declare const SOURCE_CARRIER_MARK_NAMES: ("hyperlink" | "runIdentity")[];
|
|
5
|
+
/** Every source-carrier family uses the same revision-boundary continuation policy. */
|
|
6
|
+
declare const continueSourceCarrierIdentitiesAcrossRevisions: (nodes: readonly Node[]) => readonly Node[];
|
|
9
7
|
//#endregion
|
|
10
|
-
export {
|
|
8
|
+
export { SOURCE_CARRIER_MARK_NAMES, continueSourceCarrierIdentitiesAcrossRevisions };
|
|
@@ -1,52 +1,73 @@
|
|
|
1
|
-
import { expectRunIdentityMarkAttrs } from "./attrs/index.js";
|
|
1
|
+
import { expectHyperlinkMarkAttrs, expectRunIdentityMarkAttrs } from "./attrs/index.js";
|
|
2
2
|
import "./extensions/nodes/SdtExtension.js";
|
|
3
3
|
import { RUN_IDENTITY_MARK_NAME } from "./runIdentity.js";
|
|
4
4
|
import { Fragment, Mark } from "prosemirror-model";
|
|
5
5
|
//#region src/prosemirror/runIdentityAcrossRevisions.ts
|
|
6
6
|
/**
|
|
7
|
-
* One
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `w:r` is its own authored run, so resolving the revision would leave two
|
|
13
|
-
* runs where the source had one. The package cannot say whether the two were
|
|
14
|
-
* one run, but runs that carry the same attributes and that only revised
|
|
15
|
-
* content holds apart are what such a cut writes, so the later piece takes the
|
|
16
|
-
* earlier one's identity. The pieces stay separate runs while the revision
|
|
17
|
-
* holds them apart, and become one run once it is resolved and they state the
|
|
18
|
-
* same properties again (a run joins its owner only then, see `fromProseDoc`).
|
|
19
|
-
*
|
|
20
|
-
* Runs the package writes side by side under the same revision state keep
|
|
21
|
-
* their own identities.
|
|
7
|
+
* One source identity for matching runs and hyperlinks a revision cut apart.
|
|
8
|
+
* Serialized fragments mint separate identities on reopen. Matching fragments
|
|
9
|
+
* across a revision boundary or revised-only bridge take the earlier identity,
|
|
10
|
+
* so resolution can rejoin them. Every non-identity attribute must match.
|
|
11
|
+
* Adjacent carriers under the same revision state keep their source identities.
|
|
22
12
|
*/
|
|
23
13
|
const REVISION_MARK_NAMES = /* @__PURE__ */ new Set([
|
|
24
14
|
"insertion",
|
|
25
15
|
"deletion",
|
|
26
16
|
"runPropertyChange"
|
|
27
17
|
]);
|
|
28
|
-
const
|
|
18
|
+
const CARRIER_OWNERS = [{
|
|
19
|
+
markName: RUN_IDENTITY_MARK_NAME,
|
|
20
|
+
read: (mark) => {
|
|
21
|
+
const attrs = expectRunIdentityMarkAttrs(mark);
|
|
22
|
+
return {
|
|
23
|
+
id: attrs.id,
|
|
24
|
+
payloadKey: JSON.stringify({
|
|
25
|
+
...attrs,
|
|
26
|
+
id: 0
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}, {
|
|
31
|
+
markName: "hyperlink",
|
|
32
|
+
read: (mark) => {
|
|
33
|
+
const attrs = expectHyperlinkMarkAttrs(mark);
|
|
34
|
+
if (typeof attrs._docxHyperlinkIndex !== "number") return void 0;
|
|
35
|
+
return {
|
|
36
|
+
id: attrs._docxHyperlinkIndex,
|
|
37
|
+
payloadKey: JSON.stringify({
|
|
38
|
+
...attrs,
|
|
39
|
+
_docxHyperlinkIndex: 0
|
|
40
|
+
})
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}];
|
|
44
|
+
/** The continuation policy covers every declared source-carrier mark. */
|
|
45
|
+
const SOURCE_CARRIER_MARK_NAMES = CARRIER_OWNERS.map(({ markName }) => markName);
|
|
46
|
+
const identityOf = (node, owner) => {
|
|
47
|
+
const mark = node.marks.find((candidate) => candidate.type.name === owner.markName);
|
|
48
|
+
if (!mark) return void 0;
|
|
49
|
+
const identity = owner.read(mark);
|
|
50
|
+
return identity === void 0 ? void 0 : {
|
|
51
|
+
mark,
|
|
52
|
+
...identity
|
|
53
|
+
};
|
|
54
|
+
};
|
|
29
55
|
const revisionMarksOf = (node) => node.marks.filter((mark) => REVISION_MARK_NAMES.has(mark.type.name));
|
|
30
|
-
/** The identity's attrs without the id: what the run carries. */
|
|
31
|
-
const payloadKey = (identity) => JSON.stringify({
|
|
32
|
-
...expectRunIdentityMarkAttrs(identity),
|
|
33
|
-
id: 0
|
|
34
|
-
});
|
|
35
56
|
/** Whether `right` continues `left`'s run across a revision boundary. */
|
|
36
|
-
const
|
|
37
|
-
const leftIdentity = identityOf(left);
|
|
38
|
-
const rightIdentity = identityOf(right);
|
|
39
|
-
if (!leftIdentity || !rightIdentity || leftIdentity.eq(rightIdentity)) return false;
|
|
40
|
-
return (bridged || !Mark.sameSet(revisionMarksOf(left), revisionMarksOf(right))) && payloadKey
|
|
57
|
+
const continuesCarrier = ({ left, right, bridged, owner }) => {
|
|
58
|
+
const leftIdentity = identityOf(left, owner);
|
|
59
|
+
const rightIdentity = identityOf(right, owner);
|
|
60
|
+
if (!leftIdentity || !rightIdentity || leftIdentity.mark.eq(rightIdentity.mark)) return false;
|
|
61
|
+
return (bridged || !Mark.sameSet(revisionMarksOf(left), revisionMarksOf(right))) && leftIdentity.payloadKey === rightIdentity.payloadKey;
|
|
41
62
|
};
|
|
42
63
|
/**
|
|
43
|
-
* `nodes`, one inline container's content, with each
|
|
44
|
-
* the identity of
|
|
64
|
+
* `nodes`, one inline container's content, with each revision fragment given
|
|
65
|
+
* the identity of its matching source carrier. A control is a container of its
|
|
45
66
|
* own. `nodes` itself comes back when nothing changes.
|
|
46
67
|
*/
|
|
47
|
-
const
|
|
68
|
+
const continueIdentities = (nodes, owner) => {
|
|
48
69
|
const renamed = /* @__PURE__ */ new Map();
|
|
49
|
-
/** The last
|
|
70
|
+
/** The last carrier with an identity, while only revised content follows it. */
|
|
50
71
|
let anchor;
|
|
51
72
|
let bridged = false;
|
|
52
73
|
let changed = false;
|
|
@@ -57,25 +78,26 @@ const continueRunIdentitiesAcrossRevisions = (nodes) => {
|
|
|
57
78
|
node.forEach((child) => {
|
|
58
79
|
children.push(child);
|
|
59
80
|
});
|
|
60
|
-
const continued =
|
|
81
|
+
const continued = continueIdentities(children, owner);
|
|
61
82
|
if (continued === children) return node;
|
|
62
83
|
changed = true;
|
|
63
84
|
return node.copy(Fragment.fromArray([...continued]));
|
|
64
85
|
}
|
|
65
|
-
const identity = identityOf(node);
|
|
86
|
+
const identity = identityOf(node, owner);
|
|
66
87
|
if (!identity) {
|
|
67
88
|
if (anchor && revisionMarksOf(node).length > 0) bridged = true;
|
|
68
89
|
else anchor = void 0;
|
|
69
90
|
return node;
|
|
70
91
|
}
|
|
71
|
-
const id =
|
|
92
|
+
const id = identity.id;
|
|
72
93
|
let replacement = renamed.get(id);
|
|
73
|
-
if (!replacement && anchor &&
|
|
94
|
+
if (!replacement && anchor && continuesCarrier({
|
|
74
95
|
left: anchor,
|
|
75
96
|
right: node,
|
|
76
|
-
bridged
|
|
97
|
+
bridged,
|
|
98
|
+
owner
|
|
77
99
|
})) {
|
|
78
|
-
replacement = identityOf(anchor);
|
|
100
|
+
replacement = identityOf(anchor, owner)?.mark;
|
|
79
101
|
if (replacement) renamed.set(id, replacement);
|
|
80
102
|
}
|
|
81
103
|
const next = replacement ? node.mark(replacement.addToSet(node.marks)) : node;
|
|
@@ -86,5 +108,11 @@ const continueRunIdentitiesAcrossRevisions = (nodes) => {
|
|
|
86
108
|
});
|
|
87
109
|
return changed ? result : nodes;
|
|
88
110
|
};
|
|
111
|
+
/** Every source-carrier family uses the same revision-boundary continuation policy. */
|
|
112
|
+
const continueSourceCarrierIdentitiesAcrossRevisions = (nodes) => {
|
|
113
|
+
let continued = nodes;
|
|
114
|
+
for (const owner of CARRIER_OWNERS) continued = continueIdentities(continued, owner);
|
|
115
|
+
return continued;
|
|
116
|
+
};
|
|
89
117
|
//#endregion
|
|
90
|
-
export {
|
|
118
|
+
export { SOURCE_CARRIER_MARK_NAMES, continueSourceCarrierIdentitiesAcrossRevisions };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { expectRunIdentityMarkAttrs } from "./attrs/index.js";
|
|
1
2
|
import { runFormattingInlineAtomDisposition } from "./runFormattingInlineCarriers.js";
|
|
2
3
|
import { RUN_FORMATTING_MARK_NAMES } from "./runFormattingMarkNames.js";
|
|
3
4
|
import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "./runFormattingReconciliation.js";
|
|
5
|
+
import { RUN_IDENTITY_MARK_NAME, runIdentityAttrs } from "./runIdentity.js";
|
|
4
6
|
//#region src/prosemirror/runPropertyChangeResolution.ts
|
|
5
7
|
/**
|
|
6
8
|
* Rebuild the pre-change run marks against the paragraph's live style cascade.
|
|
@@ -8,12 +10,22 @@ import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "./runFor
|
|
|
8
10
|
* owner so their reject semantics cannot diverge at the bulk threshold.
|
|
9
11
|
*/
|
|
10
12
|
const reconstructRejectedRunFormattingMarks = ({ node, paragraphContext, previousFormatting, styleResolver }) => {
|
|
11
|
-
|
|
13
|
+
const formatting = reconcileRunFormattingMarks({
|
|
12
14
|
authoredFormatting: previousFormatting ?? {},
|
|
13
15
|
context: paragraphContext,
|
|
14
16
|
node,
|
|
15
17
|
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
16
18
|
}).filter(({ type }) => RUN_FORMATTING_MARK_NAMES.has(type.name));
|
|
19
|
+
if (previousFormatting === void 0 || Object.keys(previousFormatting).length > 0) return formatting;
|
|
20
|
+
const identityType = node.type.schema.marks[RUN_IDENTITY_MARK_NAME];
|
|
21
|
+
if (!identityType) return formatting;
|
|
22
|
+
const identity = node.marks.find(({ type }) => type === identityType);
|
|
23
|
+
const attrs = identity ? expectRunIdentityMarkAttrs(identity) : void 0;
|
|
24
|
+
return [...formatting, identityType.create(runIdentityAttrs(attrs?.id ?? 0, {
|
|
25
|
+
preservedAttributes: attrs?.preservedAttributes ?? void 0,
|
|
26
|
+
preserved: attrs?.preserved ?? void 0,
|
|
27
|
+
emptyFormatting: true
|
|
28
|
+
}))];
|
|
17
29
|
};
|
|
18
30
|
/** Restored deletions inherit the live paragraph cascade without authoring their historical visuals. */
|
|
19
31
|
const restoreHistoricalRunFormatting = ({ node, paragraphContext, styleResolver }) => {
|
|
@@ -21,7 +21,7 @@ declare const TRACKED_RUN_INLINE_ATOM_DISPOSITIONS: Readonly<{
|
|
|
21
21
|
readonly pageBreakRun: "page-break-carrier";
|
|
22
22
|
readonly preservedXml: "carry";
|
|
23
23
|
readonly rangeAnchor: "transparent";
|
|
24
|
-
readonly renderedPageBreak: "
|
|
24
|
+
readonly renderedPageBreak: "carry";
|
|
25
25
|
readonly shape: "carry";
|
|
26
26
|
readonly structuredField: "carry";
|
|
27
27
|
readonly symbol: "carry";
|
|
@@ -20,7 +20,7 @@ const TRACKED_RUN_INLINE_ATOM_DISPOSITIONS = Object.freeze({
|
|
|
20
20
|
pageBreakRun: "page-break-carrier",
|
|
21
21
|
preservedXml: "carry",
|
|
22
22
|
rangeAnchor: "transparent",
|
|
23
|
-
renderedPageBreak: "
|
|
23
|
+
renderedPageBreak: "carry",
|
|
24
24
|
shape: "carry",
|
|
25
25
|
structuredField: "carry",
|
|
26
26
|
symbol: "carry",
|
package/dist/utils/base64.d.ts
CHANGED
|
@@ -1,35 +1,5 @@
|
|
|
1
|
+
import { bytesToBase64, encodeBase64Portable } from "@stll/utf8-boundaries";
|
|
1
2
|
//#region src/utils/base64.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* The package's one bytes-to-base64 encoder.
|
|
4
|
-
*
|
|
5
|
-
* Every call site that spelled this itself got a different answer to the same
|
|
6
|
-
* two questions, and one of them got the first question wrong:
|
|
7
|
-
*
|
|
8
|
-
* - `btoa(new TextDecoder("latin1").decode(bytes))` is not a binary string.
|
|
9
|
-
* The Encoding standard maps the `latin1` label to windows-1252, so bytes
|
|
10
|
-
* 0x80-0x9F decode to characters outside Latin-1 and `btoa` throws
|
|
11
|
-
* `InvalidCharacterError` on them. Ordinary image bytes contain those values,
|
|
12
|
-
* so the browser path of that spelling fails on real input.
|
|
13
|
-
* - `String.fromCharCode(...chunk)` is correct but spreads a chunk's worth of
|
|
14
|
-
* arguments per call, and the intermediate binary string is as large as the
|
|
15
|
-
* input.
|
|
16
|
-
*
|
|
17
|
-
* Neither question has to be asked per call site, so it is asked here once.
|
|
18
|
-
* The runtime's own encoder answers it when the runtime has one, and the
|
|
19
|
-
* portable encoder below answers it when not; both produce canonical base64,
|
|
20
|
-
* so the choice is invisible in the output.
|
|
21
|
-
*/
|
|
22
|
-
/**
|
|
23
|
-
* Encode into exactly one intermediate buffer: ASCII codes are written into a
|
|
24
|
-
* single array and decoded once, so a megabyte-scale input leaves the output
|
|
25
|
-
* string and nothing else.
|
|
26
|
-
*
|
|
27
|
-
* Exported because the runtimes the tests run on all carry a native encoder,
|
|
28
|
-
* and the fallback is the branch the browsers that lack one take.
|
|
29
|
-
*/
|
|
30
|
-
declare const encodeBase64Portable: (bytes: Uint8Array) => string;
|
|
31
|
-
/** Encode bytes as canonical, padded, standard-alphabet base64. */
|
|
32
|
-
declare const bytesToBase64: (bytes: Uint8Array) => string;
|
|
33
3
|
/** Encode bytes as a `data:` URL with the given media type. */
|
|
34
4
|
declare const bytesToDataUrl: (bytes: Uint8Array, mimeType: string) => string;
|
|
35
5
|
//#endregion
|
package/dist/utils/base64.js
CHANGED
|
@@ -1,40 +1,26 @@
|
|
|
1
|
+
import { bytesToBase64, bytesToBase64 as bytesToBase64$1, encodeBase64Portable } from "@stll/utf8-boundaries";
|
|
1
2
|
//#region src/utils/base64.ts
|
|
2
|
-
const BASE64_CODES = Uint8Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", (character) => character.charCodeAt(0));
|
|
3
|
-
const BASE64_PAD = 61;
|
|
4
3
|
/**
|
|
5
|
-
*
|
|
6
|
-
* single array and decoded once, so a megabyte-scale input leaves the output
|
|
7
|
-
* string and nothing else.
|
|
4
|
+
* The package's one bytes-to-base64 encoder.
|
|
8
5
|
*
|
|
9
|
-
*
|
|
10
|
-
* and
|
|
6
|
+
* Every call site that spelled this itself got a different answer to the same
|
|
7
|
+
* two questions, and one of them got the first question wrong:
|
|
8
|
+
*
|
|
9
|
+
* - `btoa(new TextDecoder("latin1").decode(bytes))` is not a binary string.
|
|
10
|
+
* The Encoding standard maps the `latin1` label to windows-1252, so bytes
|
|
11
|
+
* 0x80-0x9F decode to characters outside Latin-1 and `btoa` throws
|
|
12
|
+
* `InvalidCharacterError` on them. Ordinary image bytes contain those values,
|
|
13
|
+
* so the browser path of that spelling fails on real input.
|
|
14
|
+
* - `String.fromCharCode(...chunk)` is correct but spreads a chunk's worth of
|
|
15
|
+
* arguments per call, and the intermediate binary string is as large as the
|
|
16
|
+
* input.
|
|
17
|
+
*
|
|
18
|
+
* Neither question has to be asked per call site, so it is asked here once.
|
|
19
|
+
* The runtime's own encoder answers it when the runtime has one, and the
|
|
20
|
+
* portable encoder in the shared owner answers it when not; both produce canonical base64,
|
|
21
|
+
* so the choice is invisible in the output.
|
|
11
22
|
*/
|
|
12
|
-
const encodeBase64Portable = (bytes) => {
|
|
13
|
-
const groups = Math.ceil(bytes.length / 3);
|
|
14
|
-
const encoded = new Uint8Array(groups * 4);
|
|
15
|
-
let read = 0;
|
|
16
|
-
let write = 0;
|
|
17
|
-
for (; read + 2 < bytes.length; read += 3) {
|
|
18
|
-
const triple = bytes[read] << 16 | bytes[read + 1] << 8 | bytes[read + 2];
|
|
19
|
-
encoded[write] = BASE64_CODES[triple >> 18 & 63];
|
|
20
|
-
encoded[write + 1] = BASE64_CODES[triple >> 12 & 63];
|
|
21
|
-
encoded[write + 2] = BASE64_CODES[triple >> 6 & 63];
|
|
22
|
-
encoded[write + 3] = BASE64_CODES[triple & 63];
|
|
23
|
-
write += 4;
|
|
24
|
-
}
|
|
25
|
-
const remaining = bytes.length - read;
|
|
26
|
-
if (remaining > 0) {
|
|
27
|
-
const tail = bytes[read] << 16 | (remaining === 2 ? bytes[read + 1] << 8 : 0);
|
|
28
|
-
encoded[write] = BASE64_CODES[tail >> 18 & 63];
|
|
29
|
-
encoded[write + 1] = BASE64_CODES[tail >> 12 & 63];
|
|
30
|
-
encoded[write + 2] = remaining === 2 ? BASE64_CODES[tail >> 6 & 63] : BASE64_PAD;
|
|
31
|
-
encoded[write + 3] = BASE64_PAD;
|
|
32
|
-
}
|
|
33
|
-
return new TextDecoder().decode(encoded);
|
|
34
|
-
};
|
|
35
|
-
/** Encode bytes as canonical, padded, standard-alphabet base64. */
|
|
36
|
-
const bytesToBase64 = ("toBase64" in Uint8Array.prototype ? (bytes) => bytes.toBase64() : void 0) ?? encodeBase64Portable;
|
|
37
23
|
/** Encode bytes as a `data:` URL with the given media type. */
|
|
38
|
-
const bytesToDataUrl = (bytes, mimeType) => `data:${mimeType};base64,${bytesToBase64(bytes)}`;
|
|
24
|
+
const bytesToDataUrl = (bytes, mimeType) => `data:${mimeType};base64,${bytesToBase64$1(bytes)}`;
|
|
39
25
|
//#endregion
|
|
40
26
|
export { bytesToBase64, bytesToDataUrl, encodeBase64Portable };
|
package/dist/utils/clipboard.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { htmlCommentEnd } from "./htmlComments.js";
|
|
2
2
|
import { stripXmlDeclarations } from "./stripXmlDeclarations.js";
|
|
3
|
+
import { encodeUtf8, readBlobText } from "./textEncoding.js";
|
|
3
4
|
import { sanitizeXmlCharacters } from "@stll/docx-core";
|
|
4
5
|
import createDOMPurify from "dompurify";
|
|
5
6
|
//#region src/utils/clipboard.ts
|
|
@@ -171,8 +172,8 @@ function paragraphsToClipboardContent(paragraphs, includeFormatting = true) {
|
|
|
171
172
|
async function writeToClipboard(content) {
|
|
172
173
|
try {
|
|
173
174
|
const items = [new ClipboardItem({
|
|
174
|
-
[CLIPBOARD_TYPES.PLAIN]: new Blob([content.plainText], { type: CLIPBOARD_TYPES.PLAIN }),
|
|
175
|
-
[CLIPBOARD_TYPES.HTML]: new Blob([content.html], { type: CLIPBOARD_TYPES.HTML })
|
|
175
|
+
[CLIPBOARD_TYPES.PLAIN]: new Blob([encodeUtf8(content.plainText)], { type: CLIPBOARD_TYPES.PLAIN }),
|
|
176
|
+
[CLIPBOARD_TYPES.HTML]: new Blob([encodeUtf8(content.html)], { type: CLIPBOARD_TYPES.HTML })
|
|
176
177
|
})];
|
|
177
178
|
await navigator.clipboard.write(items);
|
|
178
179
|
return true;
|
|
@@ -222,8 +223,8 @@ async function parseClipboardItems(items, cleanWordFormatting) {
|
|
|
222
223
|
let html = "";
|
|
223
224
|
let plainText = "";
|
|
224
225
|
for (const item of items) {
|
|
225
|
-
if (item.types.includes(CLIPBOARD_TYPES.HTML)) html = await (await item.getType(CLIPBOARD_TYPES.HTML))
|
|
226
|
-
if (item.types.includes(CLIPBOARD_TYPES.PLAIN)) plainText = await (await item.getType(CLIPBOARD_TYPES.PLAIN))
|
|
226
|
+
if (item.types.includes(CLIPBOARD_TYPES.HTML)) html = await readBlobText(await item.getType(CLIPBOARD_TYPES.HTML));
|
|
227
|
+
if (item.types.includes(CLIPBOARD_TYPES.PLAIN)) plainText = await readBlobText(await item.getType(CLIPBOARD_TYPES.PLAIN));
|
|
227
228
|
}
|
|
228
229
|
return parseClipboardHtml(html, plainText, cleanWordFormatting);
|
|
229
230
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sliceText } from "./sliceText.js";
|
|
1
2
|
import { THEME_COLOR_BY_SCHEME_COLOR_VALUE, isSchemeColorValue, isThemeColor, themeColorSlot } from "@stll/docx-core/model";
|
|
2
3
|
//#region src/utils/colorResolver.ts
|
|
3
4
|
/**
|
|
@@ -109,7 +110,11 @@ function parseModifierValue(hexValue) {
|
|
|
109
110
|
* @returns RGB object with r, g, b values 0-255
|
|
110
111
|
*/
|
|
111
112
|
function hexToRgb(hex) {
|
|
112
|
-
const normalized =
|
|
113
|
+
const normalized = sliceText({
|
|
114
|
+
text: hex.padStart(6, "0"),
|
|
115
|
+
units: "codeUnits",
|
|
116
|
+
end: 6
|
|
117
|
+
});
|
|
113
118
|
const r = Number.parseInt(normalized.slice(0, 2), 16);
|
|
114
119
|
const g = Number.parseInt(normalized.slice(2, 4), 16);
|
|
115
120
|
const b = Number.parseInt(normalized.slice(4, 6), 16);
|
|
@@ -293,7 +298,11 @@ function parseColorString(colorString) {
|
|
|
293
298
|
const hex = normalized.replace(/^#/u, "").toUpperCase();
|
|
294
299
|
if (/^[0-9A-F]{6}$/iu.test(hex)) return { rgb: hex };
|
|
295
300
|
if (/^[0-9A-F]{3}$/iu.test(hex)) return { rgb: hex.split("").map((c) => c + c).join("") };
|
|
296
|
-
return { rgb:
|
|
301
|
+
return { rgb: sliceText({
|
|
302
|
+
text: hex.padStart(6, "0"),
|
|
303
|
+
units: "codeUnits",
|
|
304
|
+
end: 6
|
|
305
|
+
}) };
|
|
297
306
|
}
|
|
298
307
|
/**
|
|
299
308
|
* Create a ColorValue from theme color reference
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { Layout } from "../layout-engine/types.js";
|
|
3
|
+
import { FindMatch } from "./findReplace.js";
|
|
4
|
+
import { FindMatchRange } from "../prosemirror/findReplaceSelection.js";
|
|
5
|
+
import { Node } from "prosemirror-model";
|
|
6
|
+
import { OpStory } from "@stll/docx-core/ops";
|
|
7
|
+
//#region src/utils/findMatchView.d.ts
|
|
8
|
+
/** The same page variant selection used by the painter, including unmounted pages. */
|
|
9
|
+
declare const getRenderedSearchStories: (layout: Layout | null) => OpStory[];
|
|
10
|
+
type ResolvedMatch = FindMatchRange & {
|
|
11
|
+
index: number;
|
|
12
|
+
story: OpStory;
|
|
13
|
+
};
|
|
14
|
+
type FindMatchViewOptions = {
|
|
15
|
+
container: HTMLElement;
|
|
16
|
+
document: document_d_exports.Document;
|
|
17
|
+
bodyDoc?: Node | undefined;
|
|
18
|
+
matches: readonly FindMatch[];
|
|
19
|
+
commentRoot?: HTMLElement | undefined;
|
|
20
|
+
layout?: Layout | null | undefined;
|
|
21
|
+
};
|
|
22
|
+
/** Resolve each story once; box positions are local to their parent story. */
|
|
23
|
+
declare const resolveDocumentFindRanges: ({ document, bodyDoc, matches }: Omit<FindMatchViewOptions, "container" | "commentRoot" | "layout">) => ResolvedMatch[];
|
|
24
|
+
/** Paint search geometry over the existing page DOM, without changing editor state. */
|
|
25
|
+
declare const createFindMatchView: (options: FindMatchViewOptions) => {
|
|
26
|
+
paint: (index: number) => void;
|
|
27
|
+
reveal: (index: number) => boolean;
|
|
28
|
+
navigate: (index: number, activateComment?: (commentId: number) => void) => void;
|
|
29
|
+
destroy: () => void;
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { createFindMatchView, getRenderedSearchStories, resolveDocumentFindRanges };
|