@portone/docx-editor 0.4.0 → 0.5.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 +201 -0
- package/CONTRIBUTING.md +2 -0
- package/assets/editor.png +0 -0
- package/dist/DocxEditor.d.ts +1 -1
- package/dist/DocxEditor.js +44 -25
- package/dist/docx/cloning.js +4 -9
- package/dist/docx/commentOnlyChange.d.ts +5 -3
- package/dist/docx/comments/grammar.d.ts +27 -10
- package/dist/docx/comments/grammar.js +18 -67
- package/dist/docx/comments/model.d.ts +5 -6
- package/dist/docx/comments/model.js +0 -9
- package/dist/docx/comments/parts.d.ts +16 -10
- package/dist/docx/comments/parts.js +65 -13
- package/dist/docx/comments/people.d.ts +11 -3
- package/dist/docx/comments/people.js +20 -6
- package/dist/docx/comments/policy.js +7 -1
- package/dist/docx/comments/reading.d.ts +4 -2
- package/dist/docx/comments/reading.js +1 -14
- package/dist/docx/comments/writing.js +65 -28
- package/dist/docx/exportDocx.js +10 -14
- package/dist/docx/exportRefs.d.ts +8 -3
- package/dist/docx/exportRefs.js +2 -1
- package/dist/docx/fidelity.js +24 -10
- package/dist/docx/fields.d.ts +42 -0
- package/dist/docx/fields.js +76 -0
- package/dist/docx/formatting/styles.d.ts +0 -2
- package/dist/docx/formatting/styles.js +2 -15
- package/dist/docx/headersFooters.d.ts +89 -20
- package/dist/docx/headersFooters.js +163 -172
- package/dist/docx/identities.js +17 -26
- package/dist/docx/importDocx.d.ts +1 -1
- package/dist/docx/importDocx.js +100 -48
- package/dist/docx/importParagraph.d.ts +18 -5
- package/dist/docx/importParagraph.js +75 -128
- package/dist/docx/importPolicy.d.ts +70 -0
- package/dist/docx/importPolicy.js +195 -0
- package/dist/docx/importPreserved.d.ts +30 -0
- package/dist/docx/importPreserved.js +54 -0
- package/dist/docx/importTable.js +56 -12
- package/dist/docx/invariants.js +16 -18
- package/dist/docx/notes.d.ts +6 -1
- package/dist/docx/notes.js +6 -16
- package/dist/docx/pageGeometry.d.ts +5 -14
- package/dist/docx/pageGeometry.js +0 -12
- package/dist/docx/protectionPolicy.d.ts +13 -5
- package/dist/docx/protectionPolicy.js +32 -22
- package/dist/docx/scan.d.ts +18 -8
- package/dist/docx/scan.js +17 -11
- package/dist/docx/sections.d.ts +126 -0
- package/dist/docx/sections.js +207 -0
- package/dist/docx/serializeBlock.d.ts +13 -4
- package/dist/docx/serializeBlock.js +16 -18
- package/dist/docx/serializeParagraph.d.ts +9 -4
- package/dist/docx/serializeParagraph.js +23 -58
- package/dist/docx/serializePreserved.d.ts +14 -0
- package/dist/docx/serializePreserved.js +24 -0
- package/dist/docx/serializeStory.d.ts +17 -0
- package/dist/docx/serializeStory.js +17 -0
- package/dist/docx/serializeTable.js +10 -13
- package/dist/docx/session.d.ts +23 -6
- package/dist/docx/session.js +26 -5
- package/dist/docx/story.d.ts +140 -0
- package/dist/docx/story.js +237 -0
- package/dist/docx/storyProjection.js +6 -1
- package/dist/docx/tableTemplate.d.ts +25 -0
- package/dist/docx/tableTemplate.js +30 -16
- package/dist/docx/wrappers.d.ts +67 -0
- package/dist/docx/wrappers.js +117 -0
- package/dist/editor/clipboard/blockReaders.d.ts +74 -0
- package/dist/editor/clipboard/blockReaders.js +193 -0
- package/dist/editor/clipboard/htmlReader.d.ts +26 -0
- package/dist/editor/clipboard/htmlReader.js +376 -0
- package/dist/editor/clipboard/inlineFormatting.d.ts +0 -7
- package/dist/editor/clipboard/inlineFormatting.js +1 -7
- package/dist/editor/clipboard/internalChannel.d.ts +57 -0
- package/dist/editor/clipboard/internalChannel.js +58 -0
- package/dist/editor/clipboard/normalizers.d.ts +99 -0
- package/dist/editor/clipboard/normalizers.js +199 -0
- package/dist/editor/clipboard/parser.d.ts +34 -0
- package/dist/editor/clipboard/parser.js +58 -0
- package/dist/editor/clipboard/plugin.d.ts +21 -0
- package/dist/editor/clipboard/plugin.js +188 -0
- package/dist/editor/clipboard/readContext.d.ts +34 -0
- package/dist/editor/clipboard/readContext.js +25 -0
- package/dist/editor/clipboard/readers.d.ts +33 -0
- package/dist/editor/clipboard/readers.js +37 -0
- package/dist/editor/clipboard/source.d.ts +12 -0
- package/dist/editor/clipboard/source.js +21 -0
- package/dist/editor/commands/comments/editing.d.ts +26 -6
- package/dist/editor/commands/comments/editing.js +177 -106
- package/dist/editor/commands/comments/model.d.ts +34 -17
- package/dist/editor/commands/comments/model.js +11 -0
- package/dist/editor/commands/comments/reading.d.ts +5 -3
- package/dist/editor/commands/comments/reading.js +8 -58
- package/dist/editor/commands/index.d.ts +2 -2
- package/dist/editor/commands/index.js +2 -0
- package/dist/editor/commands/linkCommands.js +20 -5
- package/dist/editor/commands/listCommands.d.ts +6 -0
- package/dist/editor/commands/listCommands.js +3 -2
- package/dist/editor/commands/lockCommands.js +59 -16
- package/dist/editor/commands/noteQueries.d.ts +22 -5
- package/dist/editor/commands/noteQueries.js +34 -6
- package/dist/editor/commands/paragraphCommands.js +2 -2
- package/dist/editor/createEditor.js +13 -3
- package/dist/editor/documentStyles.d.ts +26 -4
- package/dist/editor/documentStyles.js +9 -4
- package/dist/editor/imageFiles.d.ts +2 -2
- package/dist/editor/imageFiles.js +2 -0
- package/dist/editor/insertTable.d.ts +1 -1
- package/dist/editor/insertTable.js +2 -2
- package/dist/editor/plainText.d.ts +12 -0
- package/dist/editor/plainText.js +2 -1
- package/dist/editor/plugins/columnResize.js +6 -3
- package/dist/editor/plugins/commentComposer.d.ts +28 -0
- package/dist/editor/plugins/commentComposer.js +46 -0
- package/dist/editor/plugins/commentDecorations.d.ts +29 -2
- package/dist/editor/plugins/commentDecorations.js +89 -15
- package/dist/editor/plugins/documentProjection.d.ts +31 -0
- package/dist/editor/plugins/documentProjection.js +22 -0
- package/dist/editor/plugins/imagePaste.js +15 -8
- package/dist/editor/plugins/linkPanel.d.ts +7 -3
- package/dist/editor/plugins/linkPanel.js +13 -27
- package/dist/editor/plugins/panelState.d.ts +67 -0
- package/dist/editor/plugins/panelState.js +54 -0
- package/dist/editor/plugins/tableContextMenu.d.ts +1 -1
- package/dist/editor/plugins/tableContextMenu.js +30 -47
- package/dist/editor/plugins/textContextMenu.d.ts +1 -1
- package/dist/editor/plugins/textContextMenu.js +30 -47
- package/dist/ooxml/fragment.d.ts +11 -0
- package/dist/ooxml/fragment.js +14 -4
- package/dist/ooxml/image.d.ts +3 -4
- package/dist/ooxml/image.js +50 -5
- package/dist/ooxml/names.d.ts +6 -0
- package/dist/ooxml/names.js +2 -0
- package/dist/ooxml/props.d.ts +10 -0
- package/dist/ooxml/props.js +28 -4
- package/dist/ooxml/rangeMarkers.d.ts +5 -0
- package/dist/ooxml/rangeMarkers.js +24 -0
- package/dist/page/PageGuides.d.ts +7 -3
- package/dist/page/PageGuides.js +13 -24
- package/dist/page/pageLayout.d.ts +64 -5
- package/dist/page/pageLayout.js +90 -29
- package/dist/page/usePageLayout.d.ts +14 -4
- package/dist/page/usePageLayout.js +19 -20
- package/dist/schema/attrRoles.js +46 -23
- package/dist/schema/clipboard.d.ts +72 -0
- package/dist/schema/clipboard.js +288 -0
- package/dist/schema/docxSchema.d.ts +9 -1
- package/dist/schema/docxSchema.js +217 -165
- package/dist/schema/editGuard.d.ts +1 -1
- package/dist/schema/guards.js +2 -2
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/locks.d.ts +3 -0
- package/dist/schema/locks.js +29 -12
- package/dist/schema/preservedFragments.d.ts +12 -0
- package/dist/schema/preservedFragments.js +38 -0
- package/dist/schema/preservedGuards.d.ts +9 -7
- package/dist/schema/preservedGuards.js +112 -11
- package/dist/schema/protection.d.ts +34 -5
- package/dist/schema/protection.js +42 -14
- package/dist/schema/rendering.d.ts +14 -0
- package/dist/schema/rendering.js +27 -12
- package/dist/schema/stories.d.ts +49 -0
- package/dist/schema/stories.js +78 -0
- package/dist/schema/wrappers.d.ts +58 -0
- package/dist/schema/wrappers.js +77 -0
- package/dist/styles/classNames.d.ts +3 -5
- package/dist/styles/classNames.js +3 -5
- package/dist/styles.css +74 -12
- package/dist/table/resize.d.ts +5 -3
- package/dist/ui/CommentsPanel.d.ts +1 -3
- package/dist/ui/CommentsPanel.js +24 -15
- package/dist/ui/NotesPanel.js +2 -2
- package/dist/ui/TextMenu.d.ts +1 -3
- package/dist/ui/TextMenu.js +10 -6
- package/dist/ui/comments/CommentComposer.d.ts +6 -1
- package/dist/ui/comments/CommentComposer.js +26 -3
- package/package.json +5 -4
- package/dist/editor/externalClipboard.d.ts +0 -22
- package/dist/editor/externalClipboard.js +0 -486
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// src/schema/stories.ts
|
|
2
|
+
import { sameSource } from "./sourceEquality.js";
|
|
3
|
+
var STORIES_ATTR = "stories";
|
|
4
|
+
var STORY_KINDS = [
|
|
5
|
+
"comment",
|
|
6
|
+
"footnote",
|
|
7
|
+
"endnote",
|
|
8
|
+
"header",
|
|
9
|
+
"footer"
|
|
10
|
+
];
|
|
11
|
+
function storyKey(kind, id) {
|
|
12
|
+
return `${kind}:${id}`;
|
|
13
|
+
}
|
|
14
|
+
function asStoryKey(text) {
|
|
15
|
+
const at = text.indexOf(":");
|
|
16
|
+
if (at < 1) return null;
|
|
17
|
+
const named = text.slice(0, at);
|
|
18
|
+
const kind = STORY_KINDS.find((candidate) => candidate === named);
|
|
19
|
+
return kind === void 0 ? null : storyKey(kind, text.slice(at + 1));
|
|
20
|
+
}
|
|
21
|
+
function isStoryJson(value) {
|
|
22
|
+
return typeof value === "object" && value !== null && typeof Reflect.get(value, "type") === "string";
|
|
23
|
+
}
|
|
24
|
+
function storiesOf(doc) {
|
|
25
|
+
const held = doc.attrs[STORIES_ATTR];
|
|
26
|
+
if (typeof held !== "object" || held === null) return {};
|
|
27
|
+
const stories = {};
|
|
28
|
+
for (const [key, value] of Object.entries(held)) {
|
|
29
|
+
if (asStoryKey(key) !== null && isStoryJson(value)) stories[key] = value;
|
|
30
|
+
}
|
|
31
|
+
return stories;
|
|
32
|
+
}
|
|
33
|
+
var built = /* @__PURE__ */ new WeakMap();
|
|
34
|
+
function storyNodeOf(doc, key) {
|
|
35
|
+
const json = storiesOf(doc)[key];
|
|
36
|
+
if (json === void 0) return null;
|
|
37
|
+
const cached = built.get(json);
|
|
38
|
+
if (cached) return cached;
|
|
39
|
+
const node = doc.type.schema.nodeFromJSON(json);
|
|
40
|
+
built.set(json, node);
|
|
41
|
+
return node;
|
|
42
|
+
}
|
|
43
|
+
var unkeyed = /* @__PURE__ */ new WeakMap();
|
|
44
|
+
function withoutBlockKeys(node) {
|
|
45
|
+
if (node.isText) return node;
|
|
46
|
+
const cached = unkeyed.get(node);
|
|
47
|
+
if (cached) return cached;
|
|
48
|
+
const children = node.children.map(withoutBlockKeys);
|
|
49
|
+
const attrs = node.attrs.srcId === null || node.attrs.srcId === void 0 ? node.attrs : { ...node.attrs, srcId: null };
|
|
50
|
+
const stripped = attrs === node.attrs && children.every((child, at) => child === node.child(at)) ? node : node.type.create(attrs, children, node.marks);
|
|
51
|
+
unkeyed.set(node, stripped);
|
|
52
|
+
return stripped;
|
|
53
|
+
}
|
|
54
|
+
function sameStory(a, b) {
|
|
55
|
+
if (a === null || b === null) return a === b;
|
|
56
|
+
return sameSource(withoutBlockKeys(a), withoutBlockKeys(b));
|
|
57
|
+
}
|
|
58
|
+
function withoutCommentStories(doc) {
|
|
59
|
+
const stories = storiesOf(doc);
|
|
60
|
+
const kept = Object.fromEntries(
|
|
61
|
+
Object.entries(stories).filter(([key]) => !key.startsWith("comment:"))
|
|
62
|
+
);
|
|
63
|
+
if (Object.keys(kept).length === Object.keys(stories).length) return doc;
|
|
64
|
+
return doc.type.create(
|
|
65
|
+
{ ...doc.attrs, [STORIES_ATTR]: kept },
|
|
66
|
+
doc.content,
|
|
67
|
+
doc.marks
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
STORIES_ATTR,
|
|
72
|
+
asStoryKey,
|
|
73
|
+
sameStory,
|
|
74
|
+
storiesOf,
|
|
75
|
+
storyKey,
|
|
76
|
+
storyNodeOf,
|
|
77
|
+
withoutCommentStories
|
|
78
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The inline wrappers a stretch of content stands inside, as the schema records them.
|
|
3
|
+
*
|
|
4
|
+
* A wrapper is an element that holds inline content and goes back out around the same content:
|
|
5
|
+
* a content control (`w:sdt`), a hyperlink (`w:hyperlink`). Each is a mark of its own, so each
|
|
6
|
+
* keeps the `inclusive` rule and the attrs its kind needs, and all of them share the `wrapper`
|
|
7
|
+
* group, so a node's `marks:` whitelist names the group rather than every kind in it and a new
|
|
8
|
+
* kind arrives as one mark spec.
|
|
9
|
+
*
|
|
10
|
+
* The nesting is recorded on the marks themselves: `depth` counts from the outermost wrapper the
|
|
11
|
+
* file wrote inwards. The order of a mark set cannot carry it - `Mark.addToSet` keeps insertion
|
|
12
|
+
* order only among marks of different types, `parseDOM` rebuilds a set from the page, and two
|
|
13
|
+
* wrappers of one kind may stand one inside the other - so `depth` is the source of truth and
|
|
14
|
+
* `wrapperMarks` is the one place that reads the order off it.
|
|
15
|
+
*
|
|
16
|
+
* What each kind reads out of the file and writes back into it is `docx/wrappers`.
|
|
17
|
+
*/
|
|
18
|
+
import type { Mark, MarkType, Node as PMNode } from "prosemirror-model";
|
|
19
|
+
/** The mark group every inline wrapper belongs to */
|
|
20
|
+
export declare const WRAPPER_GROUP = "wrapper";
|
|
21
|
+
/** What every wrapper mark spec carries besides the attrs of its own kind */
|
|
22
|
+
export declare const WRAPPER_ATTRS: {
|
|
23
|
+
/** Outer-to-inner order as read from the file; equal depths fall back to declaration rank */
|
|
24
|
+
readonly depth: {
|
|
25
|
+
readonly default: 0;
|
|
26
|
+
};
|
|
27
|
+
/** Which occurrence this is in the opened document, so two wrappers written alike stay apart */
|
|
28
|
+
readonly key: {
|
|
29
|
+
readonly default: 0;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/** Whether marks of this type wrap the content they cover (`WRAPPER_GROUP`) */
|
|
33
|
+
export declare function isWrapperType(type: MarkType): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* The wrappers this node stands inside, outermost first.
|
|
36
|
+
*
|
|
37
|
+
* Two wrappers written at the same depth - a control laid over a link during editing, say - fall
|
|
38
|
+
* back to the order the schema declares them in, which is the nesting the marks meant before
|
|
39
|
+
* `depth` existed.
|
|
40
|
+
*/
|
|
41
|
+
export declare function wrapperMarks(node: PMNode): readonly Mark[];
|
|
42
|
+
/** Every wrapper of this kind the node stands inside, outermost first */
|
|
43
|
+
export declare function wrappersOf(node: PMNode, kind: MarkType): readonly Mark[];
|
|
44
|
+
/** The outermost wrapper of this kind the node stands inside. null where it stands in none */
|
|
45
|
+
export declare function wrapperOf(node: PMNode, kind: MarkType): Mark | null;
|
|
46
|
+
/**
|
|
47
|
+
* The depth of the innermost of these wrappers, and -1 where there is none, so that
|
|
48
|
+
* `innermostDepth(marks) + 1` is the depth a wrapper laid inside every one of them takes.
|
|
49
|
+
*/
|
|
50
|
+
export declare function innermostDepth(marks: readonly Mark[]): number;
|
|
51
|
+
/**
|
|
52
|
+
* The wrappers all of these nodes stand inside alike, outermost first: the longest run of
|
|
53
|
+
* wrappers, from the outside in, that every one of them wears the very same one of.
|
|
54
|
+
*
|
|
55
|
+
* A wrapper laid across the whole stretch goes inside these and outside everything else, which is
|
|
56
|
+
* what keeps it one element in the file rather than one per stretch the nesting differs over.
|
|
57
|
+
*/
|
|
58
|
+
export declare function sharedWrappers(nodes: readonly PMNode[]): readonly Mark[];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// src/schema/wrappers.ts
|
|
2
|
+
var WRAPPER_GROUP = "wrapper";
|
|
3
|
+
var WRAPPER_ATTRS = {
|
|
4
|
+
/** Outer-to-inner order as read from the file; equal depths fall back to declaration rank */
|
|
5
|
+
depth: { default: 0 },
|
|
6
|
+
/** Which occurrence this is in the opened document, so two wrappers written alike stay apart */
|
|
7
|
+
key: { default: 0 }
|
|
8
|
+
};
|
|
9
|
+
var FACTS = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
var NO_WRAPPERS = [];
|
|
11
|
+
function factsOf(type) {
|
|
12
|
+
const known = FACTS.get(type);
|
|
13
|
+
if (known) return known;
|
|
14
|
+
const facts = {
|
|
15
|
+
wrapper: (type.spec.group ?? "").split(" ").includes(WRAPPER_GROUP),
|
|
16
|
+
rank: Object.keys(type.schema.marks).indexOf(type.name)
|
|
17
|
+
};
|
|
18
|
+
FACTS.set(type, facts);
|
|
19
|
+
return facts;
|
|
20
|
+
}
|
|
21
|
+
function isWrapperType(type) {
|
|
22
|
+
return factsOf(type).wrapper;
|
|
23
|
+
}
|
|
24
|
+
function depthOf(mark) {
|
|
25
|
+
const depth = mark.attrs.depth;
|
|
26
|
+
return typeof depth === "number" ? depth : 0;
|
|
27
|
+
}
|
|
28
|
+
function wrapperMarks(node) {
|
|
29
|
+
const marks = node.marks;
|
|
30
|
+
let found = 0;
|
|
31
|
+
for (const mark of marks) {
|
|
32
|
+
if (factsOf(mark.type).wrapper) found += 1;
|
|
33
|
+
}
|
|
34
|
+
if (found === 0) return NO_WRAPPERS;
|
|
35
|
+
const wrappers = found === marks.length ? [...marks] : marks.filter((mark) => factsOf(mark.type).wrapper);
|
|
36
|
+
if (found < 2) return wrappers;
|
|
37
|
+
return wrappers.sort(
|
|
38
|
+
(a, b) => depthOf(a) - depthOf(b) || factsOf(a.type).rank - factsOf(b.type).rank
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
function wrappersOf(node, kind) {
|
|
42
|
+
return wrapperMarks(node).filter((mark) => mark.type === kind);
|
|
43
|
+
}
|
|
44
|
+
function wrapperOf(node, kind) {
|
|
45
|
+
return wrapperMarks(node).find((mark) => mark.type === kind) ?? null;
|
|
46
|
+
}
|
|
47
|
+
function innermostDepth(marks) {
|
|
48
|
+
return marks.reduce(
|
|
49
|
+
(deepest, mark) => factsOf(mark.type).wrapper ? Math.max(deepest, depthOf(mark)) : deepest,
|
|
50
|
+
-1
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function sharedWrappers(nodes) {
|
|
54
|
+
const first = nodes.at(0);
|
|
55
|
+
if (first === void 0) return [];
|
|
56
|
+
let shared = wrapperMarks(first);
|
|
57
|
+
for (const node of nodes.slice(1)) {
|
|
58
|
+
const marks = wrapperMarks(node);
|
|
59
|
+
const differs = shared.findIndex((mark, index) => {
|
|
60
|
+
const beside = marks[index];
|
|
61
|
+
return beside === void 0 || !mark.eq(beside);
|
|
62
|
+
});
|
|
63
|
+
if (differs !== -1) shared = shared.slice(0, differs);
|
|
64
|
+
if (shared.length === 0) break;
|
|
65
|
+
}
|
|
66
|
+
return shared;
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
WRAPPER_ATTRS,
|
|
70
|
+
WRAPPER_GROUP,
|
|
71
|
+
innermostDepth,
|
|
72
|
+
isWrapperType,
|
|
73
|
+
sharedWrappers,
|
|
74
|
+
wrapperMarks,
|
|
75
|
+
wrapperOf,
|
|
76
|
+
wrappersOf
|
|
77
|
+
};
|
|
@@ -46,13 +46,11 @@ export declare const editorClassNames: {
|
|
|
46
46
|
readonly commentMarker: "docx-editor-comment-marker";
|
|
47
47
|
/** A superscript footnote or endnote reference */
|
|
48
48
|
readonly noteReference: "docx-editor-note-reference";
|
|
49
|
-
/** An invisible bookmark marker that occurs between body blocks */
|
|
50
|
-
readonly bookmarkBlock: "docx-editor-bookmark-block";
|
|
51
49
|
readonly rawInline: "docx-editor-raw-inline";
|
|
50
|
+
/** A preserved child of a run, drawn by the `display` its policy gave it */
|
|
51
|
+
readonly rawRunContent: "docx-editor-raw-run";
|
|
52
|
+
/** A preserved block, drawn by the `display` its policy gave it */
|
|
52
53
|
readonly rawBlock: "docx-editor-raw-block";
|
|
53
|
-
/** A preserved block that carries the original XML directly (inside a table cell, and so on) */
|
|
54
|
-
readonly rawXmlBlock: "docx-editor-raw-xml";
|
|
55
|
-
readonly tablePlaceholder: "docx-editor-table";
|
|
56
54
|
/** The box holding both the paper and the marks overlaid on it */
|
|
57
55
|
readonly pageLayer: "docx-editor-page-layer";
|
|
58
56
|
/** All of the page marks drawn over the paper */
|
|
@@ -41,13 +41,11 @@ var editorClassNames = {
|
|
|
41
41
|
commentMarker: `${PREFIX}-comment-marker`,
|
|
42
42
|
/** A superscript footnote or endnote reference */
|
|
43
43
|
noteReference: `${PREFIX}-note-reference`,
|
|
44
|
-
/** An invisible bookmark marker that occurs between body blocks */
|
|
45
|
-
bookmarkBlock: `${PREFIX}-bookmark-block`,
|
|
46
44
|
rawInline: `${PREFIX}-raw-inline`,
|
|
45
|
+
/** A preserved child of a run, drawn by the `display` its policy gave it */
|
|
46
|
+
rawRunContent: `${PREFIX}-raw-run`,
|
|
47
|
+
/** A preserved block, drawn by the `display` its policy gave it */
|
|
47
48
|
rawBlock: `${PREFIX}-raw-block`,
|
|
48
|
-
/** A preserved block that carries the original XML directly (inside a table cell, and so on) */
|
|
49
|
-
rawXmlBlock: `${PREFIX}-raw-xml`,
|
|
50
|
-
tablePlaceholder: `${PREFIX}-table`,
|
|
51
49
|
/** The box holding both the paper and the marks overlaid on it */
|
|
52
50
|
pageLayer: `${PREFIX}-page-layer`,
|
|
53
51
|
/** All of the page marks drawn over the paper */
|
package/dist/styles.css
CHANGED
|
@@ -62,11 +62,6 @@
|
|
|
62
62
|
overflow: hidden;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
/* A body-level bookmark occupies a document-model position but draws no placeholder. */
|
|
66
|
-
.docx-editor-bookmark-block {
|
|
67
|
-
display: none;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
65
|
.docx-editor-comment-range {
|
|
71
66
|
background: #fff2a8;
|
|
72
67
|
box-shadow: inset 0 -2px #e2b714;
|
|
@@ -588,10 +583,12 @@ button.docx-editor-comment-body {
|
|
|
588
583
|
* is the same paper `A4_PORTRAIT` names in `docx/pageGeometry.ts`.
|
|
589
584
|
*
|
|
590
585
|
* The height is used only as a minimum, so that even short text feels like a full
|
|
591
|
-
* sheet and longer text simply grows it
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
586
|
+
* sheet and longer text simply grows it, and the editor supplies one grown to the
|
|
587
|
+
* last page's own bottom margin where a later section's is deeper than this one's.
|
|
588
|
+
* The body left inside these margins is what the sheet itself is drawn at. The width
|
|
589
|
+
* of a new table and the height between two page boundaries come from the paper of
|
|
590
|
+
* the section they stand in, which `page/pageLayout.ts` works out from the very same
|
|
591
|
+
* kind of geometry, so the divider on screen lands where that page actually ends.
|
|
595
592
|
*/
|
|
596
593
|
--docx-editor-page-width: 21cm;
|
|
597
594
|
--docx-editor-page-height: 29.7cm;
|
|
@@ -677,7 +674,10 @@ button.docx-editor-comment-body {
|
|
|
677
674
|
border-top: 1px dotted rgb(26 79 208 / 40%);
|
|
678
675
|
}
|
|
679
676
|
|
|
680
|
-
/*
|
|
677
|
+
/*
|
|
678
|
+
* Display-only projections of the header and footer stories of the section each page
|
|
679
|
+
* belongs to (`page/PageGuides.tsx`).
|
|
680
|
+
*/
|
|
681
681
|
.docx-editor-page-header,
|
|
682
682
|
.docx-editor-page-footer {
|
|
683
683
|
position: absolute;
|
|
@@ -928,12 +928,21 @@ button.docx-editor-comment-body {
|
|
|
928
928
|
* held as data rather than as an `href`, so a click here places the caret the way a click on any
|
|
929
929
|
* other text does, and opening the address is the link panel's business.
|
|
930
930
|
* A color the run itself carries paints over this one, the same as any other run formatting.
|
|
931
|
+
* The line is a border rather than an underline so that it runs on across a tab, which a text
|
|
932
|
+
* decoration is not painted over.
|
|
931
933
|
*/
|
|
932
934
|
.docx-editor-link {
|
|
933
935
|
color: #1a56db;
|
|
934
936
|
border-bottom: 1px solid currentcolor;
|
|
935
937
|
}
|
|
936
938
|
|
|
939
|
+
/* A word processor underlines a link through the `Hyperlink` style, so the line above would be a second one */
|
|
940
|
+
.docx-editor-link:has([data-underline]):not(
|
|
941
|
+
:has(.docx-editor-run:not([data-underline]))
|
|
942
|
+
) {
|
|
943
|
+
border-bottom: none;
|
|
944
|
+
}
|
|
945
|
+
|
|
937
946
|
/*
|
|
938
947
|
* A content control that says its contents may not be edited (`editor/plugins/lockedContent` refuses
|
|
939
948
|
* the edits). Yellow is what the contract templates already paint their settled parts with.
|
|
@@ -957,15 +966,63 @@ button.docx-editor-comment-body {
|
|
|
957
966
|
cursor: not-allowed;
|
|
958
967
|
}
|
|
959
968
|
|
|
969
|
+
/*
|
|
970
|
+
* A preserved fragment inside a paragraph or inside a run. What it draws is the `display` the
|
|
971
|
+
* preservation rule gave it (`docx/importPolicy`), so the rule is read here as an attribute
|
|
972
|
+
* rather than as a second list of element names.
|
|
973
|
+
*/
|
|
974
|
+
.docx-editor-raw-inline,
|
|
975
|
+
.docx-editor-raw-run {
|
|
976
|
+
vertical-align: baseline;
|
|
977
|
+
}
|
|
978
|
+
|
|
960
979
|
/* Elements that, like bookmarks, must not be visible */
|
|
961
|
-
.docx-editor-raw-inline
|
|
980
|
+
.docx-editor-raw-inline[data-display="hidden"],
|
|
981
|
+
.docx-editor-raw-run[data-display="hidden"] {
|
|
962
982
|
display: inline-block;
|
|
963
983
|
width: 0;
|
|
964
984
|
overflow: hidden;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/* A character the file stands for and the editor cannot type, drawn as itself */
|
|
988
|
+
.docx-editor-raw-inline[data-display="text"],
|
|
989
|
+
.docx-editor-raw-run[data-display="text"] {
|
|
990
|
+
white-space: pre;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/*
|
|
994
|
+
* Content carried through whole that the editor has no model for: a field, a tracked change, a
|
|
995
|
+
* symbol. Small enough to read the line around it, outlined so it is plainly not ordinary text.
|
|
996
|
+
*
|
|
997
|
+
* Deliberately not `user-select: none`. A chip that carries its content whole can be selected and
|
|
998
|
+
* deleted whole, and taking it out of the selection would leave a reader dragging across it with
|
|
999
|
+
* no way to reach it.
|
|
1000
|
+
*/
|
|
1001
|
+
.docx-editor-raw-inline[data-display="chip"],
|
|
1002
|
+
.docx-editor-raw-run[data-display="chip"] {
|
|
1003
|
+
display: inline-block;
|
|
1004
|
+
max-width: 16em;
|
|
1005
|
+
overflow: hidden;
|
|
1006
|
+
padding: 0 3px;
|
|
1007
|
+
border: 1px dashed #9a9a9a;
|
|
1008
|
+
border-radius: 3px;
|
|
1009
|
+
background: #f2f2f2;
|
|
1010
|
+
color: #595959;
|
|
1011
|
+
font-size: 0.85em;
|
|
1012
|
+
font-family: system-ui, sans-serif;
|
|
1013
|
+
line-height: 1.4;
|
|
1014
|
+
white-space: nowrap;
|
|
1015
|
+
text-overflow: ellipsis;
|
|
965
1016
|
vertical-align: baseline;
|
|
966
1017
|
}
|
|
967
1018
|
|
|
968
|
-
|
|
1019
|
+
/* The chip while it is the selection, which is how a reader sees what a delete would take */
|
|
1020
|
+
.docx-editor-raw-inline[data-display="chip"].ProseMirror-selectednode,
|
|
1021
|
+
.docx-editor-raw-run[data-display="chip"].ProseMirror-selectednode {
|
|
1022
|
+
outline: 2px solid #1a73e8;
|
|
1023
|
+
outline-offset: 1px;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
969
1026
|
.docx-editor-raw-block {
|
|
970
1027
|
margin: 8pt 0;
|
|
971
1028
|
padding: 10pt 12pt;
|
|
@@ -978,6 +1035,11 @@ button.docx-editor-comment-body {
|
|
|
978
1035
|
user-select: none;
|
|
979
1036
|
}
|
|
980
1037
|
|
|
1038
|
+
/* A range marker holds a spot between blocks and stands for nothing on the page. */
|
|
1039
|
+
.docx-editor-raw-block[data-display="hidden"] {
|
|
1040
|
+
display: none;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
981
1043
|
/*
|
|
982
1044
|
* The toolbar.
|
|
983
1045
|
*
|
package/dist/table/resize.d.ts
CHANGED
|
@@ -29,7 +29,8 @@ export interface ColumnEdge {
|
|
|
29
29
|
/**
|
|
30
30
|
* The limit a table can be widened to (dxa).
|
|
31
31
|
*
|
|
32
|
-
* The body width of the paper
|
|
32
|
+
* The body width of the paper handed in, which is the section's the table stands in, minus
|
|
33
|
+
* the table indent (`w:tblInd`).
|
|
33
34
|
* For a table already stored wider than that, its current width is the limit, so
|
|
34
35
|
* dragging can only narrow it.
|
|
35
36
|
*/
|
|
@@ -49,7 +50,8 @@ export declare function resizedGridCols(gridCols: number[], col: number, width:
|
|
|
49
50
|
* Because it is one single transaction, a single undo returns everything to the state
|
|
50
51
|
* before the drag.
|
|
51
52
|
*
|
|
52
|
-
* The geometry is the paper the
|
|
53
|
-
* inside. The editor layer reads it off the state; this layer
|
|
53
|
+
* The geometry is the paper of the section the table stands in, which is what the table is
|
|
54
|
+
* kept inside. The editor layer reads it off the state (`editor/documentStyles`); this layer
|
|
55
|
+
* is handed it.
|
|
54
56
|
*/
|
|
55
57
|
export declare function buildResizeColumnTransaction(state: EditorState, edge: ColumnEdge, geometry: PageGeometry): Transaction | null;
|
|
@@ -5,11 +5,9 @@ import { type CommentAuthor } from "../editor/commands/commentCommands";
|
|
|
5
5
|
export interface CommentsPanelProps {
|
|
6
6
|
view: EditorView;
|
|
7
7
|
state: EditorState;
|
|
8
|
-
composerOpen: boolean;
|
|
9
8
|
/** Whose comments the composers write. Null for a reader, who is offered none */
|
|
10
9
|
author: CommentAuthor | null;
|
|
11
|
-
closeComposer: () => void;
|
|
12
10
|
scrollContainer: HTMLElement | null;
|
|
13
11
|
allCommentsOpen: boolean;
|
|
14
12
|
}
|
|
15
|
-
export declare function CommentsPanel({ view, state,
|
|
13
|
+
export declare function CommentsPanel({ view, state, author, scrollContainer, allCommentsOpen, }: CommentsPanelProps): ReactElement;
|
package/dist/ui/CommentsPanel.js
CHANGED
|
@@ -4,7 +4,6 @@ import { useMemo, useRef, useState } from "react";
|
|
|
4
4
|
import {
|
|
5
5
|
addComment,
|
|
6
6
|
addCommentReply,
|
|
7
|
-
documentComments,
|
|
8
7
|
removeComment,
|
|
9
8
|
removeCommentReply,
|
|
10
9
|
selectComment,
|
|
@@ -12,6 +11,11 @@ import {
|
|
|
12
11
|
updateComment,
|
|
13
12
|
updateCommentReply
|
|
14
13
|
} from "../editor/commands/commentCommands.js";
|
|
14
|
+
import {
|
|
15
|
+
closeCommentComposer,
|
|
16
|
+
commentComposerRange
|
|
17
|
+
} from "../editor/plugins/commentComposer.js";
|
|
18
|
+
import { commentProjection } from "../editor/plugins/commentDecorations.js";
|
|
15
19
|
import { commentOwned } from "../schema/protection.js";
|
|
16
20
|
import { protectionOf } from "../schema/protectionState.js";
|
|
17
21
|
import { editorClassNames } from "../styles/classNames.js";
|
|
@@ -37,19 +41,19 @@ function run(view, command) {
|
|
|
37
41
|
if (applied) view.focus();
|
|
38
42
|
return applied;
|
|
39
43
|
}
|
|
44
|
+
var REFUSED_COMMENT = "This comment could not be added. The text it was written for may have been changed or locked since.";
|
|
45
|
+
var REFUSED_REPLY = "This reply could not be added. The comment it answers may have been changed or deleted since.";
|
|
40
46
|
function sameTarget(left, right) {
|
|
41
47
|
return left?.commentId === right.commentId && left.replyId === right.replyId;
|
|
42
48
|
}
|
|
43
49
|
function CommentsPanel({
|
|
44
50
|
view,
|
|
45
51
|
state,
|
|
46
|
-
composerOpen,
|
|
47
52
|
author,
|
|
48
|
-
closeComposer,
|
|
49
53
|
scrollContainer,
|
|
50
54
|
allCommentsOpen
|
|
51
55
|
}) {
|
|
52
|
-
const comments =
|
|
56
|
+
const comments = commentProjection.read(state).comments;
|
|
53
57
|
const rules = protectionOf(state);
|
|
54
58
|
const writer = author != null && rules.protection !== "readOnly" ? author : null;
|
|
55
59
|
const owned = (authorId) => writer !== null && commentOwned(rules, authorId);
|
|
@@ -57,7 +61,9 @@ function CommentsPanel({
|
|
|
57
61
|
const [editing, setEditing] = useState(null);
|
|
58
62
|
const [draft, setDraft] = useState("");
|
|
59
63
|
const [replying, setReplying] = useState(null);
|
|
60
|
-
const
|
|
64
|
+
const composerRange = commentComposerRange(state);
|
|
65
|
+
const composerOpen = composerRange !== null;
|
|
66
|
+
const composerSelectionPos = composerRange?.from ?? -1;
|
|
61
67
|
const visible = useMemo(
|
|
62
68
|
() => allCommentsOpen ? [...comments].sort((left, right) => {
|
|
63
69
|
const leftTime = Date.parse(left.date ?? "");
|
|
@@ -112,7 +118,7 @@ function CommentsPanel({
|
|
|
112
118
|
className: editorClassNames.commentsCanvas,
|
|
113
119
|
style: { height: allCommentsOpen ? void 0 : `${canvasHeight}px` },
|
|
114
120
|
children: [
|
|
115
|
-
|
|
121
|
+
composerRange !== null && writer !== null && /* @__PURE__ */ jsx(
|
|
116
122
|
"div",
|
|
117
123
|
{
|
|
118
124
|
className: editorClassNames.commentPosition,
|
|
@@ -126,16 +132,19 @@ function CommentsPanel({
|
|
|
126
132
|
author: writer,
|
|
127
133
|
label: "Comment text",
|
|
128
134
|
submitLabel: "Comment",
|
|
129
|
-
onClose:
|
|
135
|
+
onClose: () => run(view, closeCommentComposer),
|
|
130
136
|
onSubmit: (text) => run(
|
|
131
137
|
view,
|
|
132
|
-
addComment(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
addComment(
|
|
139
|
+
{
|
|
140
|
+
text,
|
|
141
|
+
author: writer.name,
|
|
142
|
+
authorId: writer.id,
|
|
143
|
+
initials: writer.initials
|
|
144
|
+
},
|
|
145
|
+
composerRange
|
|
146
|
+
)
|
|
147
|
+
) ? null : REFUSED_COMMENT
|
|
139
148
|
}
|
|
140
149
|
)
|
|
141
150
|
}
|
|
@@ -335,7 +344,7 @@ function CommentsPanel({
|
|
|
335
344
|
authorId: writer.id,
|
|
336
345
|
initials: writer.initials
|
|
337
346
|
})
|
|
338
|
-
)
|
|
347
|
+
) ? null : REFUSED_REPLY
|
|
339
348
|
}
|
|
340
349
|
)
|
|
341
350
|
] })
|
package/dist/ui/NotesPanel.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// src/ui/NotesPanel.tsx
|
|
2
|
-
import {
|
|
2
|
+
import { noteProjection } from "../editor/commands/noteQueries.js";
|
|
3
3
|
import { editorClassNames } from "../styles/classNames.js";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
function NotesPanel({
|
|
6
6
|
state,
|
|
7
7
|
pageWidth
|
|
8
8
|
}) {
|
|
9
|
-
const notes =
|
|
9
|
+
const { notes } = noteProjection.read(state);
|
|
10
10
|
if (notes.length === 0) return null;
|
|
11
11
|
return /* @__PURE__ */ jsxs(
|
|
12
12
|
"section",
|
package/dist/ui/TextMenu.d.ts
CHANGED
|
@@ -9,7 +9,5 @@ export interface TextMenuProps {
|
|
|
9
9
|
anchor: TextMenuAnchor;
|
|
10
10
|
/** Whether the entries that lock and unlock a stretch of text are offered */
|
|
11
11
|
allowLocking?: boolean;
|
|
12
|
-
/** Opens the built-in composer for the selected text. */
|
|
13
|
-
onAddComment?: () => void;
|
|
14
12
|
}
|
|
15
|
-
export declare function TextMenu({ view, state, anchor, allowLocking,
|
|
13
|
+
export declare function TextMenu({ view, state, anchor, allowLocking, }: TextMenuProps): ReactElement;
|
package/dist/ui/TextMenu.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
selectionTouchesLocked,
|
|
18
18
|
unlockSelection
|
|
19
19
|
} from "../editor/commands/lockCommands.js";
|
|
20
|
-
import {
|
|
20
|
+
import { openCommentComposer } from "../editor/plugins/commentComposer.js";
|
|
21
21
|
import {
|
|
22
22
|
closeTextMenu
|
|
23
23
|
} from "../editor/plugins/textContextMenu.js";
|
|
@@ -62,8 +62,13 @@ async function clipboardContent() {
|
|
|
62
62
|
async function pasteFromClipboard(view) {
|
|
63
63
|
const content = await clipboardContent();
|
|
64
64
|
if (!content.html && !content.text) return;
|
|
65
|
+
const data = new DataTransfer();
|
|
66
|
+
if (content.html) data.setData("text/html", content.html);
|
|
67
|
+
if (content.text) data.setData("text/plain", content.text);
|
|
68
|
+
const event = new ClipboardEvent("paste", { clipboardData: data });
|
|
65
69
|
view.focus();
|
|
66
|
-
|
|
70
|
+
if (content.html && view.pasteHTML(content.html, event)) return;
|
|
71
|
+
if (content.text) view.pasteText(content.text, event);
|
|
67
72
|
}
|
|
68
73
|
function lockItem(lock, run) {
|
|
69
74
|
const locking = {
|
|
@@ -90,8 +95,7 @@ function TextMenu({
|
|
|
90
95
|
view,
|
|
91
96
|
state,
|
|
92
97
|
anchor,
|
|
93
|
-
allowLocking = false
|
|
94
|
-
onAddComment
|
|
98
|
+
allowLocking = false
|
|
95
99
|
}) {
|
|
96
100
|
const box = useRef(null);
|
|
97
101
|
const placement = usePanelAtPoint(box, anchor);
|
|
@@ -143,8 +147,8 @@ function TextMenu({
|
|
|
143
147
|
{
|
|
144
148
|
label: "Add comment",
|
|
145
149
|
icon: MessageSquarePlus,
|
|
146
|
-
enabled:
|
|
147
|
-
run: () =>
|
|
150
|
+
enabled: canAddComment(state),
|
|
151
|
+
run: () => run(openCommentComposer)
|
|
148
152
|
}
|
|
149
153
|
]);
|
|
150
154
|
if (allowLocking && bodyOpen) {
|
|
@@ -10,7 +10,12 @@ export interface CommentComposerProps {
|
|
|
10
10
|
author: CommentAuthor;
|
|
11
11
|
label: string;
|
|
12
12
|
submitLabel: string;
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Writes the comment, and answers why it was not written where it was not. The text stays in
|
|
15
|
+
* the form then, together with the reason, rather than the form standing there as if nothing
|
|
16
|
+
* had been asked of it.
|
|
17
|
+
*/
|
|
18
|
+
onSubmit: (text: string) => string | null;
|
|
14
19
|
onClose: () => void;
|
|
15
20
|
}
|
|
16
21
|
export declare function CommentComposer({ author, label, submitLabel, onSubmit, onClose, }: CommentComposerProps): ReactElement;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/ui/comments/CommentComposer.tsx
|
|
2
2
|
import {
|
|
3
|
+
useEffect,
|
|
3
4
|
useLayoutEffect,
|
|
4
5
|
useRef,
|
|
5
6
|
useState
|
|
@@ -12,7 +13,15 @@ function FocusedTextarea({
|
|
|
12
13
|
onChange
|
|
13
14
|
}) {
|
|
14
15
|
const input = useRef(null);
|
|
15
|
-
useLayoutEffect(() => input.current?.focus(), []);
|
|
16
|
+
useLayoutEffect(() => input.current?.focus({ preventScroll: true }), []);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const field = input.current;
|
|
19
|
+
if (typeof field?.scrollIntoView !== "function") return;
|
|
20
|
+
const frame = requestAnimationFrame(() => {
|
|
21
|
+
field.scrollIntoView({ block: "nearest" });
|
|
22
|
+
});
|
|
23
|
+
return () => cancelAnimationFrame(frame);
|
|
24
|
+
}, []);
|
|
16
25
|
return /* @__PURE__ */ jsx(
|
|
17
26
|
"textarea",
|
|
18
27
|
{
|
|
@@ -32,13 +41,27 @@ function CommentComposer({
|
|
|
32
41
|
onClose
|
|
33
42
|
}) {
|
|
34
43
|
const [text, setText] = useState("");
|
|
44
|
+
const [refused, setRefused] = useState(null);
|
|
35
45
|
const submit = (event) => {
|
|
36
46
|
event.preventDefault();
|
|
37
|
-
|
|
47
|
+
const reason = onSubmit(text);
|
|
48
|
+
setRefused(reason);
|
|
49
|
+
if (reason === null) onClose();
|
|
38
50
|
};
|
|
39
51
|
return /* @__PURE__ */ jsxs("form", { className: editorClassNames.commentComposer, onSubmit: submit, children: [
|
|
40
52
|
/* @__PURE__ */ jsx("div", { className: editorClassNames.commentMeta, children: author.name }),
|
|
41
|
-
/* @__PURE__ */ jsx(
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
FocusedTextarea,
|
|
55
|
+
{
|
|
56
|
+
label,
|
|
57
|
+
value: text,
|
|
58
|
+
onChange: (next) => {
|
|
59
|
+
setRefused(null);
|
|
60
|
+
setText(next);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
),
|
|
64
|
+
refused !== null && /* @__PURE__ */ jsx("p", { className: editorClassNames.commentMeta, role: "alert", children: refused }),
|
|
42
65
|
/* @__PURE__ */ jsxs("div", { className: editorClassNames.commentActions, children: [
|
|
43
66
|
/* @__PURE__ */ jsx("button", { type: "button", onClick: onClose, children: "Cancel" }),
|
|
44
67
|
/* @__PURE__ */ jsx(
|