@stll/folio-core 0.55.0 → 0.56.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/apply.js +169 -38
- package/dist/ai-edits/headless.js +2 -2
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +476 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComposition.d.ts +20 -3
- package/dist/controller/canonicalComposition.js +166 -38
- package/dist/controller/canonicalInlineProjection.d.ts +113 -0
- package/dist/controller/canonicalInlineProjection.js +393 -0
- package/dist/controller/canonicalInput.d.ts +13 -4
- package/dist/controller/canonicalInput.js +52 -13
- package/dist/controller/canonicalInputTimer.d.ts +7 -0
- package/dist/controller/canonicalInputTimer.js +11 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +556 -0
- package/dist/controller/canonicalSession.d.ts +24 -6
- package/dist/controller/canonicalSession.js +259 -111
- package/dist/controller/canonicalStoryEditor.d.ts +5 -3
- package/dist/controller/canonicalStoryEditor.js +7 -2
- package/dist/controller/canonicalStructure.js +57 -4
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +2 -9
- package/dist/controller/folioEditor.js +5 -4
- package/dist/controller/headerFooterEditorManager.d.ts +2 -1
- package/dist/controller/headerFooterEditorManager.js +8 -7
- package/dist/controller/hiddenEditorApi.d.ts +12 -2
- package/dist/controller/hiddenEditorApi.js +4 -0
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +216 -34
- package/dist/controller/noteEditorManager.d.ts +2 -1
- package/dist/controller/noteEditorManager.js +8 -7
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/canonicalResourceSave.d.ts +16 -0
- package/dist/docx/canonicalResourceSave.js +27 -0
- package/dist/docx/canonicalSave.d.ts +29 -0
- package/dist/docx/canonicalSave.js +101 -0
- package/dist/docx/canonicalStoryRepack.d.ts +1 -1
- package/dist/docx/canonicalStoryRepack.js +38 -5
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.js +10 -4
- package/dist/docx/footnoteParser.d.ts +1 -11
- package/dist/docx/footnoteParser.js +1 -16
- package/dist/docx/headerFooterParser.d.ts +1 -9
- package/dist/docx/headerFooterParser.js +1 -12
- package/dist/docx/headerFooterVerbatim.d.ts +26 -1
- package/dist/docx/headerFooterVerbatim.js +81 -3
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/packageParts.js +9 -3
- package/dist/docx/paragraphPropertySource.js +2 -1
- package/dist/docx/parser.js +2 -1
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/rezip.d.ts +49 -5
- package/dist/docx/rezip.js +745 -229
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +32 -3
- package/dist/docx/selectiveXmlPatch.js +7 -5
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/storyBlockReplay.d.ts +21 -1
- package/dist/docx/storyBlockReplay.js +113 -9
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/structuralXmlPatch.js +10 -22
- package/dist/docx/styleParser.d.ts +5 -1
- package/dist/docx/styleParser.js +1 -1
- package/dist/docx/tableParser.d.ts +1 -8
- package/dist/docx/tableParser.js +1 -28
- package/dist/docx/textBoxParser.d.ts +1 -5
- package/dist/docx/textBoxParser.js +1 -20
- package/dist/docx/unzip.js +6 -1
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/managers/DocumentLoaderManager.js +2 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +5 -120
- package/dist/markdown/renderParagraph.js +4 -2
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +32 -13
- package/dist/prosemirror/canonicalCommands.d.ts +28 -4
- package/dist/prosemirror/canonicalCommands.js +11 -4
- package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
- package/dist/prosemirror/canonicalSelectionRange.js +15 -0
- package/dist/prosemirror/clipboardIntent.d.ts +7 -0
- package/dist/prosemirror/clipboardIntent.js +9 -0
- package/dist/prosemirror/commands/pageBreak.js +2 -2
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
- package/dist/prosemirror/conversion/toProseDoc.js +5 -4
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +39 -30
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
- package/dist/prosemirror/extensions/marks/markUtils.js +3 -1
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/suggestionMode.js +7 -5
- package/dist/types/canonicalCapabilities.d.ts +215 -0
- package/dist/types/canonicalCapabilities.js +212 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/package.json +4 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { withCanonicalCommand } from "../canonicalCommands.js";
|
|
2
|
+
import { canonicalSelectionRange } from "../canonicalSelectionRange.js";
|
|
2
3
|
import { pageBreakRunParagraphProjectionDisposition } from "../pageBreakRunProjection.js";
|
|
3
4
|
//#region src/prosemirror/commands/pageBreak.ts
|
|
4
5
|
const UNSUPPORTED_PAGE_BREAK_RUN_ANCESTORS = /* @__PURE__ */ new Set([
|
|
@@ -46,8 +47,7 @@ const insertPageBreakCommand = (state, dispatch) => {
|
|
|
46
47
|
*/
|
|
47
48
|
const insertPageBreak = withCanonicalCommand(insertPageBreakCommand, (state) => insertPageBreakCommand(state) ? [{
|
|
48
49
|
type: "insertBreak",
|
|
49
|
-
|
|
50
|
-
to: state.selection.to,
|
|
50
|
+
...canonicalSelectionRange(state),
|
|
51
51
|
breakType: "page"
|
|
52
52
|
}] : []);
|
|
53
53
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dispatchClipboardIntent } from "../clipboardIntent.js";
|
|
1
2
|
import { Fragment, Slice } from "prosemirror-model";
|
|
2
3
|
//#region src/prosemirror/commands/pastePlainText.ts
|
|
3
4
|
/**
|
|
@@ -54,7 +55,7 @@ const pasteWithoutFormatting = (state, dispatch, view) => {
|
|
|
54
55
|
navigator.clipboard.readText().then((text) => {
|
|
55
56
|
if (!text || view.isDestroyed) return;
|
|
56
57
|
const slice = buildPlainTextSlice(text, schema);
|
|
57
|
-
view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());
|
|
58
|
+
if (dispatchClipboardIntent(view, slice) === void 0) view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());
|
|
58
59
|
}).catch((error) => {
|
|
59
60
|
if (typeof CustomEvent === "function" && !view.isDestroyed) view.dom.dispatchEvent(new CustomEvent(CLIPBOARD_READ_ERROR_EVENT, {
|
|
60
61
|
detail: { error },
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/prosemirror/conversion/hyphenTextCarriers.d.ts
|
|
2
|
+
/** These source units render as native text while keeping one logical atom each. */
|
|
3
|
+
declare const HYPHEN_TEXT_CARRIERS: {
|
|
4
|
+
readonly softHyphen: "";
|
|
5
|
+
readonly noBreakHyphen: "‑";
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
export { HYPHEN_TEXT_CARRIERS };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/prosemirror/conversion/hyphenTextCarriers.ts
|
|
2
|
+
/** These source units render as native text while keeping one logical atom each. */
|
|
3
|
+
const HYPHEN_TEXT_CARRIERS = {
|
|
4
|
+
softHyphen: "",
|
|
5
|
+
noBreakHyphen: "‑"
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
export { HYPHEN_TEXT_CARRIERS };
|
|
@@ -18,6 +18,12 @@ type ToProseDocOptions = {
|
|
|
18
18
|
*/
|
|
19
19
|
warn?: ParseContext["warn"];
|
|
20
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* Find bookmark pairs across every editable inline wrapper in a document story.
|
|
23
|
+
* Each endpoint is converted at its own structural position, so a range may
|
|
24
|
+
* start outside a hyperlink and end inside it (or the inverse).
|
|
25
|
+
*/
|
|
26
|
+
declare const collectPairedBookmarkIds: (blocks: readonly document_d_exports.BlockContent[]) => ReadonlySet<number>;
|
|
21
27
|
/**
|
|
22
28
|
* Convert a Document to a ProseMirror document
|
|
23
29
|
*
|
|
@@ -40,4 +46,4 @@ declare function footnoteToProseDoc(content: document_d_exports.BlockContent[],
|
|
|
40
46
|
*/
|
|
41
47
|
declare function createEmptyDoc(): Node;
|
|
42
48
|
//#endregion
|
|
43
|
-
export { ToProseDocOptions, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, toProseDoc };
|
|
49
|
+
export { ToProseDocOptions, collectPairedBookmarkIds, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, toProseDoc };
|
|
@@ -49,6 +49,7 @@ import { tableCellStyleRegions, tableRowBand } from "../styles/tableStyleRegions
|
|
|
49
49
|
import { canCarryTrackedRunMark, trackedRunInlineAtomDisposition } from "../trackedRunInlineAtoms.js";
|
|
50
50
|
import { assertValidProseMirrorDocument } from "../validation.js";
|
|
51
51
|
import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
|
|
52
|
+
import { HYPHEN_TEXT_CARRIERS } from "./hyphenTextCarriers.js";
|
|
52
53
|
import { listRenderingDefinitionsMatch } from "./listRenderingDefinition.js";
|
|
53
54
|
import { createMarkInterner } from "./markInterner.js";
|
|
54
55
|
import { hasSinkChildren } from "./preservedSinkCarriers.js";
|
|
@@ -786,7 +787,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
|
|
|
786
787
|
if (tableOfContentsLevel !== void 0) attrs._tableOfContentsLevel = tableOfContentsLevel;
|
|
787
788
|
if (formatting?.numPr) attrs.numPr = paragraphNumberingAttr(formatting.numPr);
|
|
788
789
|
if (formatting?.numPrFromStyle) attrs.numPrFromStyle = paragraphNumberingAttr(formatting.numPrFromStyle);
|
|
789
|
-
if (paragraph.listRendering && formatting?.numPr?.kind !== "none") Object.assign(attrs, listRenderingAttrPatch(paragraph.listRendering));
|
|
790
|
+
if (paragraph.listRendering && formatting?.numPr?.kind !== "none") Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS, listRenderingAttrPatch(paragraph.listRendering));
|
|
790
791
|
if (formatting) attrs._originalFormatting = formatting;
|
|
791
792
|
if (paragraph.propertyChanges && paragraph.propertyChanges.length > 0) attrs._propertyChanges = paragraph.propertyChanges.map(({ previousFormatting, ...change }) => {
|
|
792
793
|
if (previousFormatting === void 0) return change;
|
|
@@ -2034,8 +2035,8 @@ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredF
|
|
|
2034
2035
|
text: content.text,
|
|
2035
2036
|
level: PRESERVED_XML_LEVELS.run
|
|
2036
2037
|
}).mark(marks)];
|
|
2037
|
-
case "noBreakHyphen": return [schema.text(
|
|
2038
|
-
case "softHyphen": return [schema.text(
|
|
2038
|
+
case "noBreakHyphen": return [schema.text(HYPHEN_TEXT_CARRIERS.noBreakHyphen, marks)];
|
|
2039
|
+
case "softHyphen": return [schema.text(HYPHEN_TEXT_CARRIERS.softHyphen, marks)];
|
|
2039
2040
|
case "symbol": return [schema.node("symbol", {
|
|
2040
2041
|
font: content.font,
|
|
2041
2042
|
char: content.char
|
|
@@ -2765,4 +2766,4 @@ function createEmptyDoc() {
|
|
|
2765
2766
|
return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
|
|
2766
2767
|
}
|
|
2767
2768
|
//#endregion
|
|
2768
|
-
export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, toProseDoc };
|
|
2769
|
+
export { collectPairedBookmarkIds, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, toProseDoc };
|
|
@@ -8,7 +8,7 @@ import { collectHeadings } from "../../../utils/headingCollector.js";
|
|
|
8
8
|
import { tableOfContentsStyleLevel } from "../../../utils/tableOfContentsStyle.js";
|
|
9
9
|
import { expectParagraphAttrs } from "../../attrs/index.js";
|
|
10
10
|
import { autospacingMatchesBase } from "../../autospacingBase.js";
|
|
11
|
-
import { withCanonicalParagraphFormatting } from "../../canonicalCommands.js";
|
|
11
|
+
import { withCanonicalCommand, withCanonicalParagraphFormatting, withCanonicalStartParagraphFormatting } from "../../canonicalCommands.js";
|
|
12
12
|
import { removeSectionBreakAtSelection, setSectionBreakType } from "../../commands/sectionBreak.js";
|
|
13
13
|
import { CLEARED_LIST_RENDERING_ATTRS } from "../../listMarker.js";
|
|
14
14
|
import { directParagraphAlignment } from "../../paragraphAlignment.js";
|
|
@@ -696,7 +696,7 @@ const ParagraphExtension = createNodeExtension({
|
|
|
696
696
|
}, { styleId: null }),
|
|
697
697
|
insertSectionBreak: (breakType) => setSectionBreakType(breakType),
|
|
698
698
|
removeSectionBreak: () => removeSectionBreakAtSelection,
|
|
699
|
-
generateTOC: ({ title }) => (state, dispatch) => {
|
|
699
|
+
generateTOC: ({ title }) => withCanonicalCommand((state, dispatch) => {
|
|
700
700
|
const builtInStyles = getDocumentBuiltInStyles(state);
|
|
701
701
|
const headings = collectHeadings(state.doc, builtInStyles);
|
|
702
702
|
if (headings.length === 0) return false;
|
|
@@ -773,44 +773,53 @@ const ParagraphExtension = createNodeExtension({
|
|
|
773
773
|
tr.insert(insertPos, Fragment.from(tocNodes));
|
|
774
774
|
dispatch(tr.scrollIntoView());
|
|
775
775
|
return true;
|
|
776
|
-
},
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
value: "ltr"
|
|
784
|
-
} : {
|
|
776
|
+
}, (state) => [{
|
|
777
|
+
type: "generateTOC",
|
|
778
|
+
at: state.selection.from,
|
|
779
|
+
title
|
|
780
|
+
}]),
|
|
781
|
+
toggleBidi: () => {
|
|
782
|
+
const directionFor = (paragraph) => ({
|
|
785
783
|
source: "manual",
|
|
786
|
-
value: "rtl"
|
|
787
|
-
})
|
|
784
|
+
value: directionIsRtl(expectParagraphAttrs(paragraph).direction) ? "ltr" : "rtl"
|
|
785
|
+
});
|
|
786
|
+
return withCanonicalStartParagraphFormatting((state, dispatch) => {
|
|
787
|
+
const paragraph = state.selection.$from.parent;
|
|
788
|
+
if (paragraph.type.name !== "paragraph") return false;
|
|
789
|
+
return setParagraphAttr("direction", directionFor(paragraph))(state, dispatch);
|
|
790
|
+
}, (paragraph) => ({ bidi: directionIsRtl(directionFor(paragraph)) }));
|
|
788
791
|
},
|
|
789
|
-
setRtl: () => setParagraphAttr("direction", {
|
|
792
|
+
setRtl: () => withCanonicalParagraphFormatting(setParagraphAttr("direction", {
|
|
790
793
|
source: "manual",
|
|
791
794
|
value: "rtl"
|
|
792
|
-
}),
|
|
793
|
-
setLtr: () => setParagraphAttr("direction", {
|
|
795
|
+
}), { bidi: true }),
|
|
796
|
+
setLtr: () => withCanonicalParagraphFormatting(setParagraphAttr("direction", {
|
|
794
797
|
source: "manual",
|
|
795
798
|
value: "ltr"
|
|
796
|
-
}),
|
|
797
|
-
setTabs: (tabs) => setParagraphAttr("tabs", tabs.length > 0 ? tabs : null),
|
|
798
|
-
addTabStop: (position, alignment = "left", leader = "none") =>
|
|
799
|
-
const
|
|
800
|
-
const paragraph = $from.parent;
|
|
801
|
-
if (paragraph.type.name !== "paragraph") return false;
|
|
802
|
-
return setParagraphAttr("tabs", [...(paragraph.attrs["tabs"] || []).filter((t) => t.position !== position), {
|
|
799
|
+
}), { bidi: false }),
|
|
800
|
+
setTabs: (tabs) => withCanonicalParagraphFormatting(setParagraphAttr("tabs", tabs.length > 0 ? tabs : null), { tabs: tabs.length > 0 ? tabs : null }),
|
|
801
|
+
addTabStop: (position, alignment = "left", leader = "none") => {
|
|
802
|
+
const tabsFor = (paragraph) => [...(expectParagraphAttrs(paragraph).tabs ?? []).filter((tab) => tab.position !== position), {
|
|
803
803
|
position,
|
|
804
804
|
alignment,
|
|
805
805
|
leader
|
|
806
|
-
}].toSorted((a, b) => a.position - b.position)
|
|
806
|
+
}].toSorted((a, b) => a.position - b.position);
|
|
807
|
+
return withCanonicalStartParagraphFormatting((state, dispatch) => {
|
|
808
|
+
const paragraph = state.selection.$from.parent;
|
|
809
|
+
if (paragraph.type.name !== "paragraph") return false;
|
|
810
|
+
return setParagraphAttr("tabs", tabsFor(paragraph))(state, dispatch);
|
|
811
|
+
}, (paragraph) => ({ tabs: tabsFor(paragraph) }));
|
|
807
812
|
},
|
|
808
|
-
removeTabStop: (position) =>
|
|
809
|
-
const
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
return
|
|
813
|
+
removeTabStop: (position) => {
|
|
814
|
+
const tabsFor = (paragraph) => {
|
|
815
|
+
const tabs = (expectParagraphAttrs(paragraph).tabs ?? []).filter((tab) => tab.position !== position);
|
|
816
|
+
return tabs.length > 0 ? tabs : null;
|
|
817
|
+
};
|
|
818
|
+
return withCanonicalStartParagraphFormatting((state, dispatch) => {
|
|
819
|
+
const paragraph = state.selection.$from.parent;
|
|
820
|
+
if (paragraph.type.name !== "paragraph") return false;
|
|
821
|
+
return setParagraphAttr("tabs", tabsFor(paragraph))(state, dispatch);
|
|
822
|
+
}, (paragraph) => ({ tabs: tabsFor(paragraph) }));
|
|
814
823
|
}
|
|
815
824
|
} };
|
|
816
825
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { BUILT_IN_STYLE_NAME } from "../../../docx/builtInStyles.js";
|
|
1
2
|
import { anchorTargetAttrs, normalizeUserUrl, sanitizeExternalUrl } from "../../../utils/urlSecurity.js";
|
|
2
3
|
import { expectHyperlinkMarkAttrs } from "../../attrs/index.js";
|
|
4
|
+
import { withCanonicalCommand } from "../../canonicalCommands.js";
|
|
5
|
+
import { canonicalSelectionRange } from "../../canonicalSelectionRange.js";
|
|
3
6
|
import { removeHyperlinkInRange } from "../../hyperlinkRemoval.js";
|
|
7
|
+
import { getDocumentBuiltInStyles } from "../../plugins/documentStyleState.js";
|
|
4
8
|
import { createMarkExtension } from "../create.js";
|
|
5
9
|
import { isMarkActive } from "./markUtils.js";
|
|
6
10
|
import { panic } from "better-result";
|
|
@@ -121,7 +125,7 @@ const HyperlinkExtension = createMarkExtension({
|
|
|
121
125
|
onSchemaReady(ctx) {
|
|
122
126
|
if (!ctx.schema.marks["hyperlink"]) panic("Missing mark type: hyperlink");
|
|
123
127
|
const documentHyperlinkType = (state) => state.schema.marks["hyperlink"] ?? panic("Missing mark type: hyperlink");
|
|
124
|
-
const setHyperlink = (href, tooltip) => (state, dispatch) => {
|
|
128
|
+
const setHyperlink = (href, tooltip) => withCanonicalCommand((state, dispatch) => {
|
|
125
129
|
const hlType = documentHyperlinkType(state);
|
|
126
130
|
const { from, to, empty } = state.selection;
|
|
127
131
|
if (empty) return false;
|
|
@@ -136,34 +140,52 @@ const HyperlinkExtension = createMarkExtension({
|
|
|
136
140
|
dispatch(tr.scrollIntoView());
|
|
137
141
|
}
|
|
138
142
|
return true;
|
|
139
|
-
}
|
|
140
|
-
|
|
143
|
+
}, (state) => state.selection.empty ? [] : [{
|
|
144
|
+
type: "setHyperlink",
|
|
145
|
+
...canonicalSelectionRange(state),
|
|
146
|
+
href: normalizeHyperlinkInput(href),
|
|
147
|
+
...tooltip ? { tooltip } : {}
|
|
148
|
+
}]);
|
|
149
|
+
const removalRange = (state) => {
|
|
150
|
+
const { empty, $from } = state.selection;
|
|
151
|
+
const { from, to } = canonicalSelectionRange(state);
|
|
152
|
+
if (!empty) return {
|
|
153
|
+
from,
|
|
154
|
+
to
|
|
155
|
+
};
|
|
141
156
|
const hlType = documentHyperlinkType(state);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
if (dispatch) dispatch(removeHyperlinkInRange(state, state.tr, start, end).scrollIntoView());
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
if (dispatch) dispatch(removeHyperlinkInRange(state, state.tr, from, to).scrollIntoView());
|
|
164
|
-
return true;
|
|
157
|
+
if (!$from.marks().some((mark) => mark.type === hlType)) return void 0;
|
|
158
|
+
let start = from;
|
|
159
|
+
let end = to;
|
|
160
|
+
$from.parent.forEach((node, offset) => {
|
|
161
|
+
const nodeStart = $from.start() + offset;
|
|
162
|
+
const nodeEnd = nodeStart + node.nodeSize;
|
|
163
|
+
if (node.isText && nodeStart <= from && from <= nodeEnd && node.marks.some((mark) => mark.type === hlType)) {
|
|
164
|
+
start = Math.min(start, nodeStart);
|
|
165
|
+
end = Math.max(end, nodeEnd);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
from: start,
|
|
170
|
+
to: end
|
|
171
|
+
};
|
|
165
172
|
};
|
|
166
|
-
const
|
|
173
|
+
const removeHyperlink = withCanonicalCommand((state, dispatch) => {
|
|
174
|
+
const range = removalRange(state);
|
|
175
|
+
if (!range) return false;
|
|
176
|
+
if (dispatch) dispatch(removeHyperlinkInRange(state, state.tr, range.from, range.to).scrollIntoView());
|
|
177
|
+
return true;
|
|
178
|
+
}, (state) => {
|
|
179
|
+
const range = removalRange(state);
|
|
180
|
+
if (!range) return [];
|
|
181
|
+
const hyperlinkStyleId = getDocumentBuiltInStyles(state).styleIdForBuiltInName(BUILT_IN_STYLE_NAME.hyperlink);
|
|
182
|
+
return [{
|
|
183
|
+
type: "removeHyperlink",
|
|
184
|
+
...range,
|
|
185
|
+
...hyperlinkStyleId === void 0 ? {} : { hyperlinkStyleId }
|
|
186
|
+
}];
|
|
187
|
+
});
|
|
188
|
+
const insertHyperlink = (text, href, tooltip) => withCanonicalCommand((state, dispatch) => {
|
|
167
189
|
const hlType = documentHyperlinkType(state);
|
|
168
190
|
if (dispatch) {
|
|
169
191
|
const mark = hlType.create({
|
|
@@ -174,7 +196,13 @@ const HyperlinkExtension = createMarkExtension({
|
|
|
174
196
|
dispatch(state.tr.replaceSelectionWith(textNode, false).scrollIntoView());
|
|
175
197
|
}
|
|
176
198
|
return true;
|
|
177
|
-
}
|
|
199
|
+
}, (state) => [{
|
|
200
|
+
type: "insertHyperlink",
|
|
201
|
+
...canonicalSelectionRange(state),
|
|
202
|
+
text,
|
|
203
|
+
href: normalizeHyperlinkInput(href),
|
|
204
|
+
...tooltip ? { tooltip } : {}
|
|
205
|
+
}]);
|
|
178
206
|
return { commands: {
|
|
179
207
|
setHyperlink,
|
|
180
208
|
removeHyperlink: () => removeHyperlink,
|
|
@@ -3,6 +3,7 @@ import { mergeFontFamily } from "../../../utils/fontFamilyMerge.js";
|
|
|
3
3
|
import { normalizeHorizontalScalePercent } from "../../../utils/horizontalScale.js";
|
|
4
4
|
import { expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectEmphasisMarkAttrs, expectFontFamilyMarkAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectStrikeMarkAttrs, expectTextEffectMarkAttrs } from "../../attrs/index.js";
|
|
5
5
|
import { canonicalRunFormatting, withCanonicalCommand } from "../../canonicalCommands.js";
|
|
6
|
+
import { canonicalSelectionRange } from "../../canonicalSelectionRange.js";
|
|
6
7
|
import { runShadingAttrsToShading, shadingToRunShadingAttrs } from "../../conversion/runShadingMark.js";
|
|
7
8
|
import { documentMarkType } from "../../documentSchema.js";
|
|
8
9
|
import { selectRunFormattingCarrierRepresentations } from "../../runFormattingInlineCarriers.js";
|
|
@@ -188,7 +189,8 @@ function createMarkWithMergedAttrs(markType, currentMark, nextAttrs) {
|
|
|
188
189
|
}
|
|
189
190
|
const canonicalSetMarkFormatting = ({ state, type, attrs }) => {
|
|
190
191
|
const markType = documentMarkType(state, type);
|
|
191
|
-
const {
|
|
192
|
+
const { empty } = state.selection;
|
|
193
|
+
const { from, to } = canonicalSelectionRange(state);
|
|
192
194
|
if (empty) return canonicalRunFormatting(state, marksToTextFormatting([createMarkWithMergedAttrs(markType, markType.isInSet(state.storedMarks ?? state.selection.$from.marks()), attrs)]));
|
|
193
195
|
return selectRunFormattingCarrierRepresentations({
|
|
194
196
|
doc: state.doc,
|
|
@@ -2,6 +2,7 @@ import { insertImageFromFile } from "./commands/image.js";
|
|
|
2
2
|
import { insertPageBreak } from "./commands/pageBreak.js";
|
|
3
3
|
import { generateTableOfContents } from "./commands/paragraph.js";
|
|
4
4
|
import { insertTable } from "./commands/table.js";
|
|
5
|
+
import { executeEditorCommand } from "./executeEditorCommand.js";
|
|
5
6
|
//#region src/prosemirror/insertOperations.ts
|
|
6
7
|
/** Insert a `rows × columns` table at the current selection. */
|
|
7
8
|
function insertTableInView(view, rows, columns) {
|
|
@@ -18,7 +19,7 @@ function insertPageBreakInView(view) {
|
|
|
18
19
|
* {@link GenerateTableOfContentsOptions}.
|
|
19
20
|
*/
|
|
20
21
|
function insertTableOfContentsInView(view, options) {
|
|
21
|
-
return
|
|
22
|
+
return executeEditorCommand(view, generateTableOfContents(options));
|
|
22
23
|
}
|
|
23
24
|
//#endregion
|
|
24
25
|
export { insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView };
|
|
@@ -4,6 +4,7 @@ import { NumberingMap } from "../docx/numberingParser.js";
|
|
|
4
4
|
import { Node } from "prosemirror-model";
|
|
5
5
|
import { Transaction } from "prosemirror-state";
|
|
6
6
|
//#region src/prosemirror/paragraphPropertyCarry.d.ts
|
|
7
|
+
type RecordedFormatting = NonNullable<ParagraphPropertyChangeAttrs["previousFormatting"]>;
|
|
7
8
|
type CarryParagraphPropertiesOptions = {
|
|
8
9
|
tr: Transaction;
|
|
9
10
|
/** The paragraph that takes the properties. */
|
|
@@ -17,6 +18,11 @@ type CarryParagraphPropertiesOptions = {
|
|
|
17
18
|
/** Properties the paragraph keeps its own values of: ones its own batch set. */
|
|
18
19
|
keep?: ReadonlySet<string>;
|
|
19
20
|
};
|
|
21
|
+
type CarriedParagraphPropertiesOptions = Pick<CarryParagraphPropertiesOptions, "source" | "keep"> & {
|
|
22
|
+
target: Node;
|
|
23
|
+
};
|
|
24
|
+
/** The exact formatting transfer, shared with pre-mutation capacity checks. */
|
|
25
|
+
declare const carriedParagraphProperties: ({ source, target, keep }: CarriedParagraphPropertiesOptions) => RecordedFormatting;
|
|
20
26
|
/**
|
|
21
27
|
* Give a paragraph another one's properties: the pPr a property change
|
|
22
28
|
* covers. Its identity, mark, mark run properties and section stay its own,
|
|
@@ -61,4 +67,4 @@ declare const recordReplacedParagraphProperties: ({ tr, position, replaced, revi
|
|
|
61
67
|
*/
|
|
62
68
|
declare const propertiesSetInBatch: (node: Node, batchRevisionIds: ReadonlySet<number>) => ReadonlySet<string>;
|
|
63
69
|
//#endregion
|
|
64
|
-
export { carryParagraphProperties, paragraphLeftAfter, propertiesSetInBatch, recordReplacedParagraphProperties };
|
|
70
|
+
export { carriedParagraphProperties, carryParagraphProperties, paragraphLeftAfter, propertiesSetInBatch, recordReplacedParagraphProperties };
|
|
@@ -17,6 +17,8 @@ import { panic } from "better-result";
|
|
|
17
17
|
* revision, so accepting reads as the direct edit and rejecting restores the
|
|
18
18
|
* second's own.
|
|
19
19
|
*/
|
|
20
|
+
/** The exact formatting transfer, shared with pre-mutation capacity checks. */
|
|
21
|
+
const carriedParagraphProperties = ({ source, target, keep }) => Object.fromEntries([...Object.entries(paragraphPropertiesSnapshot(source)).filter(([key]) => !keep?.has(key)), ...Object.entries(paragraphPropertiesSnapshot(target)).filter(([key]) => keep?.has(key))]);
|
|
20
22
|
/**
|
|
21
23
|
* Give a paragraph another one's properties: the pPr a property change
|
|
22
24
|
* covers. Its identity, mark, mark run properties and section stay its own,
|
|
@@ -32,8 +34,11 @@ const carryParagraphProperties = ({ tr, position, source, styleResolver, numberi
|
|
|
32
34
|
tracked: false
|
|
33
35
|
};
|
|
34
36
|
const previousFormatting = paragraphPropertiesSnapshot(target);
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
+
const formatting = carriedParagraphProperties({
|
|
38
|
+
source,
|
|
39
|
+
target,
|
|
40
|
+
...keep === void 0 ? {} : { keep }
|
|
41
|
+
});
|
|
37
42
|
if (JSON.stringify(previousFormatting) === JSON.stringify(formatting)) return {
|
|
38
43
|
tr,
|
|
39
44
|
changed: false,
|
|
@@ -152,4 +157,4 @@ const propertiesSetInBatch = (node, batchRevisionIds) => {
|
|
|
152
157
|
return new Set([.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(now)])].filter((key) => JSON.stringify(before[key]) !== JSON.stringify(now[key])));
|
|
153
158
|
};
|
|
154
159
|
//#endregion
|
|
155
|
-
export { carryParagraphProperties, paragraphLeftAfter, propertiesSetInBatch, recordReplacedParagraphProperties };
|
|
160
|
+
export { carriedParagraphProperties, carryParagraphProperties, paragraphLeftAfter, propertiesSetInBatch, recordReplacedParagraphProperties };
|
|
@@ -661,21 +661,23 @@ function handleSuggestionEnter(view, pluginState) {
|
|
|
661
661
|
view.dispatch(tr.scrollIntoView());
|
|
662
662
|
return true;
|
|
663
663
|
}
|
|
664
|
-
/** Find the adjacent visible unit without consuming
|
|
664
|
+
/** Find the adjacent visible unit without consuming retained deletions or bookmark markers. */
|
|
665
665
|
function caretDeleteTarget(state, direction) {
|
|
666
666
|
const { $from } = state.selection;
|
|
667
667
|
const backward = direction === "backward";
|
|
668
668
|
let from = backward ? $from.pos - 1 : $from.pos;
|
|
669
669
|
let to = backward ? $from.pos : $from.pos + 1;
|
|
670
670
|
while (from >= $from.start() && to <= $from.end()) {
|
|
671
|
-
const adjacent = state.doc.resolve(from)
|
|
672
|
-
|
|
671
|
+
const $adjacent = state.doc.resolve(from);
|
|
672
|
+
const adjacent = $adjacent.nodeAfter;
|
|
673
|
+
if (!adjacent || adjacent.type.name !== "bookmarkBoundary" && !adjacent.marks.some((mark) => mark.type === state.schema.marks["deletion"])) return {
|
|
673
674
|
type: "inlineUnit",
|
|
674
675
|
from,
|
|
675
676
|
to
|
|
676
677
|
};
|
|
677
|
-
|
|
678
|
-
|
|
678
|
+
const skipped = backward && adjacent.isText ? $adjacent.textOffset + 1 : adjacent.nodeSize;
|
|
679
|
+
from += backward ? -skipped : skipped;
|
|
680
|
+
to += backward ? -skipped : skipped;
|
|
679
681
|
}
|
|
680
682
|
return { type: "paragraphEdge" };
|
|
681
683
|
}
|