@portone/docx-editor 0.5.1 → 0.6.1
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/CHANGELOG.md +47 -0
- package/CONTRIBUTING.md +8 -2
- package/README.md +1 -1
- package/dist/DocxEditor.js +87 -29
- package/dist/docx/exportDocx.d.ts +2 -1
- package/dist/docx/exportDocx.js +3 -9
- package/dist/docx/headersFooters.js +35 -23
- package/dist/docx/identities.d.ts +28 -0
- package/dist/docx/identities.js +42 -10
- package/dist/docx/importDocx.js +25 -26
- package/dist/docx/importParagraph.d.ts +1 -4
- package/dist/docx/importParagraph.js +4 -18
- package/dist/docx/invariants.d.ts +1 -1
- package/dist/docx/invariants.js +45 -4
- package/dist/docx/notes/newNote.d.ts +39 -0
- package/dist/docx/notes/newNote.js +122 -0
- package/dist/docx/notes/numbering.d.ts +27 -0
- package/dist/docx/notes/numbering.js +120 -0
- package/dist/docx/notes/reading.d.ts +58 -0
- package/dist/docx/notes/reading.js +98 -0
- package/dist/docx/notes/writing.d.ts +19 -0
- package/dist/docx/notes/writing.js +96 -0
- package/dist/docx/partPlan.d.ts +3 -0
- package/dist/docx/partPlanners.d.ts +13 -0
- package/dist/docx/partPlanners.js +48 -0
- package/dist/docx/sections.d.ts +5 -0
- package/dist/docx/sections.js +7 -2
- package/dist/docx/serializeParagraph.js +7 -2
- package/dist/docx/session.d.ts +5 -0
- package/dist/docx/session.js +6 -0
- package/dist/docx/storyParts.d.ts +112 -0
- package/dist/docx/storyParts.js +289 -0
- package/dist/editor/clipboard/htmlReader.d.ts +24 -4
- package/dist/editor/clipboard/htmlReader.js +39 -4
- package/dist/editor/clipboard/internalChannel.d.ts +30 -3
- package/dist/editor/clipboard/internalChannel.js +43 -3
- package/dist/editor/clipboard/normalizers.d.ts +35 -8
- package/dist/editor/clipboard/normalizers.js +60 -11
- package/dist/editor/clipboard/plugin.js +42 -22
- package/dist/editor/commands/comments/editing.d.ts +4 -1
- package/dist/editor/commands/comments/editing.js +1 -3
- package/dist/editor/commands/comments/model.d.ts +7 -0
- package/dist/editor/commands/index.d.ts +1 -0
- package/dist/editor/commands/index.js +18 -0
- package/dist/editor/commands/noteCommands.d.ts +47 -0
- package/dist/editor/commands/noteCommands.js +95 -0
- package/dist/editor/commands/noteQueries.d.ts +22 -3
- package/dist/editor/commands/noteQueries.js +21 -13
- package/dist/editor/createEditor.js +25 -3
- package/dist/editor/documentStyles.d.ts +3 -0
- package/dist/editor/documentStyles.js +2 -1
- package/dist/editor/editorDocument.d.ts +24 -0
- package/dist/editor/editorDocument.js +34 -4
- package/dist/editor/notes/noteSurface.d.ts +53 -0
- package/dist/editor/notes/noteSurface.js +246 -0
- package/dist/editor/plugins/commentDecorations.js +5 -4
- package/dist/editor/plugins/commentRestoration.d.ts +20 -0
- package/dist/editor/plugins/commentRestoration.js +168 -0
- package/dist/editor/plugins/compositionSelection.d.ts +20 -0
- package/dist/editor/plugins/compositionSelection.js +19 -0
- package/dist/editor/plugins/keymap.d.ts +14 -0
- package/dist/editor/plugins/keymap.js +13 -1
- package/dist/editor/plugins/noteLifecycle.d.ts +18 -0
- package/dist/editor/plugins/noteLifecycle.js +117 -0
- package/dist/editor/plugins/noteNavigation.d.ts +45 -0
- package/dist/editor/plugins/noteNavigation.js +86 -0
- package/dist/editor/plugins/noteNumbering.d.ts +13 -0
- package/dist/editor/plugins/noteNumbering.js +58 -0
- package/dist/editor/plugins/rowResize.js +2 -7
- package/dist/editor/plugins/tabLayout.js +2 -7
- package/dist/editor/stories/storyMarkup.d.ts +24 -0
- package/dist/editor/stories/storyMarkup.js +35 -0
- package/dist/editor/stories/storyState.d.ts +34 -0
- package/dist/editor/stories/storyState.js +74 -0
- package/dist/editor/stories/storyView.d.ts +115 -0
- package/dist/editor/stories/storyView.js +144 -0
- package/dist/numbering/spellers.d.ts +1 -1
- package/dist/numbering/spellers.js +6 -1
- package/dist/page/blockKinds.d.ts +23 -4
- package/dist/page/demands/footnoteDemands.d.ts +18 -0
- package/dist/page/demands/footnoteDemands.js +51 -0
- package/dist/page/demands/index.d.ts +43 -0
- package/dist/page/demands/index.js +8 -0
- package/dist/page/kinds/paragraphKind.js +7 -1
- package/dist/page/kinds/tableKind.js +9 -1
- package/dist/page/measureBlocks.d.ts +2 -0
- package/dist/page/measureBlocks.js +31 -10
- package/dist/page/pageDecorations.d.ts +9 -2
- package/dist/page/pageDecorations.js +18 -5
- package/dist/page/pageLayout.d.ts +77 -1
- package/dist/page/pageLayout.js +186 -9
- package/dist/page/usePageLayout.d.ts +57 -2
- package/dist/page/usePageLayout.js +50 -5
- package/dist/schema/attrRoles.js +3 -2
- package/dist/schema/docxSchema.js +5 -2
- package/dist/schema/editGuard.d.ts +1 -1
- package/dist/schema/guards.js +1 -2
- package/dist/schema/preservedGuards.d.ts +4 -6
- package/dist/schema/preservedGuards.js +0 -9
- package/dist/schema/stories.d.ts +34 -2
- package/dist/schema/stories.js +22 -5
- package/dist/styles/classNames.d.ts +23 -6
- package/dist/styles/classNames.js +23 -6
- package/dist/styles/inlineStyle.d.ts +7 -0
- package/dist/styles/inlineStyle.js +11 -5
- package/dist/styles/visualScale.d.ts +19 -0
- package/dist/styles/visualScale.js +26 -0
- package/dist/styles.css +96 -36
- package/dist/ui/CommentsPanel.d.ts +6 -1
- package/dist/ui/CommentsPanel.js +26 -8
- package/dist/ui/InsertImageButton.d.ts +3 -1
- package/dist/ui/InsertImageButton.js +3 -2
- package/dist/ui/TableMenu.d.ts +5 -2
- package/dist/ui/TableMenu.js +18 -1
- package/dist/ui/TextMenu.d.ts +5 -2
- package/dist/ui/TextMenu.js +21 -6
- package/dist/ui/Toolbar.d.ts +17 -2
- package/dist/ui/Toolbar.js +23 -10
- package/dist/ui/comments/useCommentRailLayout.js +2 -4
- package/dist/ui/noteItems.d.ts +21 -0
- package/dist/ui/noteItems.js +30 -0
- package/dist/ui/notes/NoteAreas.d.ts +73 -0
- package/dist/ui/notes/NoteAreas.js +131 -0
- package/dist/ui/notes/NoteList.d.ts +25 -0
- package/dist/ui/notes/NoteList.js +58 -0
- package/dist/ui/notes/StoryRow.d.ts +75 -0
- package/dist/ui/notes/StoryRow.js +122 -0
- package/dist/ui/notes/noteBands.d.ts +100 -0
- package/dist/ui/notes/noteBands.js +142 -0
- package/dist/ui/notes/noteHeights.d.ts +10 -0
- package/dist/ui/notes/noteHeights.js +24 -0
- package/dist/ui/notes/noteSeparator.d.ts +12 -0
- package/dist/ui/notes/noteSeparator.js +9 -0
- package/dist/ui/notes/useStorySurface.d.ts +68 -0
- package/dist/ui/notes/useStorySurface.js +95 -0
- package/dist/ui/runCommand.d.ts +8 -1
- package/dist/ui/runCommand.js +2 -2
- package/dist/ui/shortcutLabels.d.ts +16 -0
- package/dist/ui/shortcutLabels.js +9 -0
- package/dist/ui/usePageRoom.d.ts +13 -0
- package/dist/ui/usePageRoom.js +31 -0
- package/package.json +2 -1
- package/dist/docx/notes.d.ts +0 -27
- package/dist/docx/notes.js +0 -55
- package/dist/ui/NotesPanel.d.ts +0 -6
- package/dist/ui/NotesPanel.js +0 -33
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { EditorView } from "prosemirror-view";
|
|
12
12
|
import { type RefObject } from "react";
|
|
13
|
-
import {
|
|
13
|
+
import type { DemandBand } from "./demands";
|
|
14
|
+
import { type SectionPixels, type TrailingRows } from "./pageLayout";
|
|
14
15
|
/** One place where a page parts from the next. The position is measured on the sheet */
|
|
15
16
|
export interface PageMark {
|
|
16
17
|
page: number;
|
|
@@ -19,6 +20,33 @@ export interface PageMark {
|
|
|
19
20
|
height: number;
|
|
20
21
|
crossed: boolean;
|
|
21
22
|
}
|
|
23
|
+
/** The room one page keeps at the foot of its body for one band, measured on the sheet */
|
|
24
|
+
export interface ReservedRoom {
|
|
25
|
+
band: string;
|
|
26
|
+
/** What the page keeps there, in the order it took them (`page/pageLayout`) */
|
|
27
|
+
ids: readonly string[];
|
|
28
|
+
top: number;
|
|
29
|
+
/**
|
|
30
|
+
* The height the page gives the band, down to the end of its body. Less than the band asks for
|
|
31
|
+
* where it holds more than the page could give it
|
|
32
|
+
*/
|
|
33
|
+
height: number;
|
|
34
|
+
/** Whether the band asks for more than that height */
|
|
35
|
+
clipped: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** The rows laid after the last block that one page holds, measured on the sheet */
|
|
38
|
+
export interface TrailingRoom {
|
|
39
|
+
/** What the page holds, in the order they are laid (`page/pageLayout`) */
|
|
40
|
+
ids: readonly string[];
|
|
41
|
+
top: number;
|
|
42
|
+
/**
|
|
43
|
+
* The height the page gives the rows, down to the end of its body. Less than they ask for where
|
|
44
|
+
* one of them is taller than the room the page had left
|
|
45
|
+
*/
|
|
46
|
+
height: number;
|
|
47
|
+
/** Whether the rows ask for more than that height */
|
|
48
|
+
clipped: boolean;
|
|
49
|
+
}
|
|
22
50
|
/** The paper area of one visual page, used to place its header and footer stories. */
|
|
23
51
|
export interface PageFace {
|
|
24
52
|
page: number;
|
|
@@ -34,6 +62,13 @@ export interface PageFace {
|
|
|
34
62
|
left: number;
|
|
35
63
|
width: number;
|
|
36
64
|
crossed: boolean;
|
|
65
|
+
/** What the page keeps at the foot of its body, one entry per band, top to bottom */
|
|
66
|
+
reserved: readonly ReservedRoom[];
|
|
67
|
+
/**
|
|
68
|
+
* The rows laid after the last block that landed on this page, measured on the sheet, and null
|
|
69
|
+
* for a page holding none (`page/pageLayout`)
|
|
70
|
+
*/
|
|
71
|
+
trailing: TrailingRoom | null;
|
|
37
72
|
}
|
|
38
73
|
export interface PageOverlay {
|
|
39
74
|
left: number;
|
|
@@ -55,6 +90,26 @@ interface PageLayoutOptions {
|
|
|
55
90
|
* change by the caller. A4 where a document names none, and where none is open
|
|
56
91
|
*/
|
|
57
92
|
sections?: readonly SectionPixels[];
|
|
93
|
+
/**
|
|
94
|
+
* The bands the demands of the text are kept in (`page/demands`), by name. Left out, the pages
|
|
95
|
+
* are the ones the blocks alone come to, which is also what a document asking for no room
|
|
96
|
+
* should be laid out through. A new value lays the pages out again
|
|
97
|
+
*/
|
|
98
|
+
bands?: ReadonlyMap<string, DemandBand>;
|
|
99
|
+
/**
|
|
100
|
+
* The rows laid after the last block of the document, which open pages of their own where the
|
|
101
|
+
* last page has no room left for them. A new value lays the pages out again
|
|
102
|
+
*/
|
|
103
|
+
trailing?: TrailingRows;
|
|
104
|
+
/**
|
|
105
|
+
* Whether anything drawn over the sheet besides the body is composing, such as the view over a
|
|
106
|
+
* note being edited.
|
|
107
|
+
*
|
|
108
|
+
* A measurement moves the room a band is kept in, and what is drawn in that room is drawn again
|
|
109
|
+
* wherever it lands, which would take an open composition down with it. So the frame is taken
|
|
110
|
+
* again until that composition is over, the way it is for the body's own.
|
|
111
|
+
*/
|
|
112
|
+
composing?: () => boolean;
|
|
58
113
|
}
|
|
59
|
-
export declare function usePageLayout({ view, layer, enabled, revision, sections, }: PageLayoutOptions): PageOverlay | null;
|
|
114
|
+
export declare function usePageLayout({ view, layer, enabled, revision, sections, bands, trailing, composing, }: PageLayoutOptions): PageOverlay | null;
|
|
60
115
|
export {};
|
|
@@ -14,6 +14,18 @@ import {
|
|
|
14
14
|
pageLayout,
|
|
15
15
|
sectionPaperAt
|
|
16
16
|
} from "./pageLayout.js";
|
|
17
|
+
var NO_ROOM = [];
|
|
18
|
+
function trailingOn(placement, contentTop, bodyBottom) {
|
|
19
|
+
if (placement === void 0) return null;
|
|
20
|
+
const top = contentTop + placement.top;
|
|
21
|
+
const height = Math.max(0, bodyBottom - top);
|
|
22
|
+
return {
|
|
23
|
+
ids: placement.ids,
|
|
24
|
+
top,
|
|
25
|
+
height: Math.min(placement.height, height),
|
|
26
|
+
clipped: placement.height > height
|
|
27
|
+
};
|
|
28
|
+
}
|
|
17
29
|
function useFrameThrottle(run, hold) {
|
|
18
30
|
const latest = useRef({ run, hold });
|
|
19
31
|
const frame = useRef(0);
|
|
@@ -51,7 +63,10 @@ function usePageLayout({
|
|
|
51
63
|
layer,
|
|
52
64
|
enabled,
|
|
53
65
|
revision,
|
|
54
|
-
sections
|
|
66
|
+
sections,
|
|
67
|
+
bands,
|
|
68
|
+
trailing,
|
|
69
|
+
composing
|
|
55
70
|
}) {
|
|
56
71
|
const [overlay, setOverlay] = useState(null);
|
|
57
72
|
const papers = sections === void 0 || sections.length === 0 ? A4_SECTION_PIXELS : sections;
|
|
@@ -60,7 +75,19 @@ function usePageLayout({
|
|
|
60
75
|
const box = layer.current;
|
|
61
76
|
if (!view || !box || !enabled) return;
|
|
62
77
|
const measured = measureSheet(view, box);
|
|
63
|
-
const layout = pageLayout({
|
|
78
|
+
const layout = pageLayout({
|
|
79
|
+
blocks: measured.blocks,
|
|
80
|
+
sections: papers,
|
|
81
|
+
bands,
|
|
82
|
+
trailing
|
|
83
|
+
});
|
|
84
|
+
const roomOn = /* @__PURE__ */ new Map();
|
|
85
|
+
for (const room of layout.reserved) {
|
|
86
|
+
roomOn.set(room.page, [...roomOn.get(room.page) ?? [], room]);
|
|
87
|
+
}
|
|
88
|
+
const laidOn = new Map(
|
|
89
|
+
layout.trailing.map((placement) => [placement.page, placement])
|
|
90
|
+
);
|
|
64
91
|
const paperOf = (pos) => sectionPaperAt(papers, pos);
|
|
65
92
|
const sheet = paperOf(0);
|
|
66
93
|
setPageMarks(view, { pushes: layout.pushes, cuts: layout.cuts });
|
|
@@ -83,6 +110,7 @@ function usePageLayout({
|
|
|
83
110
|
pages: layout.pages.map((start) => {
|
|
84
111
|
const paper = paperOf(start.pos);
|
|
85
112
|
const paperTop = measured.contentTop + start.bodyStart - (start.crossed ? 0 : paper.marginTop);
|
|
113
|
+
const bodyBottom = measured.contentTop + start.bodyStart + paper.bodyHeight;
|
|
86
114
|
return {
|
|
87
115
|
page: start.page,
|
|
88
116
|
pos: start.pos,
|
|
@@ -91,19 +119,36 @@ function usePageLayout({
|
|
|
91
119
|
footerTop: paperTop + paper.pageHeight - paper.marginBottom / 2,
|
|
92
120
|
left: sheet.marginLeft,
|
|
93
121
|
width: sheet.bodyWidth,
|
|
94
|
-
crossed: start.crossed
|
|
122
|
+
crossed: start.crossed,
|
|
123
|
+
trailing: trailingOn(
|
|
124
|
+
laidOn.get(start.page),
|
|
125
|
+
measured.contentTop,
|
|
126
|
+
bodyBottom
|
|
127
|
+
),
|
|
128
|
+
reserved: roomOn.get(start.page)?.map((room) => {
|
|
129
|
+
const top = measured.contentTop + room.top;
|
|
130
|
+
const height = Math.max(0, bodyBottom - top);
|
|
131
|
+
return {
|
|
132
|
+
band: room.band,
|
|
133
|
+
ids: room.ids,
|
|
134
|
+
top,
|
|
135
|
+
height: Math.min(room.height, height),
|
|
136
|
+
clipped: room.height > height
|
|
137
|
+
};
|
|
138
|
+
}) ?? NO_ROOM
|
|
95
139
|
};
|
|
96
140
|
})
|
|
97
141
|
};
|
|
98
142
|
setOverlay((previous) => sameOverlay(previous, next) ? previous : next);
|
|
99
143
|
},
|
|
100
|
-
() => view?.composing === true
|
|
144
|
+
() => view?.composing === true || composing?.() === true
|
|
101
145
|
);
|
|
102
146
|
useEffect(() => {
|
|
103
147
|
if (enabled) remeasure();
|
|
104
|
-
}, [remeasure, revision, enabled]);
|
|
148
|
+
}, [remeasure, revision, enabled, bands, trailing]);
|
|
105
149
|
useEffect(() => {
|
|
106
150
|
if (enabled) return;
|
|
151
|
+
setOverlay(null);
|
|
107
152
|
layer.current?.style.removeProperty(editorCssVariables.sheetHeight);
|
|
108
153
|
if (!view) return;
|
|
109
154
|
setPageMarks(view, { pushes: [], cuts: [] });
|
package/dist/schema/attrRoles.js
CHANGED
|
@@ -103,8 +103,9 @@ var NODE_ATTR_ROLES = {
|
|
|
103
103
|
id: { role: "source", class: "identity" },
|
|
104
104
|
customMarkFollows: { role: "source", class: "model" },
|
|
105
105
|
referenceXml: { role: "source", class: "preserved" },
|
|
106
|
-
// Worked out from the
|
|
107
|
-
//
|
|
106
|
+
// Worked out again from the reference order and the numbering properties after every edit that
|
|
107
|
+
// moves them (`docx/notes/numbering`), and the writer puts back the reference alone: a note
|
|
108
|
+
// renumbered around an edit is the same reference it was
|
|
108
109
|
label: { role: "display", class: "derived" }
|
|
109
110
|
},
|
|
110
111
|
rawRunContent: {
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
tableStyle
|
|
36
36
|
} from "../styles/inlineStyle.js";
|
|
37
37
|
import { imageNodeSpec, runMarkSpec } from "./rendering.js";
|
|
38
|
+
import { noteName } from "./stories.js";
|
|
38
39
|
import { WRAPPER_ATTRS, WRAPPER_GROUP } from "./wrappers.js";
|
|
39
40
|
import { imageNodeSpec as imageNodeSpec2, runMarkSpec as runMarkSpec2 } from "./rendering.js";
|
|
40
41
|
var NO_STORIES = Object.freeze({});
|
|
@@ -790,7 +791,6 @@ var docxSchema = new Schema({
|
|
|
790
791
|
referenceXml: { default: null }
|
|
791
792
|
},
|
|
792
793
|
toDOM(node) {
|
|
793
|
-
const kind = node.attrs.kind === "endnote" ? "Endnote" : "Footnote";
|
|
794
794
|
const label = text(node.attrs.label) ?? "?";
|
|
795
795
|
return [
|
|
796
796
|
"sup",
|
|
@@ -801,7 +801,10 @@ var docxSchema = new Schema({
|
|
|
801
801
|
"data-note-label": label,
|
|
802
802
|
"data-custom-mark-follows": node.attrs.customMarkFollows === true ? "1" : void 0,
|
|
803
803
|
"data-reference-xml": text(node.attrs.referenceXml),
|
|
804
|
-
"aria-label":
|
|
804
|
+
"aria-label": noteName(
|
|
805
|
+
node.attrs.kind === "endnote" ? "endnote" : "footnote",
|
|
806
|
+
label
|
|
807
|
+
)
|
|
805
808
|
},
|
|
806
809
|
node.attrs.customMarkFollows === true ? "" : label
|
|
807
810
|
];
|
|
@@ -46,7 +46,7 @@ export type EditIntent =
|
|
|
46
46
|
* against the places it puts that guard to the test, and a place naming a guard that no longer
|
|
47
47
|
* stands has to be a mistake the compiler catches rather than an annotation answering for nothing.
|
|
48
48
|
*/
|
|
49
|
-
export type EditGuardName = "protection" | "lock" | "preserved" | "
|
|
49
|
+
export type EditGuardName = "protection" | "lock" | "preserved" | "section";
|
|
50
50
|
/** What every guard answers, whichever of the two judgements it is written as */
|
|
51
51
|
interface GuardCommon {
|
|
52
52
|
readonly name: EditGuardName;
|
package/dist/schema/guards.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
transactionReaches
|
|
5
5
|
} from "./editGuard.js";
|
|
6
6
|
import { lockGuard } from "./locks.js";
|
|
7
|
-
import {
|
|
7
|
+
import { preservedGuard, sectionGuard } from "./preservedGuards.js";
|
|
8
8
|
import {
|
|
9
9
|
isCommentNode,
|
|
10
10
|
protectionAllows
|
|
@@ -37,7 +37,6 @@ var EDIT_GUARDS = [
|
|
|
37
37
|
protectionGuard,
|
|
38
38
|
lockGuard,
|
|
39
39
|
preservedGuard,
|
|
40
|
-
noteGuard,
|
|
41
40
|
sectionGuard
|
|
42
41
|
];
|
|
43
42
|
function judgesSteps(guard) {
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The guards over what a document is opened with and the editor only preserves: the fragments a
|
|
3
|
-
* file falls apart without, the
|
|
4
|
-
* the paragraph that ends a section.
|
|
3
|
+
* file falls apart without, and the paragraph that ends a section.
|
|
5
4
|
*
|
|
6
5
|
* The first of those is the two ends of a bookmark range, the two ends of a permission or move
|
|
7
6
|
* range, and the pieces of a field, which say what they say only in the order they stand in. None
|
|
8
7
|
* of it is content the editor writes, so nothing in it can put such a thing back once it is gone,
|
|
9
8
|
* and a document that lost one of a bookmark's two ends cannot be written back as a file at all
|
|
10
|
-
* (`docx/exportDocx` refuses it). What
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* (`docx/exportDocx` refuses it). What that guard holds is therefore the whole list of the nodes
|
|
10
|
+
* it answers for, in the order the document carries them; a section break, which an edit may
|
|
11
|
+
* legitimately move from one paragraph to another, is held by its number instead.
|
|
13
12
|
*/
|
|
14
13
|
import type { Node as PMNode } from "prosemirror-model";
|
|
15
14
|
import { type ChangeGuard, type EditGuardName } from "./editGuard";
|
|
@@ -30,7 +29,6 @@ type Signature = (node: PMNode) => string;
|
|
|
30
29
|
*/
|
|
31
30
|
export declare function preservedNodeGuard(name: EditGuardName, holds: (node: PMNode) => boolean, signature: Signature): ChangeGuard;
|
|
32
31
|
export declare const preservedGuard: ChangeGuard;
|
|
33
|
-
export declare const noteGuard: ChangeGuard;
|
|
34
32
|
/**
|
|
35
33
|
* A guard that lets a change through only while it leaves at least as many section breaks standing
|
|
36
34
|
* as it found.
|
|
@@ -137,14 +137,6 @@ var preservedGuard = {
|
|
|
137
137
|
return shut;
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
|
-
function isNoteReference(node) {
|
|
141
|
-
return node.type.name === "noteReference";
|
|
142
|
-
}
|
|
143
|
-
var noteGuard = preservedNodeGuard(
|
|
144
|
-
"note",
|
|
145
|
-
isNoteReference,
|
|
146
|
-
(node) => JSON.stringify(node.attrs)
|
|
147
|
-
);
|
|
148
140
|
function endsASection(node) {
|
|
149
141
|
if (node.type.name !== "paragraph") return false;
|
|
150
142
|
const pPr = node.attrs.pPr;
|
|
@@ -174,7 +166,6 @@ var sectionGuard = {
|
|
|
174
166
|
}
|
|
175
167
|
};
|
|
176
168
|
export {
|
|
177
|
-
noteGuard,
|
|
178
169
|
preservedGuard,
|
|
179
170
|
preservedNodeGuard,
|
|
180
171
|
sectionGuard
|
package/dist/schema/stories.d.ts
CHANGED
|
@@ -7,9 +7,23 @@
|
|
|
7
7
|
* the key, the value on the node, and the two comparisons the protection rules are written over.
|
|
8
8
|
*/
|
|
9
9
|
import type { Node as PMNode } from "prosemirror-model";
|
|
10
|
-
|
|
10
|
+
/** Which of the two notes parts a note stands in */
|
|
11
|
+
export declare const NOTE_KINDS: readonly ["footnote", "endnote"];
|
|
12
|
+
export type NoteKind = (typeof NOTE_KINDS)[number];
|
|
13
|
+
/** The two kinds of story a header or footer part holds, one story to a part */
|
|
14
|
+
export declare const HEADER_FOOTER_KINDS: readonly ["header", "footer"];
|
|
15
|
+
export type HeaderFooterKind = (typeof HEADER_FOOTER_KINDS)[number];
|
|
16
|
+
export declare const STORY_KINDS: readonly ["comment", "footnote", "endnote", "header", "footer"];
|
|
17
|
+
export type StoryKind = (typeof STORY_KINDS)[number];
|
|
11
18
|
/** `comment:4`, `footnote:2`, `header:word/header1.xml` */
|
|
12
19
|
export type StoryKey = `${StoryKind}:${string}`;
|
|
20
|
+
/**
|
|
21
|
+
* What a reader listening to the page is told a note reference is.
|
|
22
|
+
*
|
|
23
|
+
* A reference whose own mark follows it in the document draws no label of the editor's
|
|
24
|
+
* (§17.11.14), so it is named by its kind alone rather than by a number that is not there.
|
|
25
|
+
*/
|
|
26
|
+
export declare function noteName(kind: NoteKind, label: string): string;
|
|
13
27
|
/** One story as the document node holds it, which is `Node.toJSON` of a document of this schema */
|
|
14
28
|
export interface StoryJson {
|
|
15
29
|
readonly type: string;
|
|
@@ -18,7 +32,25 @@ export interface StoryJson {
|
|
|
18
32
|
}
|
|
19
33
|
/** The attr the stories stand on, named here so the schema and the readers cannot spell it apart */
|
|
20
34
|
export declare const STORIES_ATTR = "stories";
|
|
21
|
-
export declare function storyKey(kind:
|
|
35
|
+
export declare function storyKey<K extends StoryKind>(kind: K, id: string): `${K}:${string}`;
|
|
36
|
+
/** The key of a story that is a note: `footnote:2`, `endnote:3` */
|
|
37
|
+
export type NoteKey = `${NoteKind}:${string}`;
|
|
38
|
+
/**
|
|
39
|
+
* The note this key names, and null for a key naming a story of another kind.
|
|
40
|
+
*
|
|
41
|
+
* A note's id never carries a colon - a note is identified by a whole number (§17.11.2, §17.11.8)
|
|
42
|
+
* - so the kind is everything up to the first one.
|
|
43
|
+
*/
|
|
44
|
+
export declare function noteKeyOf(key: StoryKey): {
|
|
45
|
+
readonly kind: NoteKind;
|
|
46
|
+
readonly id: string;
|
|
47
|
+
} | null;
|
|
48
|
+
/**
|
|
49
|
+
* The kinds of note an edit may add, delete, copy and rewrite, which is both of them: each part is
|
|
50
|
+
* written back one entry per note (`docx/notes/writing`). The lifecycle, the clipboard and the
|
|
51
|
+
* navigation all read this one list, so a kind of note added to the format joins it once.
|
|
52
|
+
*/
|
|
53
|
+
export declare const EDITABLE_NOTE_KINDS: readonly NoteKind[];
|
|
22
54
|
/**
|
|
23
55
|
* The key this text spells, or null for one that names no kind of story.
|
|
24
56
|
*
|
package/dist/schema/stories.js
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
// src/schema/stories.ts
|
|
2
2
|
import { sameSource } from "./sourceEquality.js";
|
|
3
|
-
var
|
|
3
|
+
var NOTE_KINDS = ["footnote", "endnote"];
|
|
4
|
+
var HEADER_FOOTER_KINDS = ["header", "footer"];
|
|
4
5
|
var STORY_KINDS = [
|
|
5
6
|
"comment",
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"header",
|
|
9
|
-
"footer"
|
|
7
|
+
...NOTE_KINDS,
|
|
8
|
+
...HEADER_FOOTER_KINDS
|
|
10
9
|
];
|
|
10
|
+
function noteName(kind, label) {
|
|
11
|
+
const named = kind === "endnote" ? "Endnote" : "Footnote";
|
|
12
|
+
return label === "" ? named : `${named} ${label}`;
|
|
13
|
+
}
|
|
14
|
+
var STORIES_ATTR = "stories";
|
|
11
15
|
function storyKey(kind, id) {
|
|
12
16
|
return `${kind}:${id}`;
|
|
13
17
|
}
|
|
18
|
+
function noteKeyOf(key) {
|
|
19
|
+
const at = key.indexOf(":");
|
|
20
|
+
const named = key.slice(0, at);
|
|
21
|
+
const kind = NOTE_KINDS.find((candidate) => candidate === named);
|
|
22
|
+
return kind === void 0 ? null : { kind, id: key.slice(at + 1) };
|
|
23
|
+
}
|
|
24
|
+
var EDITABLE_NOTE_KINDS = NOTE_KINDS;
|
|
14
25
|
function asStoryKey(text) {
|
|
15
26
|
const at = text.indexOf(":");
|
|
16
27
|
if (at < 1) return null;
|
|
@@ -68,8 +79,14 @@ function withoutCommentStories(doc) {
|
|
|
68
79
|
);
|
|
69
80
|
}
|
|
70
81
|
export {
|
|
82
|
+
EDITABLE_NOTE_KINDS,
|
|
83
|
+
HEADER_FOOTER_KINDS,
|
|
84
|
+
NOTE_KINDS,
|
|
71
85
|
STORIES_ATTR,
|
|
86
|
+
STORY_KINDS,
|
|
72
87
|
asStoryKey,
|
|
88
|
+
noteKeyOf,
|
|
89
|
+
noteName,
|
|
73
90
|
sameStory,
|
|
74
91
|
storiesOf,
|
|
75
92
|
storyKey,
|
|
@@ -51,7 +51,9 @@ export declare const editorClassNames: {
|
|
|
51
51
|
readonly rawRunContent: "docx-editor-raw-run";
|
|
52
52
|
/** A preserved block, drawn by the `display` its policy gave it */
|
|
53
53
|
readonly rawBlock: "docx-editor-raw-block";
|
|
54
|
-
/** The
|
|
54
|
+
/** The room the scaled page layer takes up in the scroll box */
|
|
55
|
+
readonly pageBox: "docx-editor-page-box";
|
|
56
|
+
/** The box holding both the paper and the marks overlaid on it, scaled to the reader's zoom */
|
|
55
57
|
readonly pageLayer: "docx-editor-page-layer";
|
|
56
58
|
/** All of the page marks drawn over the paper */
|
|
57
59
|
readonly pageGuides: "docx-editor-page-guides";
|
|
@@ -140,17 +142,32 @@ export declare const editorClassNames: {
|
|
|
140
142
|
readonly commentMeta: "docx-editor-comment-meta";
|
|
141
143
|
readonly commentAuthor: "docx-editor-comment-author";
|
|
142
144
|
readonly commentDate: "docx-editor-comment-date";
|
|
145
|
+
/** The note on a card whose comment lost the text it was written for */
|
|
146
|
+
readonly commentDetached: "docx-editor-comment-detached";
|
|
143
147
|
readonly commentBody: "docx-editor-comment-body";
|
|
144
148
|
readonly commentActions: "docx-editor-comment-actions";
|
|
145
149
|
readonly commentPrimaryAction: "docx-editor-comment-primary-action";
|
|
146
150
|
readonly commentIconActions: "docx-editor-comment-icon-actions";
|
|
147
151
|
readonly commentComposer: "docx-editor-comment-composer";
|
|
148
152
|
readonly commentInput: "docx-editor-comment-input";
|
|
149
|
-
|
|
150
|
-
readonly
|
|
151
|
-
|
|
152
|
-
readonly
|
|
153
|
-
|
|
153
|
+
/** Everything drawn over the paper in the room the pages keep for notes, which only its areas take the mouse in */
|
|
154
|
+
readonly noteAreas: "docx-editor-note-areas";
|
|
155
|
+
/** The footnotes at the foot of one page: a short rule, then each footnote */
|
|
156
|
+
readonly footnoteArea: "docx-editor-footnote-area";
|
|
157
|
+
/** The endnotes drawn after the last paragraph, one box per page they run onto */
|
|
158
|
+
readonly endnoteArea: "docx-editor-endnote-area";
|
|
159
|
+
/** The short rule that sets notes apart from the text above them */
|
|
160
|
+
readonly noteSeparator: "docx-editor-note-separator";
|
|
161
|
+
/** One note, drawn from its story */
|
|
162
|
+
readonly noteRow: "docx-editor-note-row";
|
|
163
|
+
/** Attached alongside it while the caret is in that note and an editing view stands over it */
|
|
164
|
+
readonly noteRowOpen: "docx-editor-note-row-open";
|
|
165
|
+
/** The editing view one side story is edited in (`editor/stories`) */
|
|
166
|
+
readonly storyBody: "docx-editor-story-body";
|
|
167
|
+
/** A note's own reference mark, drawn as the label its reference carries */
|
|
168
|
+
readonly noteMark: "docx-editor-note-mark";
|
|
169
|
+
/** The notes listed after the last page */
|
|
170
|
+
readonly noteList: "docx-editor-note-list";
|
|
154
171
|
/** The panel drawn in place of the editor when a document was refused and the consumer wrote no panel of its own */
|
|
155
172
|
readonly rejection: "docx-editor-rejection";
|
|
156
173
|
readonly rejectionTitle: "docx-editor-rejection-title";
|
|
@@ -46,7 +46,9 @@ var editorClassNames = {
|
|
|
46
46
|
rawRunContent: `${PREFIX}-raw-run`,
|
|
47
47
|
/** A preserved block, drawn by the `display` its policy gave it */
|
|
48
48
|
rawBlock: `${PREFIX}-raw-block`,
|
|
49
|
-
/** The
|
|
49
|
+
/** The room the scaled page layer takes up in the scroll box */
|
|
50
|
+
pageBox: `${PREFIX}-page-box`,
|
|
51
|
+
/** The box holding both the paper and the marks overlaid on it, scaled to the reader's zoom */
|
|
50
52
|
pageLayer: `${PREFIX}-page-layer`,
|
|
51
53
|
/** All of the page marks drawn over the paper */
|
|
52
54
|
pageGuides: `${PREFIX}-page-guides`,
|
|
@@ -136,17 +138,32 @@ var editorClassNames = {
|
|
|
136
138
|
commentMeta: `${PREFIX}-comment-meta`,
|
|
137
139
|
commentAuthor: `${PREFIX}-comment-author`,
|
|
138
140
|
commentDate: `${PREFIX}-comment-date`,
|
|
141
|
+
/** The note on a card whose comment lost the text it was written for */
|
|
142
|
+
commentDetached: `${PREFIX}-comment-detached`,
|
|
139
143
|
commentBody: `${PREFIX}-comment-body`,
|
|
140
144
|
commentActions: `${PREFIX}-comment-actions`,
|
|
141
145
|
commentPrimaryAction: `${PREFIX}-comment-primary-action`,
|
|
142
146
|
commentIconActions: `${PREFIX}-comment-icon-actions`,
|
|
143
147
|
commentComposer: `${PREFIX}-comment-composer`,
|
|
144
148
|
commentInput: `${PREFIX}-comment-input`,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
/** Everything drawn over the paper in the room the pages keep for notes, which only its areas take the mouse in */
|
|
150
|
+
noteAreas: `${PREFIX}-note-areas`,
|
|
151
|
+
/** The footnotes at the foot of one page: a short rule, then each footnote */
|
|
152
|
+
footnoteArea: `${PREFIX}-footnote-area`,
|
|
153
|
+
/** The endnotes drawn after the last paragraph, one box per page they run onto */
|
|
154
|
+
endnoteArea: `${PREFIX}-endnote-area`,
|
|
155
|
+
/** The short rule that sets notes apart from the text above them */
|
|
156
|
+
noteSeparator: `${PREFIX}-note-separator`,
|
|
157
|
+
/** One note, drawn from its story */
|
|
158
|
+
noteRow: `${PREFIX}-note-row`,
|
|
159
|
+
/** Attached alongside it while the caret is in that note and an editing view stands over it */
|
|
160
|
+
noteRowOpen: `${PREFIX}-note-row-open`,
|
|
161
|
+
/** The editing view one side story is edited in (`editor/stories`) */
|
|
162
|
+
storyBody: `${PREFIX}-story-body`,
|
|
163
|
+
/** A note's own reference mark, drawn as the label its reference carries */
|
|
164
|
+
noteMark: `${PREFIX}-note-mark`,
|
|
165
|
+
/** The notes listed after the last page */
|
|
166
|
+
noteList: `${PREFIX}-note-list`,
|
|
150
167
|
/** The panel drawn in place of the editor when a document was refused and the consumer wrote no panel of its own */
|
|
151
168
|
rejection: `${PREFIX}-rejection`,
|
|
152
169
|
rejectionTitle: `${PREFIX}-rejection-title`
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CellFormat, type DocumentDefaults, type HighlightName, type LineSpacing, type ParagraphFormat, type RowFormat, type RunFormat, type TableFormat, type TableWidth } from "../model/format";
|
|
2
|
+
import { editorCssVariables } from "./classNames";
|
|
2
3
|
import { type FontFallbacks } from "./fontStack";
|
|
3
4
|
/**
|
|
4
5
|
* The value used on screen only, when nowhere in the document declares a default
|
|
@@ -65,3 +66,9 @@ export declare function cellStyle(format: CellFormat | null): string | undefined
|
|
|
65
66
|
* not drawn in a different font in every environment.
|
|
66
67
|
*/
|
|
67
68
|
export declare function documentDefaultsStyle(defaults: DocumentDefaults, fontFallbacks?: FontFallbacks): string;
|
|
69
|
+
export type DocumentDefaultsVariables = Readonly<Record<typeof editorCssVariables.fontSize | typeof editorCssVariables.lineHeight | typeof editorCssVariables.fontFamily, string>>;
|
|
70
|
+
/**
|
|
71
|
+
* The same values as the variables they are written into, for a box drawn outside the sheet that
|
|
72
|
+
* is to set its text the way the sheet does: a note drawn at the foot of a page, or after the last
|
|
73
|
+
*/
|
|
74
|
+
export declare function documentDefaultsVariables(defaults: DocumentDefaults, fontFallbacks?: FontFallbacks): DocumentDefaultsVariables;
|
|
@@ -199,12 +199,17 @@ function cellStyle(format) {
|
|
|
199
199
|
return declarations(css);
|
|
200
200
|
}
|
|
201
201
|
function documentDefaultsStyle(defaults, fontFallbacks = DEFAULT_FONT_FALLBACKS) {
|
|
202
|
+
return Object.entries(documentDefaultsVariables(defaults, fontFallbacks)).map(([name, value]) => `${name}:${value}`).join(";");
|
|
203
|
+
}
|
|
204
|
+
function documentDefaultsVariables(defaults, fontFallbacks = DEFAULT_FONT_FALLBACKS) {
|
|
202
205
|
const fontFamily = defaults.fontFamily ? withFontFallback(defaults.fontFamily, fontFallbacks) : fontFallbacks.defaultStack;
|
|
203
|
-
return
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
return {
|
|
207
|
+
[editorCssVariables.fontSize]: pt(
|
|
208
|
+
defaults.fontSizePt ?? FALLBACK_FONT_SIZE_PT
|
|
209
|
+
),
|
|
210
|
+
[editorCssVariables.lineHeight]: lineHeightValue(defaults.lineSpacing),
|
|
211
|
+
[editorCssVariables.fontFamily]: fontFamily
|
|
212
|
+
};
|
|
208
213
|
}
|
|
209
214
|
export {
|
|
210
215
|
FALLBACK_FONT_SIZE_PT,
|
|
@@ -213,6 +218,7 @@ export {
|
|
|
213
218
|
cellStyle,
|
|
214
219
|
columnWidthPx,
|
|
215
220
|
documentDefaultsStyle,
|
|
221
|
+
documentDefaultsVariables,
|
|
216
222
|
lineHeightValue,
|
|
217
223
|
paragraphStyle,
|
|
218
224
|
rowStyle,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The scale an element is drawn at, read back off the transforms standing over it.
|
|
3
|
+
*
|
|
4
|
+
* The page layer is scaled with a transform rather than the `zoom` property (`./editor.css`), so
|
|
5
|
+
* the scale has to be read out of whatever the transform resolves to: a browser hands back the used
|
|
6
|
+
* matrix, while a document implementation that does not compute one hands the function back as it
|
|
7
|
+
* was written. Everything that turns a rectangle read off the screen into a measurement on the
|
|
8
|
+
* paper divides by this number, so a transform an application puts above the editor - a dialog
|
|
9
|
+
* opening on a scale, a container fitting itself to a small screen - counts as much as the layer's
|
|
10
|
+
* own: a rectangle read inside one of those is drawn at their product.
|
|
11
|
+
*
|
|
12
|
+
* The drawn width over `offsetWidth` would answer without parsing anything, but `offsetWidth` is
|
|
13
|
+
* rounded to whole pixels, and a scale a ten-thousandth out is a measurement half a pixel out by
|
|
14
|
+
* the foot of a long document, which is the drift this scaling exists to avoid.
|
|
15
|
+
*/
|
|
16
|
+
/** The horizontal scale of an element's own transform and of every transform above it */
|
|
17
|
+
export declare function visualScaleOf(element: Element | null | undefined): number;
|
|
18
|
+
/** The scale the paper a node is drawn on is being read at */
|
|
19
|
+
export declare function pageScaleAround(node: Element): number;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/styles/visualScale.ts
|
|
2
|
+
import { editorClassNames } from "./classNames.js";
|
|
3
|
+
var HORIZONTAL_SCALE = /^(?:matrix3d|matrix|scale3d|scaleX|scale)\(\s*(-?\d*\.?\d+(?:e[+-]?\d+)?)/i;
|
|
4
|
+
function styleOf(element) {
|
|
5
|
+
const view = element.ownerDocument.defaultView;
|
|
6
|
+
return view ? view.getComputedStyle(element) : null;
|
|
7
|
+
}
|
|
8
|
+
function ownScale(element) {
|
|
9
|
+
const matched = HORIZONTAL_SCALE.exec(styleOf(element)?.transform ?? "");
|
|
10
|
+
const scale = Number.parseFloat(matched?.[1] ?? "");
|
|
11
|
+
return Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
12
|
+
}
|
|
13
|
+
function visualScaleOf(element) {
|
|
14
|
+
let scale = 1;
|
|
15
|
+
for (let at = element ?? null; at !== null; at = at.parentElement) {
|
|
16
|
+
scale *= ownScale(at);
|
|
17
|
+
}
|
|
18
|
+
return scale;
|
|
19
|
+
}
|
|
20
|
+
function pageScaleAround(node) {
|
|
21
|
+
return visualScaleOf(node.closest(`.${editorClassNames.pageLayer}`));
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
pageScaleAround,
|
|
25
|
+
visualScaleOf
|
|
26
|
+
};
|