@portone/docx-editor 0.6.0 → 0.6.2

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.
Files changed (146) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/DocxEditor.js +84 -26
  3. package/dist/core.d.ts +4 -3
  4. package/dist/docx/exportDocx.d.ts +3 -2
  5. package/dist/docx/exportDocx.js +6 -10
  6. package/dist/docx/headersFooters.js +35 -23
  7. package/dist/docx/identities.d.ts +30 -0
  8. package/dist/docx/identities.js +43 -10
  9. package/dist/docx/importDocx.js +25 -26
  10. package/dist/docx/importParagraph.d.ts +1 -4
  11. package/dist/docx/importParagraph.js +4 -18
  12. package/dist/docx/invariants.d.ts +13 -10
  13. package/dist/docx/invariants.js +300 -116
  14. package/dist/docx/newLists.js +12 -3
  15. package/dist/docx/notes/newNote.d.ts +39 -0
  16. package/dist/docx/notes/newNote.js +122 -0
  17. package/dist/docx/notes/numbering.d.ts +27 -0
  18. package/dist/docx/notes/numbering.js +113 -0
  19. package/dist/docx/notes/reading.d.ts +58 -0
  20. package/dist/docx/notes/reading.js +98 -0
  21. package/dist/docx/notes/references.d.ts +33 -0
  22. package/dist/docx/notes/references.js +37 -0
  23. package/dist/docx/notes/writing.d.ts +19 -0
  24. package/dist/docx/notes/writing.js +95 -0
  25. package/dist/docx/partPlan.d.ts +3 -0
  26. package/dist/docx/partPlanners.d.ts +13 -0
  27. package/dist/docx/partPlanners.js +48 -0
  28. package/dist/docx/sections.d.ts +5 -0
  29. package/dist/docx/sections.js +7 -2
  30. package/dist/docx/serializeParagraph.js +7 -2
  31. package/dist/docx/serializePreserved.d.ts +5 -1
  32. package/dist/docx/serializePreserved.js +24 -7
  33. package/dist/docx/session.d.ts +5 -0
  34. package/dist/docx/session.js +6 -0
  35. package/dist/docx/storyParts.d.ts +133 -0
  36. package/dist/docx/storyParts.js +314 -0
  37. package/dist/editor/clipboard/htmlReader.d.ts +24 -4
  38. package/dist/editor/clipboard/htmlReader.js +39 -4
  39. package/dist/editor/clipboard/internalChannel.d.ts +30 -3
  40. package/dist/editor/clipboard/internalChannel.js +43 -3
  41. package/dist/editor/clipboard/normalizers.d.ts +35 -8
  42. package/dist/editor/clipboard/normalizers.js +60 -11
  43. package/dist/editor/clipboard/plugin.js +42 -22
  44. package/dist/editor/commands/exportQueries.d.ts +4 -3
  45. package/dist/editor/commands/index.d.ts +2 -1
  46. package/dist/editor/commands/index.js +18 -0
  47. package/dist/editor/commands/noteCommands.d.ts +47 -0
  48. package/dist/editor/commands/noteCommands.js +95 -0
  49. package/dist/editor/commands/noteQueries.d.ts +22 -3
  50. package/dist/editor/commands/noteQueries.js +21 -13
  51. package/dist/editor/createEditor.js +21 -3
  52. package/dist/editor/documentStyles.d.ts +3 -0
  53. package/dist/editor/documentStyles.js +2 -1
  54. package/dist/editor/editorDocument.d.ts +24 -0
  55. package/dist/editor/editorDocument.js +34 -4
  56. package/dist/editor/notes/noteSurface.d.ts +53 -0
  57. package/dist/editor/notes/noteSurface.js +246 -0
  58. package/dist/editor/plugins/compositionSelection.d.ts +20 -0
  59. package/dist/editor/plugins/compositionSelection.js +19 -0
  60. package/dist/editor/plugins/keymap.d.ts +14 -0
  61. package/dist/editor/plugins/keymap.js +13 -1
  62. package/dist/editor/plugins/noteLifecycle.d.ts +18 -0
  63. package/dist/editor/plugins/noteLifecycle.js +117 -0
  64. package/dist/editor/plugins/noteNavigation.d.ts +45 -0
  65. package/dist/editor/plugins/noteNavigation.js +86 -0
  66. package/dist/editor/plugins/noteNumbering.d.ts +13 -0
  67. package/dist/editor/plugins/noteNumbering.js +58 -0
  68. package/dist/editor/plugins/rowResize.js +2 -7
  69. package/dist/editor/plugins/tabLayout.js +2 -7
  70. package/dist/editor/stories/storyMarkup.d.ts +24 -0
  71. package/dist/editor/stories/storyMarkup.js +35 -0
  72. package/dist/editor/stories/storyState.d.ts +34 -0
  73. package/dist/editor/stories/storyState.js +74 -0
  74. package/dist/editor/stories/storyView.d.ts +115 -0
  75. package/dist/editor/stories/storyView.js +144 -0
  76. package/dist/index.d.ts +2 -2
  77. package/dist/numbering/spellers.d.ts +1 -1
  78. package/dist/numbering/spellers.js +6 -1
  79. package/dist/ooxml/errors.d.ts +135 -2
  80. package/dist/ooxml/errors.js +6 -0
  81. package/dist/page/blockKinds.d.ts +23 -4
  82. package/dist/page/demands/footnoteDemands.d.ts +18 -0
  83. package/dist/page/demands/footnoteDemands.js +51 -0
  84. package/dist/page/demands/index.d.ts +43 -0
  85. package/dist/page/demands/index.js +8 -0
  86. package/dist/page/kinds/paragraphKind.js +7 -1
  87. package/dist/page/kinds/tableKind.js +9 -1
  88. package/dist/page/measureBlocks.d.ts +2 -0
  89. package/dist/page/measureBlocks.js +31 -10
  90. package/dist/page/pageDecorations.d.ts +9 -2
  91. package/dist/page/pageDecorations.js +18 -5
  92. package/dist/page/pageLayout.d.ts +77 -1
  93. package/dist/page/pageLayout.js +186 -9
  94. package/dist/page/usePageLayout.d.ts +57 -2
  95. package/dist/page/usePageLayout.js +50 -5
  96. package/dist/schema/attrRoles.js +3 -2
  97. package/dist/schema/docxSchema.js +5 -2
  98. package/dist/schema/editGuard.d.ts +1 -1
  99. package/dist/schema/guards.js +1 -2
  100. package/dist/schema/preservedGuards.d.ts +4 -6
  101. package/dist/schema/preservedGuards.js +0 -9
  102. package/dist/schema/stories.d.ts +42 -2
  103. package/dist/schema/stories.js +28 -5
  104. package/dist/styles/classNames.d.ts +21 -6
  105. package/dist/styles/classNames.js +21 -6
  106. package/dist/styles/inlineStyle.d.ts +7 -0
  107. package/dist/styles/inlineStyle.js +11 -5
  108. package/dist/styles/visualScale.d.ts +19 -0
  109. package/dist/styles/visualScale.js +26 -0
  110. package/dist/styles.css +89 -32
  111. package/dist/ui/InsertImageButton.d.ts +3 -1
  112. package/dist/ui/InsertImageButton.js +3 -2
  113. package/dist/ui/TableMenu.d.ts +5 -2
  114. package/dist/ui/TableMenu.js +18 -1
  115. package/dist/ui/TextMenu.d.ts +5 -2
  116. package/dist/ui/TextMenu.js +21 -6
  117. package/dist/ui/Toolbar.d.ts +17 -2
  118. package/dist/ui/Toolbar.js +23 -10
  119. package/dist/ui/comments/useCommentRailLayout.js +2 -4
  120. package/dist/ui/noteItems.d.ts +21 -0
  121. package/dist/ui/noteItems.js +30 -0
  122. package/dist/ui/notes/NoteAreas.d.ts +73 -0
  123. package/dist/ui/notes/NoteAreas.js +131 -0
  124. package/dist/ui/notes/NoteList.d.ts +25 -0
  125. package/dist/ui/notes/NoteList.js +58 -0
  126. package/dist/ui/notes/StoryRow.d.ts +75 -0
  127. package/dist/ui/notes/StoryRow.js +122 -0
  128. package/dist/ui/notes/noteBands.d.ts +100 -0
  129. package/dist/ui/notes/noteBands.js +142 -0
  130. package/dist/ui/notes/noteHeights.d.ts +10 -0
  131. package/dist/ui/notes/noteHeights.js +24 -0
  132. package/dist/ui/notes/noteSeparator.d.ts +12 -0
  133. package/dist/ui/notes/noteSeparator.js +9 -0
  134. package/dist/ui/notes/useStorySurface.d.ts +68 -0
  135. package/dist/ui/notes/useStorySurface.js +95 -0
  136. package/dist/ui/runCommand.d.ts +8 -1
  137. package/dist/ui/runCommand.js +2 -2
  138. package/dist/ui/shortcutLabels.d.ts +16 -0
  139. package/dist/ui/shortcutLabels.js +9 -0
  140. package/dist/ui/usePageRoom.d.ts +13 -0
  141. package/dist/ui/usePageRoom.js +31 -0
  142. package/package.json +1 -1
  143. package/dist/docx/notes.d.ts +0 -27
  144. package/dist/docx/notes.js +0 -55
  145. package/dist/ui/NotesPanel.d.ts +0 -6
  146. package/dist/ui/NotesPanel.js +0 -33
