@stll/folio-core 0.59.0 → 0.61.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 +23 -1
- package/dist/ai-edits/apply.js +139 -32
- package/dist/ai-edits/headless.d.ts +3 -0
- package/dist/ai-edits/headless.js +57 -63
- 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 +4 -2
- package/dist/compat/eigenpal.js +2 -2
- 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/canonicalSession.js +3 -2
- package/dist/controller/canonicalStructure.js +10 -7
- package/dist/controller/fontReadiness.js +1 -1
- 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 +19 -4
- package/dist/controller/layoutSession.d.ts +4 -1
- package/dist/display-list/build/fontTable.js +7 -5
- package/dist/display-list/build/furniture.d.ts +1 -0
- package/dist/display-list/build/furniture.js +1 -0
- package/dist/display-list/build/imagePrimitives.js +3 -6
- package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
- package/dist/display-list/build/watermarkPrimitives.js +9 -3
- package/dist/display-list/editor/pageRenderer.js +1 -0
- package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
- package/dist/docx/bookmarkIdNormalization.js +100 -0
- package/dist/docx/bookmarkParser.js +4 -2
- 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 +6 -1
- package/dist/docx/importedIdCollisions.d.ts +136 -0
- package/dist/docx/importedIdCollisions.js +215 -0
- 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/numberingParser.js +2 -2
- package/dist/docx/packageParts.js +6 -5
- package/dist/docx/paragraphParser.js +6 -4
- package/dist/docx/paragraphPropertySource.js +1 -2
- package/dist/docx/parseContext.d.ts +2 -1
- package/dist/docx/parseContext.js +1 -0
- package/dist/docx/parseWarningMessage.js +1 -0
- package/dist/docx/parser.js +10 -5
- package/dist/docx/preservedRunContent.js +11 -2
- package/dist/docx/relsParser.js +1 -1
- package/dist/docx/removeHeaderFooterParts.js +8 -7
- package/dist/docx/replyToComment.js +3 -13
- package/dist/docx/rezip.js +90 -90
- 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/selectedXmlIdentityScan.d.ts +10 -0
- package/dist/docx/selectedXmlIdentityScan.js +36 -0
- package/dist/docx/selectiveSave.js +19 -17
- package/dist/docx/selectiveXmlPatch.js +44 -52
- package/dist/docx/serializer/commentSerializer.d.ts +3 -1
- package/dist/docx/serializer/commentSerializer.js +11 -2
- package/dist/docx/serializer/runSerializer.js +5 -4
- package/dist/docx/serializer/tableSerializer.js +2 -1
- package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
- package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
- 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/embeddedFontFingerprint.d.ts +5 -0
- package/dist/fonts/embeddedFontFingerprint.js +18 -0
- package/dist/fonts/embeddedFonts.d.ts +1 -1
- package/dist/fonts/embeddedFonts.js +1 -1
- package/dist/fonts/fontsourceFaces.js +2 -1
- package/dist/fonts/headlessMeasure.js +0 -0
- 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/headless-layout.js +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -2
- 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/flowConversionShared.d.ts +4 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +5 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +16 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +6 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +13 -14
- package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +25 -1
- package/dist/layout-engine/measure/cache.js +39 -7
- package/dist/layout-engine/measure/crossRunWords.js +12 -2
- package/dist/layout-engine/measure/lineTypography.js +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
- package/dist/layout-engine/measure/measureContainer.js +3 -4
- package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
- package/dist/layout-engine/measure/measureHelpers.js +21 -18
- package/dist/layout-engine/measure/measureParagraph.js +2 -0
- package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
- package/dist/layout-engine/types.d.ts +4 -1
- package/dist/layout-painter/renderPage.d.ts +1 -0
- package/dist/layout-painter/renderPage.js +11 -3
- package/dist/layout-painter/renderParagraph.js +13 -3
- package/dist/layout-painter/renderWatermark.d.ts +1 -0
- package/dist/layout-painter/renderWatermark.js +7 -3
- 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/TableSelectionManager.d.ts +1 -1
- package/dist/managers/autoSaveCodec.js +2 -6
- package/dist/managers/editorShortcuts.d.ts +2 -1
- package/dist/managers/editorShortcuts.js +2 -1
- package/dist/managers/reviewDisplayMode.d.ts +8 -0
- package/dist/managers/reviewDisplayMode.js +15 -0
- 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 +3 -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/canonicalSelectionRange.d.ts +4 -1
- package/dist/prosemirror/canonicalSelectionRange.js +9 -3
- package/dist/prosemirror/commands/comments.js +51 -13
- package/dist/prosemirror/containerFinalParagraph.d.ts +8 -8
- package/dist/prosemirror/containerFinalParagraph.js +8 -8
- package/dist/prosemirror/conversion/fromProseDoc.js +9 -4
- package/dist/prosemirror/conversion/toProseDoc.js +4 -4
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
- package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +16 -2
- package/dist/prosemirror/findReplaceSelection.d.ts +11 -1
- package/dist/prosemirror/findReplaceSelection.js +15 -1
- package/dist/prosemirror/markupViewProjection.d.ts +10 -1
- package/dist/prosemirror/markupViewProjection.js +21 -3
- package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
- package/dist/prosemirror/pluginKeyOwner.js +35 -0
- package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
- package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
- package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
- package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
- package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
- package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
- package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
- package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
- package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
- package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
- package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
- package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
- package/dist/prosemirror/plugins/documentNumbering.js +5 -3
- package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
- package/dist/prosemirror/plugins/documentStyleState.js +2 -2
- package/dist/prosemirror/plugins/documentStyles.js +1 -1
- package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
- package/dist/prosemirror/plugins/selectionTracker.js +4 -3
- package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
- package/dist/prosemirror/plugins/suggestionMode.js +4 -3
- package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
- package/dist/prosemirror/plugins/templateDirectives.js +19 -4
- package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
- package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
- package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
- package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
- package/dist/prosemirror/plugins/transactionInvariants.js +29 -4
- 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/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/findReplace.d.ts +5 -0
- package/dist/utils/fontLoader.d.ts +2 -2
- package/dist/utils/fontLoader.js +2 -7
- package/dist/utils/fontResolver.d.ts +7 -3
- package/dist/utils/fontResolver.js +6 -8
- package/dist/utils/replaceText.js +21 -4
- 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 +73 -31
|
@@ -2,11 +2,47 @@ import { setProseParagraphMarkupWithPropertySource } from "../../../docx/paragra
|
|
|
2
2
|
import { getTransactionDirtyRange } from "../../../paged-layout/transactionDirtyRange.js";
|
|
3
3
|
import { detectBaseDirection } from "../../../utils/baseDirection.js";
|
|
4
4
|
import { directionIsAutoManaged } from "../../paragraphDirection.js";
|
|
5
|
+
import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
|
|
5
6
|
import { createExtension } from "../create.js";
|
|
6
7
|
import { ignoreTrackedChanges } from "./ParagraphChangeTrackerExtension.js";
|
|
7
|
-
import { Plugin
|
|
8
|
+
import { Plugin } from "prosemirror-state";
|
|
8
9
|
//#region src/prosemirror/extensions/features/AutoBidiDetectionExtension.ts
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* AutoBidiDetection — sets the paragraph `direction` (to `{ source: "auto" }`)
|
|
12
|
+
* on RTL-led paragraphs that arrived without an explicit direction decision.
|
|
13
|
+
*
|
|
14
|
+
* Why: Folio only ever rendered/exported RTL when a paragraph already carried
|
|
15
|
+
* `w:bidi` (from a Word import) or the user toggled it by hand. Content that
|
|
16
|
+
* never had a flag — AI-generated text, Markdown/HTML/plain-text imports, paste,
|
|
17
|
+
* or just typing Arabic without the shortcut — stayed left-to-right both in the
|
|
18
|
+
* editor and in the exported `.docx`. The ProseMirror doc is the single source
|
|
19
|
+
* of truth for both the layout painter (`toFlowBlocks`) and the serializer
|
|
20
|
+
* (`fromProseDoc`), so writing the attribute here fixes the editor and the Word
|
|
21
|
+
* export from one place.
|
|
22
|
+
*
|
|
23
|
+
* Detection uses the first-strong-character rule (`detectBaseDirection`), the
|
|
24
|
+
* same logic the layout painter uses for base direction.
|
|
25
|
+
*
|
|
26
|
+
* Auto vs. explicit: only "auto-managed" paragraphs are (re-)evaluated — those
|
|
27
|
+
* whose `direction` is undecided (absent) or was set by this detector
|
|
28
|
+
* (`source: "auto"`). A manual user toggle or imported `w:bidi`
|
|
29
|
+
* (`source: "manual"`) is authoritative and never touched. Because the detector
|
|
30
|
+
* re-evaluates its own decisions, replacing an auto-RTL paragraph's text with
|
|
31
|
+
* Latin clears it again (no stale "sticky" RTL).
|
|
32
|
+
*
|
|
33
|
+
* The `direction` discriminated union is editor-runtime state. Its `"auto"`
|
|
34
|
+
* source is a *rendering* aid only — `directionToAuthoredBidi` maps it to
|
|
35
|
+
* `undefined`, so an auto-detected paragraph never serializes `w:bidi` on its
|
|
36
|
+
* own; only a manual decision (an explicit user toggle, or `w:bidi` the
|
|
37
|
+
* source document already carried) is authored content. This keeps a no-edit
|
|
38
|
+
* save byte-identical on direction, while the editor and layout painter still
|
|
39
|
+
* treat `"auto"` as RTL (`directionToBidi` / `directionIsRtl`) so detected
|
|
40
|
+
* text displays correctly before the user ever makes it explicit.
|
|
41
|
+
*
|
|
42
|
+
* Mirrors the appendTransaction + ensure-in-state pattern of
|
|
43
|
+
* `ParaIdAllocatorExtension`.
|
|
44
|
+
*/
|
|
45
|
+
const autoBidiDetectionKey = createPluginKeyOwner("autoBidiDetection");
|
|
10
46
|
const paragraphDirectionalText = (node) => {
|
|
11
47
|
let text = "";
|
|
12
48
|
node.descendants((child) => {
|
|
@@ -95,7 +131,7 @@ const ensureBaseDirectionInState = (state) => {
|
|
|
95
131
|
return state.apply(applyBidiUpdates(state, updates));
|
|
96
132
|
};
|
|
97
133
|
const createAutoBidiDetectionPlugin = () => new Plugin({
|
|
98
|
-
key: autoBidiDetectionKey,
|
|
134
|
+
key: autoBidiDetectionKey.createKey(),
|
|
99
135
|
appendTransaction(transactions, _oldState, newState) {
|
|
100
136
|
if (!transactions.some((t) => t.docChanged)) return null;
|
|
101
137
|
const [first, ...rest] = transactions;
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { Extension } from "../types.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Plugin } from "prosemirror-state";
|
|
3
3
|
//#region src/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts
|
|
4
|
-
declare const emptyParagraphFormatKey:
|
|
4
|
+
declare const emptyParagraphFormatKey: Readonly<{
|
|
5
|
+
key: string;
|
|
6
|
+
createKey: () => import("prosemirror-state").PluginKey<unknown>;
|
|
7
|
+
owns: (plugin: Plugin<unknown>) => boolean;
|
|
8
|
+
get: (state: import("prosemirror-state").EditorState) => Plugin<unknown> | undefined;
|
|
9
|
+
getState: (state: import("prosemirror-state").EditorState) => unknown;
|
|
10
|
+
}>;
|
|
5
11
|
declare const EmptyParagraphFormatExtension: (options?: Partial<Record<string, unknown>> | undefined) => Extension;
|
|
6
12
|
//#endregion
|
|
7
13
|
export { EmptyParagraphFormatExtension, emptyParagraphFormatKey };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
|
|
1
2
|
import { createExtension } from "../create.js";
|
|
2
3
|
import { textFormattingToMarks } from "../marks/markUtils.js";
|
|
3
|
-
import { Plugin
|
|
4
|
+
import { Plugin } from "prosemirror-state";
|
|
4
5
|
//#region src/prosemirror/extensions/features/EmptyParagraphFormatExtension.ts
|
|
5
6
|
/**
|
|
6
7
|
* EmptyParagraphFormat — re-establishes stored marks for an empty styled
|
|
@@ -22,7 +23,7 @@ import { Plugin, PluginKey } from "prosemirror-state";
|
|
|
22
23
|
* (bold/italic/color/…). Plain body paragraphs (font + size only) are left
|
|
23
24
|
* untouched so ordinary typed text stays mark-free and serializes cleanly.
|
|
24
25
|
*/
|
|
25
|
-
const emptyParagraphFormatKey =
|
|
26
|
+
const emptyParagraphFormatKey = createPluginKeyOwner("emptyParagraphFormat");
|
|
26
27
|
/**
|
|
27
28
|
* Run-formatting properties the painter does NOT reproduce from
|
|
28
29
|
* `defaultTextFormatting` on its own (it forwards only font family + size).
|
|
@@ -37,7 +38,7 @@ function hasNonFontDefaults(dtf) {
|
|
|
37
38
|
}
|
|
38
39
|
function createEmptyParagraphFormatPlugin() {
|
|
39
40
|
return new Plugin({
|
|
40
|
-
key: emptyParagraphFormatKey,
|
|
41
|
+
key: emptyParagraphFormatKey.createKey(),
|
|
41
42
|
appendTransaction(transactions, _oldState, newState) {
|
|
42
43
|
if (!transactions.some((t) => t.selectionSet || t.docChanged)) return null;
|
|
43
44
|
const { selection } = newState;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
|
|
1
2
|
import { createExtension } from "../create.js";
|
|
2
|
-
import { NodeSelection, Plugin
|
|
3
|
+
import { NodeSelection, Plugin } from "prosemirror-state";
|
|
3
4
|
//#region src/prosemirror/extensions/features/ImageDragExtension.ts
|
|
4
5
|
/**
|
|
5
6
|
* Image Drag Extension — handles drag-to-reposition for images
|
|
@@ -10,12 +11,12 @@ import { NodeSelection, Plugin, PluginKey } from "prosemirror-state";
|
|
|
10
11
|
* - Inline images: reorder within text flow via ProseMirror's default drag
|
|
11
12
|
* - Custom drag initiation from mousedown on selected images
|
|
12
13
|
*/
|
|
13
|
-
const imageDragKey =
|
|
14
|
+
const imageDragKey = createPluginKeyOwner("imageDrag");
|
|
14
15
|
const ImageDragExtension = createExtension({
|
|
15
16
|
name: "imageDrag",
|
|
16
17
|
onSchemaReady(_ctx) {
|
|
17
18
|
return { plugins: [new Plugin({
|
|
18
|
-
key: imageDragKey,
|
|
19
|
+
key: imageDragKey.createKey(),
|
|
19
20
|
props: { handleDOMEvents: {
|
|
20
21
|
dragstart(view, event) {
|
|
21
22
|
const { selection } = view.state;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
|
|
1
2
|
import { createExtension } from "../create.js";
|
|
2
|
-
import { Plugin
|
|
3
|
+
import { Plugin } from "prosemirror-state";
|
|
3
4
|
//#region src/prosemirror/extensions/features/JoinedRunStyleExtension.ts
|
|
4
5
|
/**
|
|
5
6
|
* Runs that a join moves into another paragraph take that paragraph's style.
|
|
@@ -16,7 +17,7 @@ import { Plugin, PluginKey } from "prosemirror-state";
|
|
|
16
17
|
* {@link JOINED_RUNS_RESTYLED_META}, and is left as it is.
|
|
17
18
|
*/
|
|
18
19
|
const JOINED_RUNS_RESTYLED_META = "joinedRunsRestyled";
|
|
19
|
-
const pastedTableEndKey =
|
|
20
|
+
const pastedTableEndKey = createPluginKeyOwner("pastedTableEnd");
|
|
20
21
|
/**
|
|
21
22
|
* A table pasted over a story's last paragraph leaves that paragraph, emptied,
|
|
22
23
|
* after it: a story ends with a paragraph, and the paste replaced the words,
|
|
@@ -24,7 +25,7 @@ const pastedTableEndKey = new PluginKey("pastedTableEnd");
|
|
|
24
25
|
* paragraph, so the empty one is put back.
|
|
25
26
|
*/
|
|
26
27
|
const createPastedTableEndPlugin = () => new Plugin({
|
|
27
|
-
key: pastedTableEndKey,
|
|
28
|
+
key: pastedTableEndKey.createKey(),
|
|
28
29
|
appendTransaction(transactions, oldState, newState) {
|
|
29
30
|
if (!transactions.some((transaction) => transaction.docChanged && transaction.getMeta("uiEvent") === "paste")) return null;
|
|
30
31
|
if (newState.doc.lastChild?.type.spec["tableRole"] !== "table" || oldState.doc.lastChild?.type.name !== "paragraph") return null;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { Extension } from "../types.js";
|
|
2
2
|
import { Node } from "prosemirror-model";
|
|
3
|
-
import { EditorState,
|
|
3
|
+
import { EditorState, Plugin, Transaction } from "prosemirror-state";
|
|
4
4
|
//#region src/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts
|
|
5
5
|
type ParagraphPropertySourceSeed = {
|
|
6
6
|
contract: string | null;
|
|
7
7
|
tokens: ReadonlySet<string>;
|
|
8
8
|
};
|
|
9
|
-
declare const paraIdAllocatorKey:
|
|
9
|
+
declare const paraIdAllocatorKey: Readonly<{
|
|
10
|
+
key: string;
|
|
11
|
+
createKey: () => import("prosemirror-state").PluginKey<ParagraphPropertySourceSeed>;
|
|
12
|
+
owns: (plugin: Plugin<ParagraphPropertySourceSeed>) => boolean;
|
|
13
|
+
get: (state: EditorState) => Plugin<ParagraphPropertySourceSeed> | undefined;
|
|
14
|
+
getState: (state: EditorState) => ParagraphPropertySourceSeed | undefined;
|
|
15
|
+
}>;
|
|
10
16
|
/**
|
|
11
17
|
* Transaction meta asking this plugin to derive the ids it mints from a
|
|
12
18
|
* caller-supplied seed instead of `Math.random()`.
|
|
@@ -17,7 +23,7 @@ declare const paraIdAllocatorKey: PluginKey<ParagraphPropertySourceSeed>;
|
|
|
17
23
|
* be deterministic, so it says so on its own transaction rather than leaving
|
|
18
24
|
* the plugin to guess.
|
|
19
25
|
*/
|
|
20
|
-
declare const deterministicParaIdSeedKey
|
|
26
|
+
declare const deterministicParaIdSeedKey = "stll.folio.meta.deterministicParaIdSeed";
|
|
21
27
|
/** Ask the allocator to mint reproducible ids for the paragraphs `tr` creates. */
|
|
22
28
|
declare const requestDeterministicParaIds: (tr: Transaction, seed: string) => Transaction;
|
|
23
29
|
type ParagraphPropertySourceKeeper = {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR, getExplicitParagraphPropertySourceTransfers, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithParagraphPropertySource, setProseParagraphMarkupWithPropertySource, transferProseParagraphPropertySource } from "../../../docx/paragraphPropertySource.js";
|
|
2
2
|
import { deterministicHexId, generateHexId } from "../../../utils/hexId.js";
|
|
3
|
+
import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
|
|
3
4
|
import { sweepPositions } from "../../positionSweep.js";
|
|
4
5
|
import { createExtension } from "../create.js";
|
|
5
6
|
import { ignoreTrackedChanges } from "./ParagraphChangeTrackerExtension.js";
|
|
6
7
|
import { panic } from "better-result";
|
|
7
8
|
import { Fragment } from "prosemirror-model";
|
|
8
|
-
import { Plugin
|
|
9
|
+
import { Plugin } from "prosemirror-state";
|
|
9
10
|
//#region src/prosemirror/extensions/features/ParaIdAllocatorExtension.ts
|
|
10
11
|
/**
|
|
11
12
|
* ParaIdAllocator — assigns a stable `w14:paraId` to every paragraph.
|
|
@@ -44,7 +45,7 @@ import { Plugin, PluginKey } from "prosemirror-state";
|
|
|
44
45
|
* split therefore restores the same allocated id instead of minting
|
|
45
46
|
* another one.
|
|
46
47
|
*/
|
|
47
|
-
const paraIdAllocatorKey =
|
|
48
|
+
const paraIdAllocatorKey = createPluginKeyOwner("paraIdAllocator");
|
|
48
49
|
/**
|
|
49
50
|
* Transaction meta asking this plugin to derive the ids it mints from a
|
|
50
51
|
* caller-supplied seed instead of `Math.random()`.
|
|
@@ -55,7 +56,7 @@ const paraIdAllocatorKey = new PluginKey("paraIdAllocator");
|
|
|
55
56
|
* be deterministic, so it says so on its own transaction rather than leaving
|
|
56
57
|
* the plugin to guess.
|
|
57
58
|
*/
|
|
58
|
-
const deterministicParaIdSeedKey =
|
|
59
|
+
const deterministicParaIdSeedKey = "stll.folio.meta.deterministicParaIdSeed";
|
|
59
60
|
/** Ask the allocator to mint reproducible ids for the paragraphs `tr` creates. */
|
|
60
61
|
const requestDeterministicParaIds = (tr, seed) => tr.setMeta(deterministicParaIdSeedKey, seed);
|
|
61
62
|
/**
|
|
@@ -297,7 +298,7 @@ const ensureParaIdsInState = (state) => {
|
|
|
297
298
|
return state.apply(tr);
|
|
298
299
|
};
|
|
299
300
|
const createParaIdAllocatorPlugin = () => new Plugin({
|
|
300
|
-
key: paraIdAllocatorKey,
|
|
301
|
+
key: paraIdAllocatorKey.createKey(),
|
|
301
302
|
state: {
|
|
302
303
|
init: (_config, state) => collectParagraphPropertySourceSeed(state.doc),
|
|
303
304
|
apply: (_transaction, seed) => seed
|
|
@@ -307,7 +308,7 @@ const createParaIdAllocatorPlugin = () => new Plugin({
|
|
|
307
308
|
const paragraphSourceSeed = paraIdAllocatorKey.getState(oldState);
|
|
308
309
|
if (!paragraphSourceSeed) panic("ParaId allocator lost its paragraph-property source seed");
|
|
309
310
|
const keeperPositions = mapParagraphKeepers(oldState.doc, transactions, paragraphSourceSeed);
|
|
310
|
-
const deterministicSeed = transactions.map((transaction) => transaction.getMeta(
|
|
311
|
+
const deterministicSeed = transactions.map((transaction) => transaction.getMeta("stll.folio.meta.deterministicParaIdSeed")).find((value) => typeof value === "string") ?? null;
|
|
311
312
|
const census = collectParagraphCensus(newState.doc, paragraphSourceSeed);
|
|
312
313
|
const updates = collectParaIdUpdatesFromCensus(census, keeperPositions.paraIds, deterministicSeed);
|
|
313
314
|
const paragraphSourceUpdates = collectParagraphPropertySourceUpdates(census, keeperPositions.sourceTokens, transactions);
|
|
@@ -2,9 +2,15 @@ import { document_d_exports } from "../../../types/document.js";
|
|
|
2
2
|
import { Extension } from "../types.js";
|
|
3
3
|
import { RemovedSectionReference, TrackedSectionEndpointRemoval } from "../../../internal/sectionEndpointResolution.js";
|
|
4
4
|
import { Node } from "prosemirror-model";
|
|
5
|
-
import { EditorState, Plugin,
|
|
5
|
+
import { EditorState, Plugin, Transaction } from "prosemirror-state";
|
|
6
6
|
//#region src/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts
|
|
7
|
-
declare const paragraphChangeTrackerKey:
|
|
7
|
+
declare const paragraphChangeTrackerKey: Readonly<{
|
|
8
|
+
key: string;
|
|
9
|
+
createKey: () => import("prosemirror-state").PluginKey<InternalParagraphChangeTrackerState>;
|
|
10
|
+
owns: (plugin: Plugin<InternalParagraphChangeTrackerState>) => boolean;
|
|
11
|
+
get: (state: EditorState) => Plugin<InternalParagraphChangeTrackerState> | undefined;
|
|
12
|
+
getState: (state: EditorState) => InternalParagraphChangeTrackerState | undefined;
|
|
13
|
+
}>;
|
|
8
14
|
type ParagraphChangeTrackerState = {
|
|
9
15
|
/** Set of paraIds that were modified since last clear */
|
|
10
16
|
changedParaIds: Set<string>;
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { withTrackedSectionEndpointRemoval } from "../../../internal/sectionEndpointResolution.js";
|
|
2
2
|
import { canonicalJson } from "../../../utils/canonicalJson.js";
|
|
3
3
|
import { enclosingParagraphIndexed, nodeAtIndexed, nodesBetweenIndexed } from "../../indexedNodeLookup.js";
|
|
4
|
+
import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
|
|
4
5
|
import { sweepPositions } from "../../positionSweep.js";
|
|
5
6
|
import { sectionPropertiesOf } from "../../sectionCarrier.js";
|
|
6
7
|
import { sectionMarkEditsOf } from "../../sectionMarkEdits.js";
|
|
7
8
|
import { createExtension } from "../create.js";
|
|
8
9
|
import { AddMarkStep, AddNodeMarkStep, AttrStep, RemoveMarkStep, RemoveNodeMarkStep } from "prosemirror-transform";
|
|
9
|
-
import { Plugin
|
|
10
|
+
import { Plugin } from "prosemirror-state";
|
|
10
11
|
import { isHistoryTransaction } from "prosemirror-history";
|
|
11
12
|
//#region src/prosemirror/extensions/features/ParagraphChangeTrackerExtension.ts
|
|
12
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Paragraph Change Tracker Extension
|
|
15
|
+
*
|
|
16
|
+
* Watches ProseMirror transactions and records which paragraph IDs (paraId)
|
|
17
|
+
* were modified. Also detects paragraph and block-structure changes.
|
|
18
|
+
* Used by the selective save system to patch only changed paragraphs in document.xml.
|
|
19
|
+
*/
|
|
20
|
+
const paragraphChangeTrackerKey = createPluginKeyOwner("paragraphChangeTracker");
|
|
13
21
|
const CLEAR_META = "clear";
|
|
14
22
|
const IGNORE_META = "ignore";
|
|
15
23
|
const STRUCTURAL_META = "structural";
|
|
@@ -196,7 +204,7 @@ const mapStepTouches = (tr, batches) => {
|
|
|
196
204
|
};
|
|
197
205
|
function createParagraphChangeTrackerPlugin() {
|
|
198
206
|
return new Plugin({
|
|
199
|
-
key: paragraphChangeTrackerKey,
|
|
207
|
+
key: paragraphChangeTrackerKey.createKey(),
|
|
200
208
|
state: {
|
|
201
209
|
init(_config, state) {
|
|
202
210
|
const counts = countDocumentStructure(state.doc);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { expectRunIdentityMarkAttrs } from "../../attrs/index.js";
|
|
2
2
|
import { nodesBetweenIndexed } from "../../indexedNodeLookup.js";
|
|
3
|
+
import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
|
|
3
4
|
import { sweepPositions } from "../../positionSweep.js";
|
|
4
5
|
import { RUN_IDENTITY_ATTRIBUTE, RUN_IDENTITY_MARK_NAME, runIdentityAttrs } from "../../runIdentity.js";
|
|
5
6
|
import { createMarkExtension } from "../create.js";
|
|
6
|
-
import { Plugin
|
|
7
|
+
import { Plugin } from "prosemirror-state";
|
|
7
8
|
import { isHistoryTransaction, undoDepth } from "prosemirror-history";
|
|
8
9
|
//#region src/prosemirror/extensions/marks/RunIdentityExtension.ts
|
|
9
10
|
/**
|
|
@@ -28,7 +29,7 @@ import { isHistoryTransaction, undoDepth } from "prosemirror-history";
|
|
|
28
29
|
* supplies the session the format itself says such a run belongs to.
|
|
29
30
|
*/
|
|
30
31
|
const CANONICAL_RUN_IDENTITY_ID = /^(?:0|[1-9]\d*)$/u;
|
|
31
|
-
const runIdentityStripKey =
|
|
32
|
+
const runIdentityStripKey = createPluginKeyOwner("runIdentityStrip");
|
|
32
33
|
/**
|
|
33
34
|
* Every range `transactions` inserted, in the document they produced.
|
|
34
35
|
*
|
|
@@ -87,7 +88,7 @@ const insertedRanges = (transactions, skip = () => false) => {
|
|
|
87
88
|
* collaborative apply all arrive here and nowhere else in common.
|
|
88
89
|
*/
|
|
89
90
|
const createRunIdentityStripPlugin = () => new Plugin({
|
|
90
|
-
key: runIdentityStripKey,
|
|
91
|
+
key: runIdentityStripKey.createKey(),
|
|
91
92
|
appendTransaction(transactions, oldState, newState) {
|
|
92
93
|
if (!transactions.some((transaction) => transaction.docChanged)) return null;
|
|
93
94
|
const markType = newState.schema.marks[RUN_IDENTITY_MARK_NAME];
|
|
@@ -409,7 +409,7 @@ function isMarkActive(state, type, attrs) {
|
|
|
409
409
|
});
|
|
410
410
|
let hasMark = false;
|
|
411
411
|
state.doc.nodesBetween(from, to, (node) => {
|
|
412
|
-
if (node.isText) {
|
|
412
|
+
if (node.isText && !(RUN_FORMATTING_MARK_NAMES.has(markType.name) && node.marks.some((mark) => mark.type.name === "footnoteRef"))) {
|
|
413
413
|
const mark = markType.isInSet(node.marks);
|
|
414
414
|
if (mark) {
|
|
415
415
|
if (!attrs) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readCommentReferenceAttrs } from "../../commentReferenceAttrs.js";
|
|
2
2
|
import { planCommentReferenceRepairs } from "../../commentReferenceIntegrity.js";
|
|
3
3
|
import { readRangeAnchorAttrs } from "../../rangeAnchorAttrs.js";
|
|
4
|
+
import { trackedRunInlineAtomDisposition } from "../../trackedRunInlineAtoms.js";
|
|
4
5
|
import { createNodeExtension } from "../create.js";
|
|
5
6
|
import "./RangeAnchorExtension.js";
|
|
6
7
|
import { Plugin } from "prosemirror-state";
|
|
@@ -10,7 +11,16 @@ const COMMENT_REFERENCE_NODE_NAME = "commentReference";
|
|
|
10
11
|
const surveyCommentReferences = (doc) => {
|
|
11
12
|
const references = [];
|
|
12
13
|
const markEnds = /* @__PURE__ */ new Map();
|
|
14
|
+
const unanchoredMarks = [];
|
|
13
15
|
doc.descendants((node, position) => {
|
|
16
|
+
const transparent = trackedRunInlineAtomDisposition(node) === "transparent";
|
|
17
|
+
if (transparent) {
|
|
18
|
+
for (const mark of node.marks) if (mark.type.name === "comment") unanchoredMarks.push({
|
|
19
|
+
position,
|
|
20
|
+
size: node.nodeSize,
|
|
21
|
+
mark
|
|
22
|
+
});
|
|
23
|
+
}
|
|
14
24
|
if (node.type.name === "commentReference") {
|
|
15
25
|
const attrs = readCommentReferenceAttrs(node);
|
|
16
26
|
references.push(attrs.ok ? {
|
|
@@ -33,6 +43,7 @@ const surveyCommentReferences = (doc) => {
|
|
|
33
43
|
}
|
|
34
44
|
return false;
|
|
35
45
|
}
|
|
46
|
+
if (transparent) return false;
|
|
36
47
|
if (!node.isInline) return true;
|
|
37
48
|
for (const mark of node.marks) {
|
|
38
49
|
if (mark.type.name !== "comment") continue;
|
|
@@ -44,6 +55,7 @@ const surveyCommentReferences = (doc) => {
|
|
|
44
55
|
});
|
|
45
56
|
return {
|
|
46
57
|
references,
|
|
58
|
+
unanchoredMarks,
|
|
47
59
|
markExtents: [...markEnds].map(([commentId, end]) => ({
|
|
48
60
|
commentId,
|
|
49
61
|
end
|
|
@@ -84,9 +96,11 @@ const CommentReferenceExtension = createNodeExtension({
|
|
|
84
96
|
if (!transactions.some(({ docChanged }) => docChanged)) return null;
|
|
85
97
|
const referenceType = newState.schema.nodes[COMMENT_REFERENCE_NODE_NAME];
|
|
86
98
|
if (!referenceType) return null;
|
|
87
|
-
const
|
|
88
|
-
|
|
99
|
+
const survey = surveyCommentReferences(newState.doc);
|
|
100
|
+
const repairs = planCommentReferenceRepairs(survey);
|
|
101
|
+
if (repairs.length === 0 && survey.unanchoredMarks.length === 0) return null;
|
|
89
102
|
const transaction = newState.tr;
|
|
103
|
+
for (const { position, size, mark } of survey.unanchoredMarks) transaction.removeMark(position, position + size, mark);
|
|
90
104
|
for (const repair of repairs) {
|
|
91
105
|
if (repair.type === "delete") {
|
|
92
106
|
transaction.delete(repair.position, repair.position + repair.size);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { DisplayMode } from "../managers/EditorModeManager.js";
|
|
1
2
|
import { FindOptions } from "../utils/findReplace.js";
|
|
2
3
|
import { Node } from "prosemirror-model";
|
|
4
|
+
import { EditorState } from "prosemirror-state";
|
|
3
5
|
//#region src/prosemirror/findReplaceSelection.d.ts
|
|
4
6
|
/**
|
|
5
7
|
* Positional fields of a document search match that the range resolver needs.
|
|
@@ -26,5 +28,13 @@ type ProseMirrorFindMatch = FindMatchPosition & FindMatchRange & {
|
|
|
26
28
|
};
|
|
27
29
|
declare function resolveFindMatchRange(doc: Node, match: FindMatchPosition): FindMatchRange | null;
|
|
28
30
|
declare function findInProseMirrorDocument(doc: Node, searchText: string, options: FindOptions): ProseMirrorFindMatch[];
|
|
31
|
+
type FindInMarkupViewOptions = {
|
|
32
|
+
state: EditorState;
|
|
33
|
+
markupView: DisplayMode;
|
|
34
|
+
searchText: string;
|
|
35
|
+
options: FindOptions;
|
|
36
|
+
};
|
|
37
|
+
/** Search the displayed story; returned ranges address the authored editor document. */
|
|
38
|
+
declare const findInMarkupView: ({ state, markupView, searchText, options }: FindInMarkupViewOptions) => ProseMirrorFindMatch[];
|
|
29
39
|
//#endregion
|
|
30
|
-
export { FindMatchPosition, FindMatchRange, ProseMirrorFindMatch, findInProseMirrorDocument, resolveFindMatchRange };
|
|
40
|
+
export { FindMatchPosition, FindMatchRange, ProseMirrorFindMatch, findInMarkupView, findInProseMirrorDocument, resolveFindMatchRange };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { findAllMatches } from "../utils/findReplace.js";
|
|
2
2
|
import { decodeOoxmlSymbolCharacter } from "../utils/ooxmlSymbol.js";
|
|
3
3
|
import { expectSymbolAttrs } from "./attrs/index.js";
|
|
4
|
+
import { projectMarkupView } from "./markupViewProjection.js";
|
|
4
5
|
//#region src/prosemirror/findReplaceSelection.ts
|
|
5
6
|
function resolveFindMatchRange(doc, match) {
|
|
6
7
|
let resolved = null;
|
|
@@ -40,6 +41,19 @@ function findInProseMirrorDocument(doc, searchText, options) {
|
|
|
40
41
|
});
|
|
41
42
|
return matches;
|
|
42
43
|
}
|
|
44
|
+
/** Search the displayed story; returned ranges address the authored editor document. */
|
|
45
|
+
const findInMarkupView = ({ state, markupView, searchText, options }) => {
|
|
46
|
+
const projection = projectMarkupView(state, markupView);
|
|
47
|
+
if (projection.type === "authored") return findInProseMirrorDocument(state.doc, searchText, options);
|
|
48
|
+
return findInProseMirrorDocument(projection.doc, searchText, options).map((match) => ({
|
|
49
|
+
paragraphIndex: match.paragraphIndex,
|
|
50
|
+
startOffset: match.startOffset,
|
|
51
|
+
endOffset: match.endOffset,
|
|
52
|
+
text: match.text,
|
|
53
|
+
from: projection.toEditor(match.from, 1),
|
|
54
|
+
to: projection.toEditor(match.to, -1)
|
|
55
|
+
}));
|
|
56
|
+
};
|
|
43
57
|
function forEachSearchParagraph(doc, visit) {
|
|
44
58
|
let paragraphIndex = 0;
|
|
45
59
|
const walkBlocks = (container, contentStart) => {
|
|
@@ -139,4 +153,4 @@ function getSearchableParagraphText(paragraph) {
|
|
|
139
153
|
return text;
|
|
140
154
|
}
|
|
141
155
|
//#endregion
|
|
142
|
-
export { findInProseMirrorDocument, resolveFindMatchRange };
|
|
156
|
+
export { findInMarkupView, findInProseMirrorDocument, resolveFindMatchRange };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
1
2
|
import { DisplayMode } from "../managers/EditorModeManager.js";
|
|
2
3
|
import { RemovedSectionReference } from "../internal/sectionEndpointResolution.js";
|
|
3
4
|
import { indexedPositionMap } from "../internal/indexedPositionMap.js";
|
|
@@ -93,5 +94,13 @@ declare const projectMarkupView: (state: EditorState, view: DisplayMode) => Mark
|
|
|
93
94
|
* of text it cannot enter.
|
|
94
95
|
*/
|
|
95
96
|
declare const visibleCaretPosition: (projection: MarkupViewProjection, position: number) => number;
|
|
97
|
+
type ProjectStoryMarkupViewOptions = {
|
|
98
|
+
doc: Node;
|
|
99
|
+
markupView: DisplayMode;
|
|
100
|
+
styles?: document_d_exports.StyleDefinitions | null | undefined;
|
|
101
|
+
numbering?: document_d_exports.NumberingDefinitions | undefined;
|
|
102
|
+
};
|
|
103
|
+
/** Detached stories use the same state-aware projection owner as the body. */
|
|
104
|
+
declare const projectStoryMarkupView: ({ doc, markupView, styles, numbering }: ProjectStoryMarkupViewOptions) => MarkupViewProjection;
|
|
96
105
|
//#endregion
|
|
97
|
-
export { MarkupViewProjection, markupViewResolutionMode, projectMarkupView, resolveStateStory, visibleCaretPosition };
|
|
106
|
+
export { MarkupViewProjection, markupViewResolutionMode, projectMarkupView, projectStoryMarkupView, resolveStateStory, visibleCaretPosition };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { indexedPositionMap } from "../internal/indexedPositionMap.js";
|
|
2
2
|
import { finalRevisionParagraphRanges } from "../internal/revisionResolutionTracking.js";
|
|
3
3
|
import { resolveWholeStory } from "../internal/wholeStoryRevisionResolution.js";
|
|
4
|
-
import { getDocumentNumbering } from "./plugins/documentNumbering.js";
|
|
4
|
+
import { createDocumentNumberingPlugin, getDocumentNumbering } from "./plugins/documentNumbering.js";
|
|
5
5
|
import { getDocumentStyleResolver } from "./plugins/documentStyleState.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createDocumentStyleContextPlugin } from "./plugins/documentStyles.js";
|
|
7
|
+
import { EditorState, Selection } from "prosemirror-state";
|
|
7
8
|
//#region src/prosemirror/markupViewProjection.ts
|
|
8
9
|
/** Resolve every revision in the state's story with the state's own styles and numbering. */
|
|
9
10
|
const resolveStateStory = (state, mode) => resolveWholeStory({
|
|
@@ -84,5 +85,22 @@ const visibleCaretPosition = (projection, position) => {
|
|
|
84
85
|
const near = Selection.near(projection.doc.resolve(bounded), -1);
|
|
85
86
|
return projection.toEditor(near.head, -1);
|
|
86
87
|
};
|
|
88
|
+
const storyProjectionStates = /* @__PURE__ */ new WeakMap();
|
|
89
|
+
/** Detached stories use the same state-aware projection owner as the body. */
|
|
90
|
+
const projectStoryMarkupView = ({ doc, markupView, styles, numbering }) => {
|
|
91
|
+
if (markupView === "all-markup") return AUTHORED;
|
|
92
|
+
const cached = storyProjectionStates.get(doc);
|
|
93
|
+
if (cached && cached.styles === styles && cached.numbering === numbering) return projectMarkupView(cached.state, markupView);
|
|
94
|
+
const state = EditorState.create({
|
|
95
|
+
doc,
|
|
96
|
+
plugins: [createDocumentStyleContextPlugin(styles), createDocumentNumberingPlugin(numbering)]
|
|
97
|
+
});
|
|
98
|
+
storyProjectionStates.set(doc, {
|
|
99
|
+
styles,
|
|
100
|
+
numbering,
|
|
101
|
+
state
|
|
102
|
+
});
|
|
103
|
+
return projectMarkupView(state, markupView);
|
|
104
|
+
};
|
|
87
105
|
//#endregion
|
|
88
|
-
export { markupViewResolutionMode, projectMarkupView, resolveStateStory, visibleCaretPosition };
|
|
106
|
+
export { markupViewResolutionMode, projectMarkupView, projectStoryMarkupView, resolveStateStory, visibleCaretPosition };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EditorState, Plugin, PluginKey } from "prosemirror-state";
|
|
2
|
+
//#region src/prosemirror/pluginKeyOwner.d.ts
|
|
3
|
+
type PluginKeyOwner<State> = Readonly<{
|
|
4
|
+
key: string;
|
|
5
|
+
createKey: () => PluginKey<State>;
|
|
6
|
+
owns: (plugin: Plugin<State>) => boolean;
|
|
7
|
+
get: (state: EditorState) => Plugin<State> | undefined;
|
|
8
|
+
getState: (state: EditorState) => State | undefined;
|
|
9
|
+
}>;
|
|
10
|
+
/** An immutable plugin family descriptor; each plugin owns its actual key. */
|
|
11
|
+
declare const createPluginKeyOwner: <State = unknown>(name: string) => PluginKeyOwner<State>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { PluginKeyOwner, createPluginKeyOwner };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { panic } from "better-result";
|
|
2
|
+
import { PluginKey } from "prosemirror-state";
|
|
3
|
+
//#region src/prosemirror/pluginKeyOwner.ts
|
|
4
|
+
const PLUGIN_KEY_PREFIX = "stll.folio.plugin.";
|
|
5
|
+
const METADATA_KEY_PREFIX = "stll.folio.meta.";
|
|
6
|
+
const PLUGIN_OWNER_BRAND = Symbol.for("stll.folio.plugin.owner");
|
|
7
|
+
/** An immutable plugin family descriptor; each plugin owns its actual key. */
|
|
8
|
+
const createPluginKeyOwner = (name) => {
|
|
9
|
+
const pluginsByState = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
const owns = (plugin) => plugin.spec.key !== void 0 && PLUGIN_OWNER_BRAND in plugin.spec.key && plugin.spec.key[PLUGIN_OWNER_BRAND] === name;
|
|
11
|
+
const get = (state) => {
|
|
12
|
+
if (pluginsByState.has(state)) return pluginsByState.get(state);
|
|
13
|
+
let found;
|
|
14
|
+
for (const plugin of state.plugins) {
|
|
15
|
+
if (!owns(plugin)) continue;
|
|
16
|
+
if (found) panic(`Multiple plugins belong to ${name} in one editor state`);
|
|
17
|
+
found = plugin;
|
|
18
|
+
}
|
|
19
|
+
pluginsByState.set(state, found);
|
|
20
|
+
return found;
|
|
21
|
+
};
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
key: `${METADATA_KEY_PREFIX}${name}`,
|
|
24
|
+
createKey: () => {
|
|
25
|
+
const key = new PluginKey(`${PLUGIN_KEY_PREFIX}${name}`);
|
|
26
|
+
Object.defineProperty(key, PLUGIN_OWNER_BRAND, { value: name });
|
|
27
|
+
return key;
|
|
28
|
+
},
|
|
29
|
+
owns,
|
|
30
|
+
get,
|
|
31
|
+
getState: (state) => get(state)?.getState(state)
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { createPluginKeyOwner };
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PluginKeyOwner } from "../pluginKeyOwner.js";
|
|
2
|
+
import { Plugin } from "prosemirror-state";
|
|
2
3
|
import { DecorationSet } from "prosemirror-view";
|
|
3
4
|
//#region src/prosemirror/plugins/aiCitationDecorations.d.ts
|
|
4
|
-
declare const aiCitationDecorationsKey:
|
|
5
|
+
declare const aiCitationDecorationsKey: Readonly<{
|
|
6
|
+
key: string;
|
|
7
|
+
createKey: () => import("prosemirror-state").PluginKey<AICitationDecorationState>;
|
|
8
|
+
owns: (plugin: Plugin<AICitationDecorationState>) => boolean;
|
|
9
|
+
get: (state: import("prosemirror-state").EditorState) => Plugin<AICitationDecorationState> | undefined;
|
|
10
|
+
getState: (state: import("prosemirror-state").EditorState) => AICitationDecorationState | undefined;
|
|
11
|
+
}>;
|
|
5
12
|
declare const SET_META = "set";
|
|
6
13
|
declare const ACTIVE_META = "active";
|
|
7
14
|
type AICitationRange = {
|
|
@@ -23,14 +30,14 @@ type AICitationDecorationState = {
|
|
|
23
30
|
*/
|
|
24
31
|
declare function createAICitationDecorationsPlugin(): Plugin<AICitationDecorationState>;
|
|
25
32
|
declare function setAICitationsMeta(citations: AICitationRange[]): {
|
|
26
|
-
key:
|
|
33
|
+
key: PluginKeyOwner<AICitationDecorationState>;
|
|
27
34
|
payload: {
|
|
28
35
|
type: typeof SET_META;
|
|
29
36
|
citations: AICitationRange[];
|
|
30
37
|
};
|
|
31
38
|
};
|
|
32
39
|
declare function setActiveCitationMeta(activeId: string | null): {
|
|
33
|
-
key:
|
|
40
|
+
key: PluginKeyOwner<AICitationDecorationState>;
|
|
34
41
|
payload: {
|
|
35
42
|
type: typeof ACTIVE_META;
|
|
36
43
|
activeId: string | null;
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createPluginKeyOwner } from "../pluginKeyOwner.js";
|
|
2
|
+
import { Plugin } from "prosemirror-state";
|
|
2
3
|
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
3
4
|
//#region src/prosemirror/plugins/aiCitationDecorations.ts
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* AI Citation Decorations Plugin
|
|
7
|
+
*
|
|
8
|
+
* Renders pointer-back-to-source highlights on Folio (DOCX) ranges
|
|
9
|
+
* cited by an AI answer. Distinct from the suggestion-decoration
|
|
10
|
+
* plugin: citations are read-only pointers (no edit semantics) and
|
|
11
|
+
* usually appear briefly when the user clicks a citation chip in the
|
|
12
|
+
* thread.
|
|
13
|
+
*
|
|
14
|
+
* The host pushes updates via the `setAICitationsMeta` /
|
|
15
|
+
* `setActiveCitationMeta` helpers below.
|
|
16
|
+
*/
|
|
17
|
+
const aiCitationDecorationsKey = createPluginKeyOwner("aiCitationDecorations");
|
|
5
18
|
const SET_META = "set";
|
|
6
19
|
const ACTIVE_META = "active";
|
|
7
20
|
function buildDecorationSet(doc, citations, activeId) {
|
|
@@ -31,7 +44,7 @@ function buildDecorationSet(doc, citations, activeId) {
|
|
|
31
44
|
*/
|
|
32
45
|
function createAICitationDecorationsPlugin() {
|
|
33
46
|
return new Plugin({
|
|
34
|
-
key: aiCitationDecorationsKey,
|
|
47
|
+
key: aiCitationDecorationsKey.createKey(),
|
|
35
48
|
state: {
|
|
36
49
|
init(_, state) {
|
|
37
50
|
return {
|