@@ -7,6 +7,7 @@ import {
7
7
  withListNumbering,
8
8
  withParagraphStyle
9
9
  } from "../../docx/paraProps.js";
10
+ import { setStory } from "../../docx/story.js";
10
11
  import {
11
12
  listsWorn,
12
13
  NEW_LISTS_ATTR,
@@ -20,6 +21,10 @@ import {
20
21
  import { styleIdOf } from "../../ooxml/props.js";
21
22
  import { docxSchema } from "../../schema/index.js";
22
23
  import { COPIED_STYLE_ATTRIBUTE } from "../../schema/clipboard.js";
24
+ import {
25
+ EDITABLE_NOTE_KINDS,
26
+ storyKey
27
+ } from "../../schema/stories.js";
23
28
  import { editorClassNames } from "../../styles/classNames.js";
24
29
  import { numIdsIn } from "../commands/listCommands.js";
25
30
  import {
@@ -32,6 +37,9 @@ import {
32
37
  marksFor,
33
38
  withInlineStyle
34
39
  } from "./inlineFormatting.js";
40
+ import {
41
+ NO_NOTE_STORIES
42
+ } from "./internalChannel.js";
35
43
  import { detectHtmlSource } from "./source.js";
36
44
  var BLOCK_TAGS = /* @__PURE__ */ new Set([
37
45
  "ADDRESS",
@@ -363,14 +371,41 @@ function readHtmlSlice(context, source) {
363
371
  template.innerHTML = source;
364
372
  return readHtml(template.content, context);
365
373
  }
374
+ function notesCalledIn(doc) {
375
+ const keys = /* @__PURE__ */ new Set();
376
+ doc.descendants((node) => {
377
+ if (node.type !== docxSchema.nodes.noteReference) return true;
378
+ const kind = EDITABLE_NOTE_KINDS.find(
379
+ (candidate) => candidate === node.attrs.kind
380
+ );
381
+ const id = node.attrs.id;
382
+ if (kind !== void 0 && typeof id === "string") {
383
+ keys.add(storyKey(kind, id));
384
+ }
385
+ return true;
386
+ });
387
+ return keys;
388
+ }
389
+ function withPastedStories(tr, stories) {
390
+ if (stories.size === 0) return tr;
391
+ const called = notesCalledIn(tr.doc);
392
+ for (const [key, story] of stories) {
393
+ if (called.has(key)) setStory(tr, key, story);
394
+ }
395
+ return tr;
396
+ }
366
397
  function withPastedContent(tr, content) {
367
- return tr.setDocAttribute(
368
- NEW_LISTS_ATTR,
369
- newListsValue(listsWorn(content.newLists, numIdsIn(tr.doc)))
398
+ return withPastedStories(
399
+ tr.setDocAttribute(
400
+ NEW_LISTS_ATTR,
401
+ newListsValue(listsWorn(content.newLists, numIdsIn(tr.doc)))
402
+ ),
403
+ content.newStories ?? NO_NOTE_STORIES
370
404
  );
371
405
  }
372
406
  export {
373
407
  readHtml,
374
408
  readHtmlSlice,
375
- withPastedContent
409
+ withPastedContent,
410
+ withPastedStories
376
411
  };
@@ -16,15 +16,23 @@
16
16
  * about the copy that only the editor it was copied from can answer: a number says nothing about
17
17
  * whether it counted or bulleted, and the definition that said so is the source document's. It is
18
18
  * read here because this is where both ends are the same session.
19
+ *
20
+ * The note each reference in it calls is kept the same way, and for a stronger reason: a cut takes
21
+ * a footnote away together with its last reference (`editor/plugins/noteLifecycle`), so by the time
22
+ * the paste happens the document no longer holds what the copy was pointing at.
19
23
  */
20
- import type { Slice } from "prosemirror-model";
24
+ import type { Node as PMNode, Slice } from "prosemirror-model";
21
25
  import type { ListKind } from "../../numbering/listTemplate";
22
26
  import type { Numbering } from "../../numbering/parseNumbering";
27
+ import { type NoteKey, type StoryKey } from "../../schema/stories";
23
28
  /** Where the copied HTML carries the name of the slice this editor kept */
24
29
  export declare const INTERNAL_TOKEN_ATTRIBUTE = "data-docx-clip";
25
30
  /** The kind of list each numbering id of a slice stood for where the slice was copied */
26
31
  export type ListKinds = ReadonlyMap<number, ListKind>;
27
32
  export declare const NO_LIST_KINDS: ListKinds;
33
+ /** The story of each note the slice refers to, as the document copied from held it */
34
+ export type NoteStories = ReadonlyMap<NoteKey, PMNode>;
35
+ export declare const NO_NOTE_STORIES: NoteStories;
28
36
  /**
29
37
  * The two ways a copy leaves the editor.
30
38
  *
@@ -34,19 +42,38 @@ export declare const NO_LIST_KINDS: ListKinds;
34
42
  * replaced only by the next copy made the same way.
35
43
  */
36
44
  export type CopyRoute = "clipboard" | "drag";
37
- /** What one name stands for: the slice that was copied, and what its list numbers meant there */
45
+ /** What one name stands for: the slice that was copied, and what it named where it was copied */
38
46
  export interface RecalledCopy {
39
47
  readonly slice: Slice;
40
48
  readonly listKinds: ListKinds;
49
+ readonly noteStories: NoteStories;
50
+ }
51
+ /** The document a copy is made from, which is the only one that can answer what it carries */
52
+ export interface CopySource {
53
+ /** Null for a state built without a document, which has no session to bind a name to */
54
+ readonly sessionId: string | null;
55
+ readonly doc: PMNode;
56
+ readonly numbering: Numbering;
57
+ /** The notes laying a part out rather than saying something, which are never copied */
58
+ readonly specialNotes: ReadonlySet<StoryKey>;
41
59
  }
42
60
  /**
43
61
  * Keeps the copied slice under a fresh name, and answers with the name to write into the markup.
44
62
  * Null for a state built without a document: with no session to bind the name to there is nothing
45
63
  * to tell this editor's copy from another's, and the copy travels as markup alone.
46
64
  */
47
- export declare function rememberCopied(route: CopyRoute, slice: Slice, sessionId: string | null, numbering: Numbering): string | null;
65
+ export declare function rememberCopied(route: CopyRoute, slice: Slice, source: CopySource): string | null;
48
66
  /** The copy that name stands for, and only when the session asking is the one that copied it */
49
67
  export declare function recallCopied(token: string | null, sessionId: string | null): RecalledCopy | null;
68
+ /**
69
+ * The notes the last drag out of this editor carried.
70
+ *
71
+ * A drop is handed the slice itself rather than markup (`prosemirror-view`), so it carries no name
72
+ * to look a copy up by; the drag is the one route whose last copy is the copy being dropped. The
73
+ * session must still be the one that dragged, since a drop from another editor arrives as the
74
+ * markup its own reader answers for.
75
+ */
76
+ export declare function draggedNotes(sessionId: string | null): NoteStories;
50
77
  /**
51
78
  * The name the pasted markup carries, if it carries one.
52
79
  *
@@ -1,31 +1,50 @@
1
1
  // src/editor/clipboard/internalChannel.ts
2
2
  import { docxSchema } from "../../schema/index.js";
3
+ import {
4
+ EDITABLE_NOTE_KINDS,
5
+ storyKey,
6
+ storyNodeOf
7
+ } from "../../schema/stories.js";
3
8
  import { listKindOf, listRefOf } from "../commands/listCommands.js";
4
9
  var INTERNAL_TOKEN_ATTRIBUTE = "data-docx-clip";
5
10
  var NO_LIST_KINDS = /* @__PURE__ */ new Map();
11
+ var NO_NOTE_STORIES = /* @__PURE__ */ new Map();
6
12
  var copied = /* @__PURE__ */ new Map();
7
13
  var copies = 0;
8
14
  function nextToken() {
9
15
  copies += 1;
10
16
  return `c${copies}-${Math.random().toString(36).slice(2, 10)}`;
11
17
  }
12
- function rememberCopied(route, slice, sessionId, numbering) {
18
+ function rememberCopied(route, slice, source) {
19
+ const { sessionId } = source;
13
20
  if (sessionId === null) return null;
14
21
  const token = nextToken();
15
22
  copied.set(route, {
16
23
  token,
17
24
  sessionId,
18
25
  slice,
19
- listKinds: listKindsIn(slice, numbering)
26
+ listKinds: listKindsIn(slice, source.numbering),
27
+ noteStories: noteStoriesIn(slice, source)
20
28
  });
21
29
  return token;
22
30
  }
31
+ function recalled(copy) {
32
+ return {
33
+ slice: copy.slice,
34
+ listKinds: copy.listKinds,
35
+ noteStories: copy.noteStories
36
+ };
37
+ }
23
38
  function recallCopied(token, sessionId) {
24
39
  if (token === null || sessionId === null) return null;
25
40
  const found = [...copied.values()].find(
26
41
  (copy) => copy.token === token && copy.sessionId === sessionId
27
42
  );
28
- return found === void 0 ? null : { slice: found.slice, listKinds: found.listKinds };
43
+ return found === void 0 ? null : recalled(found);
44
+ }
45
+ function draggedNotes(sessionId) {
46
+ const found = copied.get("drag");
47
+ return found === void 0 || sessionId === null || found.sessionId !== sessionId ? NO_NOTE_STORIES : found.noteStories;
29
48
  }
30
49
  function listKindsIn(slice, numbering) {
31
50
  const kinds = /* @__PURE__ */ new Map();
@@ -41,6 +60,25 @@ function listKindsIn(slice, numbering) {
41
60
  slice.content.forEach(read);
42
61
  return kinds.size === 0 ? NO_LIST_KINDS : kinds;
43
62
  }
63
+ function noteStoriesIn(slice, source) {
64
+ const stories = /* @__PURE__ */ new Map();
65
+ const read = (node) => {
66
+ if (node.type === docxSchema.nodes.noteReference) {
67
+ const kind = EDITABLE_NOTE_KINDS.find(
68
+ (candidate) => candidate === node.attrs.kind
69
+ );
70
+ const id = node.attrs.id;
71
+ if (kind === void 0 || typeof id !== "string") return;
72
+ const key = storyKey(kind, id);
73
+ const story = source.specialNotes.has(key) ? null : storyNodeOf(source.doc, key);
74
+ if (story !== null) stories.set(key, story);
75
+ return;
76
+ }
77
+ node.forEach(read);
78
+ };
79
+ slice.content.forEach(read);
80
+ return stories.size === 0 ? NO_NOTE_STORIES : stories;
81
+ }
44
82
  function internalTokenOf(dom) {
45
83
  if (dom instanceof Element) {
46
84
  const own = dom.getAttribute(INTERNAL_TOKEN_ATTRIBUTE);
@@ -52,6 +90,8 @@ function internalTokenOf(dom) {
52
90
  export {
53
91
  INTERNAL_TOKEN_ATTRIBUTE,
54
92
  NO_LIST_KINDS,
93
+ NO_NOTE_STORIES,
94
+ draggedNotes,
55
95
  internalTokenOf,
56
96
  recallCopied,
57
97
  rememberCopied
@@ -16,8 +16,9 @@
16
16
  import { type Node as PMNode, Slice } from "prosemirror-model";
17
17
  import type { EditorState } from "prosemirror-state";
18
18
  import { type ListKind } from "../../numbering/listTemplate";
19
+ import { type NoteKind } from "../../schema/stories";
19
20
  import type { PastedContent } from "./htmlReader";
20
- import { type ListKinds } from "./internalChannel";
21
+ import { type ListKinds, type NoteStories } from "./internalChannel";
21
22
  /** What one normalizer answers about the document the slice is going into */
22
23
  export interface NormalizeContext {
23
24
  readonly state: EditorState;
@@ -40,6 +41,17 @@ export interface NormalizeContext {
40
41
  * the list button starts one. Null in a document with nowhere to write a definition.
41
42
  */
42
43
  startList(kind: ListKind): number | null;
44
+ /**
45
+ * What the notes the slice's references call said where it was copied
46
+ * (`./internalChannel`). Empty for a slice that arrived any other way, whose references name
47
+ * notes of a document this one knows nothing about.
48
+ */
49
+ readonly noteStories: NoteStories;
50
+ /**
51
+ * A note this paste puts in, under an id no note of this document answers to, registered in
52
+ * `PastedContent.newStories`. It answers with the id the reference is pasted under.
53
+ */
54
+ startNote(kind: NoteKind, story: PMNode): string;
43
55
  }
44
56
  export type SliceNormalizer = (slice: Slice, context: NormalizeContext) => Slice;
45
57
  /** The slice with every node rewritten depth first, and the ones mapped to null taken out */
@@ -71,17 +83,31 @@ export declare const rekeyNumbering: SliceNormalizer;
71
83
  /**
72
84
  * Takes the anchors off what is pasted.
73
85
  *
74
- * A comment marker, a bookmark and a note reference all point at something written elsewhere in
75
- * the package: the comment, the bookmark's other end, the note's body. A copy of the marker alone
76
- * points at the same thing a second time, which is a duplicate identifier the file may not hold
77
- * and a range the reader cannot close. Nothing here duplicates what they point at, so the anchor
78
- * goes and the text it stood in stays, which is what Word does with a note it has no body for.
86
+ * A comment marker and a bookmark both point at something written elsewhere in the package: the
87
+ * comment, the bookmark's other end. A copy of the marker alone points at the same thing a second
88
+ * time, which is a duplicate identifier the file may not hold and a range the reader cannot close.
89
+ * Nothing here duplicates what they point at, so the anchor goes and the text it stood in stays,
90
+ * which is what Word does with a note it has no body for.
79
91
  *
80
92
  * A move drop duplicates nothing: the source goes as the drop lands, so the one anchor there was
81
93
  * travels with the text it opened. Taking it off would delete a marker the document has no way to
82
94
  * write back, which is a change the preserved guard refuses whole, and the drag would do nothing.
83
95
  */
84
96
  export declare const detachAnchors: SliceNormalizer;
97
+ /**
98
+ * Gives a pasted note reference a note of its own.
99
+ *
100
+ * A note is written once and called from the text by its id, so a second reference naming that id
101
+ * is one note drawn with one number where the reader made two. The note each reference called was
102
+ * remembered as the slice was copied (`./internalChannel`) - a cut deletes a footnote together
103
+ * with its last reference, so the document no longer holds it by the time the paste lands - and
104
+ * each reference is pasted under a fresh id with a copy of that note beside it.
105
+ *
106
+ * A reference no remembered note answers for points at nothing here: a copy from another editor or
107
+ * another document numbers its notes against its own file, and markup naming one says nothing
108
+ * about what it said. It goes the way the other anchors do.
109
+ */
110
+ export declare const duplicateNotes: SliceNormalizer;
85
111
  /**
86
112
  * Works out again what the pasted paragraphs are drawn with.
87
113
  *
@@ -93,7 +119,8 @@ export declare const detachAnchors: SliceNormalizer;
93
119
  export declare const rederiveDisplay: SliceNormalizer;
94
120
  export declare const DEFAULT_NORMALIZERS: readonly SliceNormalizer[];
95
121
  /**
96
- * The pasted content as this document may hold it, and the definitions of the lists the paste
97
- * starts - the ones a reading started, and the ones a reissued number was taken for.
122
+ * The pasted content as this document may hold it, the definitions of the lists the paste starts -
123
+ * the ones a reading started, and the ones a reissued number was taken for - and the notes it puts
124
+ * in beside the references calling them.
98
125
  */
99
126
  export declare function normalizePasted(content: PastedContent, state: EditorState, move: boolean, normalizers?: readonly SliceNormalizer[]): PastedContent;
@@ -9,6 +9,11 @@ import {
9
9
  resolveParagraph,
10
10
  resolveRun
11
11
  } from "../../docx/formatting.js";
12
+ import {
13
+ copiedNoteStory,
14
+ nextNoteId,
15
+ takenNoteIds
16
+ } from "../../docx/notes/newNote.js";
12
17
  import { withListNumbering } from "../../docx/paraProps.js";
13
18
  import {
14
19
  allocateList,
@@ -20,13 +25,21 @@ import {
20
25
  RANGE_MARKERS
21
26
  } from "../../ooxml/rangeMarkers.js";
22
27
  import { docxSchema } from "../../schema/index.js";
28
+ import {
29
+ EDITABLE_NOTE_KINDS,
30
+ storyKey
31
+ } from "../../schema/stories.js";
23
32
  import { listRefOf, numIdsIn } from "../commands/listCommands.js";
24
33
  import { documentFormatting } from "../documentStyles.js";
34
+ import { documentOf } from "../editorDocument.js";
25
35
  import {
26
36
  canStartNewList,
27
37
  documentNumbering
28
38
  } from "../plugins/numberingDecorations.js";
29
- import { NO_LIST_KINDS } from "./internalChannel.js";
39
+ import {
40
+ NO_LIST_KINDS,
41
+ NO_NOTE_STORIES
42
+ } from "./internalChannel.js";
30
43
  function xmlAttr(value) {
31
44
  return typeof value === "string" ? value : null;
32
45
  }
@@ -90,22 +103,25 @@ var rekeyNumbering = (slice, context) => {
90
103
  return props === null ? node : withAttrs(node, { ...node.attrs, pPr: props.pPr });
91
104
  });
92
105
  };
93
- var ANCHOR_NODES = /* @__PURE__ */ new Set([
94
- "commentStart",
95
- "commentEnd",
96
- "commentReference",
97
- "noteReference"
98
- ]);
106
+ var ANCHORS = {
107
+ commentStart: () => true,
108
+ commentEnd: () => true,
109
+ commentReference: () => true
110
+ };
99
111
  var REFERENCE_ELEMENTS = [
100
112
  "commentReference",
101
113
  "footnoteReference",
102
- "endnoteReference"
114
+ "endnoteReference",
115
+ "footnoteRef",
116
+ "endnoteRef"
103
117
  ];
118
+ var NOTE_OWN_MARKS = ["footnoteRef", "endnoteRef"];
104
119
  var ANCHOR_ELEMENTS = /* @__PURE__ */ new Set([
105
120
  ...RANGE_MARKERS,
106
121
  ...PERMISSION_MARKERS,
107
122
  ...COMMENT_RANGE_MARKERS,
108
- ...REFERENCE_ELEMENTS
123
+ ...REFERENCE_ELEMENTS,
124
+ ...NOTE_OWN_MARKS
109
125
  ]);
110
126
  var PRESERVED_INLINE = /* @__PURE__ */ new Set([
111
127
  "rawInline",
@@ -119,11 +135,26 @@ function preservedName(node) {
119
135
  return typeof element === "string" ? element : null;
120
136
  }
121
137
  var detachAnchors = (slice, { move }) => move ? slice : mapSliceNodes(slice, (node) => {
122
- if (ANCHOR_NODES.has(node.type.name)) return null;
138
+ if (ANCHORS[node.type.name]?.(node) === true) return null;
123
139
  if (!PRESERVED_INLINE.has(node.type.name)) return node;
124
140
  const name = preservedName(node);
125
141
  return name !== null && ANCHOR_ELEMENTS.has(name) ? null : node;
126
142
  });
143
+ var duplicateNotes = (slice, { move, noteStories, startNote }) => move ? slice : mapSliceNodes(slice, (node) => {
144
+ if (node.type !== docxSchema.nodes.noteReference) return node;
145
+ const kind = EDITABLE_NOTE_KINDS.find(
146
+ (candidate) => candidate === node.attrs.kind
147
+ );
148
+ const id = node.attrs.id;
149
+ if (kind === void 0 || typeof id !== "string") return null;
150
+ const story = noteStories.get(storyKey(kind, id));
151
+ if (story === void 0) return null;
152
+ return withAttrs(node, {
153
+ ...node.attrs,
154
+ id: startNote(kind, story),
155
+ referenceXml: null
156
+ });
157
+ });
127
158
  var rederiveDisplay = (slice, { state }) => {
128
159
  const formatting = documentFormatting(state);
129
160
  return mapSliceNodes(slice, (node) => {
@@ -152,6 +183,7 @@ var rederiveDisplay = (slice, { state }) => {
152
183
  var DEFAULT_NORMALIZERS = [
153
184
  dropSourceIdentity,
154
185
  detachAnchors,
186
+ duplicateNotes,
155
187
  rekeyNumbering,
156
188
  rederiveDisplay
157
189
  ];
@@ -164,11 +196,26 @@ function normalizePasted(content, state, move, normalizers = DEFAULT_NORMALIZERS
164
196
  ...content.newLists.keys()
165
197
  ]);
166
198
  const started = /* @__PURE__ */ new Map();
199
+ const document = documentOf(state);
200
+ const takenNotes = /* @__PURE__ */ new Map();
201
+ const startedNotes = /* @__PURE__ */ new Map();
167
202
  const context = {
168
203
  state,
169
204
  move,
170
205
  knownLists: known,
171
206
  listKinds: content.listKinds ?? NO_LIST_KINDS,
207
+ noteStories: content.noteStories ?? NO_NOTE_STORIES,
208
+ startNote(kind, story) {
209
+ const ids = takenNotes.get(kind) ?? takenNoteIds(state.doc, kind, document.reservedNoteKeys);
210
+ takenNotes.set(kind, ids);
211
+ const id = nextNoteId(ids);
212
+ ids.add(id);
213
+ startedNotes.set(
214
+ storyKey(kind, id),
215
+ copiedNoteStory(story, document.session)
216
+ );
217
+ return id;
218
+ },
172
219
  startList(kind) {
173
220
  if (!canStartNewList(state)) return null;
174
221
  const list = templateList(kind);
@@ -185,13 +232,15 @@ function normalizePasted(content, state, move, normalizers = DEFAULT_NORMALIZERS
185
232
  );
186
233
  return {
187
234
  slice,
188
- newLists: started.size === 0 ? content.newLists : new Map([...content.newLists, ...started])
235
+ newLists: started.size === 0 ? content.newLists : new Map([...content.newLists, ...started]),
236
+ newStories: startedNotes.size === 0 ? content.newStories : startedNotes
189
237
  };
190
238
  }
191
239
  export {
192
240
  DEFAULT_NORMALIZERS,
193
241
  detachAnchors,
194
242
  dropSourceIdentity,
243
+ duplicateNotes,
195
244
  mapSliceNodes,
196
245
  normalizePasted,
197
246
  rederiveDisplay,
@@ -13,7 +13,9 @@ import { documentOf } from "../editorDocument.js";
13
13
  import { insertPlainText } from "../plainText.js";
14
14
  import { moveCaretToDrop } from "../plugins/dropCaret.js";
15
15
  import { documentNumbering } from "../plugins/numberingDecorations.js";
16
+ import { withPastedStories } from "./htmlReader.js";
16
17
  import {
18
+ draggedNotes,
17
19
  INTERNAL_TOKEN_ATTRIBUTE,
18
20
  internalTokenOf,
19
21
  rememberCopied
@@ -78,6 +80,7 @@ function docxClipboard(options = {}) {
78
80
  }
79
81
  );
80
82
  let started = null;
83
+ let startedStories = null;
81
84
  let dropMove = false;
82
85
  let draggingOut = false;
83
86
  return new Plugin({
@@ -90,26 +93,33 @@ function docxClipboard(options = {}) {
90
93
  };
91
94
  },
92
95
  /**
93
- * The definitions of the lists a paste began, registered on the document once the paste is
94
- * in. A list the pasted markup started is numbered as it is read, and only the edit that
95
- * lands says whether that number is worn in the end.
96
+ * What a paste brought beside its text, registered on the document once the paste is in: the
97
+ * definitions of the lists it began and the notes its references call. A list the pasted
98
+ * markup started is numbered as it is read, and only the edit that lands says whether that
99
+ * number is worn in the end.
96
100
  */
97
101
  appendTransaction(transactions, _before, after) {
98
102
  const lists = started;
103
+ const stories = startedStories;
99
104
  started = null;
100
- if (lists === null || lists.size === 0 || !transactions.some((tr) => tr.docChanged)) {
101
- return null;
105
+ startedStories = null;
106
+ if (!transactions.some((tr2) => tr2.docChanged)) return null;
107
+ const tr = after.tr;
108
+ if (lists !== null && lists.size > 0) {
109
+ const worn = numIdsIn(after.doc);
110
+ const registered = newListsOf(after.doc.attrs[NEW_LISTS_ATTR]);
111
+ const missing = [...lists].filter(
112
+ ([numId]) => worn.has(numId) && !registered.has(numId)
113
+ );
114
+ if (missing.length > 0) {
115
+ tr.setDocAttribute(
116
+ NEW_LISTS_ATTR,
117
+ newListsValue(new Map([...registered, ...missing]))
118
+ );
119
+ }
102
120
  }
103
- const worn = numIdsIn(after.doc);
104
- const registered = newListsOf(after.doc.attrs[NEW_LISTS_ATTR]);
105
- const missing = [...lists].filter(
106
- ([numId]) => worn.has(numId) && !registered.has(numId)
107
- );
108
- if (missing.length === 0) return null;
109
- return after.tr.setDocAttribute(
110
- NEW_LISTS_ATTR,
111
- newListsValue(new Map([...registered, ...missing]))
112
- );
121
+ if (stories !== null) withPastedStories(tr, stories);
122
+ return tr.steps.length === 0 ? null : tr;
113
123
  },
114
124
  props: {
115
125
  handleDOMEvents: {
@@ -145,24 +155,34 @@ function docxClipboard(options = {}) {
145
155
  clipboardTextSerializer: clipboardText,
146
156
  transformCopied(slice, view) {
147
157
  const route = draggingOut ? "drag" : "clipboard";
148
- copyToken = rememberCopied(
149
- route,
150
- slice,
151
- documentOf(view.state).session?.sessionId ?? null,
152
- documentNumbering(view.state)
153
- );
158
+ const document = documentOf(view.state);
159
+ copyToken = rememberCopied(route, slice, {
160
+ sessionId: document.session?.sessionId ?? null,
161
+ doc: view.state.doc,
162
+ numbering: documentNumbering(view.state),
163
+ specialNotes: document.specialNotes
164
+ });
154
165
  return copiedSlice(slice);
155
166
  },
156
167
  transformPasted(slice, view, plain) {
157
168
  if (!plain) parser.setPlainText(false);
158
169
  const read = parser.takeRead();
159
170
  const content = normalizePasted(
160
- read ?? { slice, newLists: NO_NEW_LISTS },
171
+ // A drop is handed the dragged slice itself rather than markup, so what that slice
172
+ // carried is looked up by the route it left on rather than by a name written into markup
173
+ read ?? {
174
+ slice,
175
+ newLists: NO_NEW_LISTS,
176
+ noteStories: draggedNotes(
177
+ documentOf(view.state).session?.sessionId ?? null
178
+ )
179
+ },
161
180
  view.state,
162
181
  dropMove,
163
182
  normalizers
164
183
  );
165
184
  started = content.newLists;
185
+ startedStories = content.newStories ?? null;
166
186
  return content.slice;
167
187
  },
168
188
  handlePaste(view, event, slice) {
@@ -1,11 +1,12 @@
1
1
  /** Document-level readers for whether the document as it stands can be written back. */
2
2
  import type { EditorState } from "prosemirror-state";
3
3
  import { type ExportProblem } from "../../docx/invariants";
4
- export type { ExportProblem } from "../../docx/invariants";
4
+ export type { ExportPartName, ExportProblem, ExportProblemReason, ExportProblemStory, ExportStoryKind, } from "../../docx/invariants";
5
5
  /**
6
6
  * Every reason writing the document back would be refused, in the order `exportDocx` would raise
7
- * them, each with the code and message the refusal would carry and the position in the document
8
- * where there is one. Empty when the file would be written.
7
+ * them, each with the code and message the refusal would carry, the `reason` naming what it is
8
+ * about, and the position in the document where there is one. Empty when the file would be
9
+ * written.
9
10
  *
10
11
  * A state built without an opened document has no file to write back into, so nothing about it
11
12
  * can be refused and it reports no problem.
@@ -63,7 +63,7 @@ export { addComment, addCommentReply, canAddComment, canEditComment, documentCom
63
63
  * with the code `exportDocx` would throw it under. `canExport` is what an export control is
64
64
  * drawn from, and `downloadDocx` answers `blocked` with the same list.
65
65
  */
66
- export type { ExportProblem } from "./exportQueries";
66
+ export type { ExportPartName, ExportProblem, ExportProblemReason, ExportProblemStory, ExportStoryKind, } from "./exportQueries";
67
67
  export { canExport, documentExportProblems } from "./exportQueries";
68
68
  export type { FidelityCode, FidelityNote, FidelitySeverity, } from "./fidelityQueries";
69
69
  export { documentFidelity } from "./fidelityQueries";
@@ -90,6 +90,7 @@ export { activeLink, activeLinkSpan, canSetLink, removeLink, setLink, } from "./
90
90
  export { activeListKind, decreaseListLevel, increaseListLevel, isInList, toggleBulletList, toggleNumberedList, } from "./listCommands";
91
91
  export type { SelectionLock } from "./lockCommands";
92
92
  export { documentHasLocked, lockSelection, selectionLock, selectionTouchesLocked, unlockSelection, } from "./lockCommands";
93
+ export { canInsertEndnote, canInsertFootnote, insertEndnote, insertFootnote, openEndnote, openFootnote, setEndnoteBody, setFootnoteBody, } from "./noteCommands";
93
94
  export type { DocumentNote } from "./noteQueries";
94
95
  export { documentNotes } from "./noteQueries";
95
96
  export type { ActiveParagraphAlign, ActiveParagraphStyle, } from "./paragraphCommands";
@@ -81,6 +81,16 @@ import {
81
81
  selectionTouchesLocked,
82
82
  unlockSelection
83
83
  } from "./lockCommands.js";
84
+ import {
85
+ canInsertEndnote,
86
+ canInsertFootnote,
87
+ insertEndnote,
88
+ insertFootnote,
89
+ openEndnote,
90
+ openFootnote,
91
+ setEndnoteBody,
92
+ setFootnoteBody
93
+ } from "./noteCommands.js";
84
94
  import { documentNotes } from "./noteQueries.js";
85
95
  import {
86
96
  activeParagraphAlign,
@@ -117,6 +127,8 @@ export {
117
127
  canExport,
118
128
  canFormatText,
119
129
  canIncreaseIndent,
130
+ canInsertEndnote,
131
+ canInsertFootnote,
120
132
  canInsertImage,
121
133
  canInsertTable,
122
134
  canRunCommand,
@@ -139,6 +151,8 @@ export {
139
151
  imageFilesIn,
140
152
  increaseIndent,
141
153
  increaseListLevel,
154
+ insertEndnote,
155
+ insertFootnote,
142
156
  insertImage,
143
157
  insertImageFiles,
144
158
  insertLineBreak,
@@ -151,6 +165,8 @@ export {
151
165
  isStrikeActive,
152
166
  isUnderlineActive,
153
167
  lockSelection,
168
+ openEndnote,
169
+ openFootnote,
154
170
  readImageFile,
155
171
  redo,
156
172
  removeComment,
@@ -161,8 +177,10 @@ export {
161
177
  selectionTouchesLocked,
162
178
  setCommentBody,
163
179
  setCommentResolved,
180
+ setEndnoteBody,
164
181
  setFontFamily,
165
182
  setFontSize,
183
+ setFootnoteBody,
166
184
  setLineSpacing,
167
185
  setLink,
168
186
  setParagraphAlign,