@beyondwork/docx-react-component 1.0.1 → 1.0.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 (172) hide show
  1. package/README.md +44 -104
  2. package/package.json +76 -46
  3. package/src/README.md +85 -0
  4. package/src/api/README.md +22 -0
  5. package/src/api/public-types.ts +525 -0
  6. package/src/compare/diff-engine.ts +530 -0
  7. package/src/compare/export-redlines.ts +162 -0
  8. package/src/compare/snapshot.ts +37 -0
  9. package/src/component-inventory.md +99 -0
  10. package/src/core/README.md +10 -0
  11. package/src/core/commands/README.md +3 -0
  12. package/src/core/commands/formatting-commands.ts +161 -0
  13. package/src/core/commands/image-commands.ts +144 -0
  14. package/src/core/commands/index.ts +1013 -0
  15. package/src/core/commands/list-commands.ts +370 -0
  16. package/src/core/commands/review-commands.ts +108 -0
  17. package/src/core/commands/text-commands.ts +119 -0
  18. package/src/core/schema/README.md +3 -0
  19. package/src/core/schema/text-schema.ts +512 -0
  20. package/src/core/selection/README.md +3 -0
  21. package/src/core/selection/mapping.ts +238 -0
  22. package/src/core/selection/review-anchors.ts +94 -0
  23. package/src/core/state/README.md +3 -0
  24. package/src/core/state/editor-state.ts +580 -0
  25. package/src/core/state/text-transaction.ts +276 -0
  26. package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
  27. package/src/formats/xlsx/io/parse-sheet.ts +289 -0
  28. package/src/formats/xlsx/io/parse-styles.ts +57 -0
  29. package/src/formats/xlsx/io/parse-workbook.ts +75 -0
  30. package/src/formats/xlsx/io/xlsx-session.ts +306 -0
  31. package/src/formats/xlsx/model/cell.ts +189 -0
  32. package/src/formats/xlsx/model/sheet.ts +244 -0
  33. package/src/formats/xlsx/model/styles.ts +118 -0
  34. package/src/formats/xlsx/model/workbook.ts +449 -0
  35. package/src/index.ts +45 -0
  36. package/src/io/README.md +10 -0
  37. package/src/io/docx-session.ts +1763 -0
  38. package/src/io/export/README.md +3 -0
  39. package/src/io/export/export-session.ts +165 -0
  40. package/src/io/export/minimal-docx.ts +115 -0
  41. package/src/io/export/reattach-preserved-parts.ts +54 -0
  42. package/src/io/export/serialize-comments.ts +876 -0
  43. package/src/io/export/serialize-footnotes.ts +217 -0
  44. package/src/io/export/serialize-headers-footers.ts +200 -0
  45. package/src/io/export/serialize-main-document.ts +982 -0
  46. package/src/io/export/serialize-numbering.ts +97 -0
  47. package/src/io/export/serialize-revisions.ts +389 -0
  48. package/src/io/export/serialize-runtime-revisions.ts +265 -0
  49. package/src/io/export/serialize-tables.ts +147 -0
  50. package/src/io/export/split-review-boundaries.ts +194 -0
  51. package/src/io/normalize/README.md +3 -0
  52. package/src/io/normalize/normalize-text.ts +437 -0
  53. package/src/io/ooxml/README.md +3 -0
  54. package/src/io/ooxml/parse-comments.ts +779 -0
  55. package/src/io/ooxml/parse-complex-content.ts +287 -0
  56. package/src/io/ooxml/parse-fields.ts +438 -0
  57. package/src/io/ooxml/parse-footnotes.ts +403 -0
  58. package/src/io/ooxml/parse-headers-footers.ts +483 -0
  59. package/src/io/ooxml/parse-inline-media.ts +431 -0
  60. package/src/io/ooxml/parse-main-document.ts +1846 -0
  61. package/src/io/ooxml/parse-numbering.ts +425 -0
  62. package/src/io/ooxml/parse-revisions.ts +658 -0
  63. package/src/io/ooxml/parse-shapes.ts +271 -0
  64. package/src/io/ooxml/parse-tables.ts +568 -0
  65. package/src/io/ooxml/parse-theme.ts +314 -0
  66. package/src/io/ooxml/part-manifest.ts +136 -0
  67. package/src/io/ooxml/revision-boundaries.ts +351 -0
  68. package/src/io/opc/README.md +3 -0
  69. package/src/io/opc/corrupt-package.ts +166 -0
  70. package/src/io/opc/docx-package.ts +74 -0
  71. package/src/io/opc/package-reader.ts +320 -0
  72. package/src/io/opc/package-writer.ts +273 -0
  73. package/src/legal/bookmarks.ts +196 -0
  74. package/src/legal/cross-references.ts +356 -0
  75. package/src/legal/defined-terms.ts +203 -0
  76. package/src/model/README.md +3 -0
  77. package/src/model/canonical-document.ts +1911 -0
  78. package/src/model/cds-1.0.0.ts +196 -0
  79. package/src/model/snapshot.ts +393 -0
  80. package/src/preservation/README.md +3 -0
  81. package/src/preservation/markup-compatibility.ts +48 -0
  82. package/src/preservation/opaque-fragment-store.ts +89 -0
  83. package/src/preservation/opaque-region.ts +233 -0
  84. package/src/preservation/package-preservation.ts +120 -0
  85. package/src/preservation/preserved-part-manifest.ts +56 -0
  86. package/src/preservation/relationship-retention.ts +57 -0
  87. package/src/preservation/store.ts +185 -0
  88. package/src/review/README.md +16 -0
  89. package/src/review/store/README.md +3 -0
  90. package/src/review/store/comment-anchors.ts +70 -0
  91. package/src/review/store/comment-remapping.ts +154 -0
  92. package/src/review/store/comment-store.ts +331 -0
  93. package/src/review/store/comment-thread.ts +109 -0
  94. package/src/review/store/revision-actions.ts +394 -0
  95. package/src/review/store/revision-store.ts +303 -0
  96. package/src/review/store/revision-types.ts +168 -0
  97. package/src/review/store/runtime-comment-store.ts +43 -0
  98. package/src/runtime/README.md +3 -0
  99. package/src/runtime/ai-action-policy.ts +764 -0
  100. package/src/runtime/document-runtime.ts +967 -0
  101. package/src/runtime/read-only-diagnostics-runtime.ts +232 -0
  102. package/src/runtime/review-runtime.ts +44 -0
  103. package/src/runtime/revision-runtime.ts +107 -0
  104. package/src/runtime/session-capabilities.ts +138 -0
  105. package/src/runtime/surface-projection.ts +570 -0
  106. package/src/runtime/table-commands.ts +87 -0
  107. package/src/runtime/table-schema.ts +140 -0
  108. package/src/runtime/virtualized-rendering.ts +258 -0
  109. package/src/ui/README.md +30 -0
  110. package/src/ui/WordReviewEditor.tsx +1504 -0
  111. package/src/ui/comments/README.md +3 -0
  112. package/src/ui/compatibility/README.md +3 -0
  113. package/src/ui/editor-surface/README.md +3 -0
  114. package/src/ui/headless/comment-decoration-model.ts +124 -0
  115. package/src/ui/headless/revision-decoration-model.ts +128 -0
  116. package/src/ui/headless/selection-helpers.ts +34 -0
  117. package/src/ui/headless/use-editor-keyboard.ts +98 -0
  118. package/src/ui/review/README.md +3 -0
  119. package/src/ui/shared/revision-filters.ts +31 -0
  120. package/src/ui/status/README.md +3 -0
  121. package/src/ui/theme/README.md +3 -0
  122. package/src/ui/toolbar/README.md +3 -0
  123. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +48 -0
  124. package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +44 -0
  125. package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
  126. package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
  127. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +139 -0
  128. package/src/ui-tailwind/editor-surface/pm-decorations.ts +98 -0
  129. package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
  130. package/src/ui-tailwind/editor-surface/pm-schema.ts +452 -0
  131. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +327 -0
  132. package/src/ui-tailwind/editor-surface/search-plugin.ts +157 -0
  133. package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
  134. package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
  135. package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +118 -0
  136. package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +52 -0
  137. package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
  138. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +215 -0
  139. package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
  140. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +122 -0
  141. package/src/ui-tailwind/index.ts +61 -0
  142. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +276 -0
  143. package/src/ui-tailwind/review/tw-health-panel.tsx +120 -0
  144. package/src/ui-tailwind/review/tw-review-rail.tsx +120 -0
  145. package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
  146. package/src/ui-tailwind/status/tw-status-bar.tsx +58 -0
  147. package/src/ui-tailwind/theme/editor-theme.css +190 -0
  148. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +48 -0
  149. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +231 -0
  150. package/src/ui-tailwind/tw-review-workspace.tsx +140 -0
  151. package/src/validation/README.md +3 -0
  152. package/src/validation/compatibility-engine.ts +317 -0
  153. package/src/validation/compatibility-report.ts +160 -0
  154. package/src/validation/diagnostics.ts +203 -0
  155. package/src/validation/import-diagnostics.ts +128 -0
  156. package/src/validation/low-priority-word-surfaces.ts +373 -0
  157. package/dist/chunk-32W6IVQE.js +0 -7725
  158. package/dist/chunk-32W6IVQE.js.map +0 -1
  159. package/dist/index.cjs +0 -23722
  160. package/dist/index.cjs.map +0 -1
  161. package/dist/index.d.cts +0 -7
  162. package/dist/index.d.ts +0 -7
  163. package/dist/index.js +0 -16011
  164. package/dist/index.js.map +0 -1
  165. package/dist/public-types-DqCURAz8.d.cts +0 -1152
  166. package/dist/public-types-DqCURAz8.d.ts +0 -1152
  167. package/dist/tailwind.cjs +0 -8295
  168. package/dist/tailwind.cjs.map +0 -1
  169. package/dist/tailwind.d.cts +0 -323
  170. package/dist/tailwind.d.ts +0 -323
  171. package/dist/tailwind.js +0 -553
  172. package/dist/tailwind.js.map +0 -1
@@ -0,0 +1,452 @@
1
+ import { Schema } from "prosemirror-model";
2
+ import {
3
+ tableNodeSpec,
4
+ tableRowNodeSpec,
5
+ tableCellNodeSpec,
6
+ tableHeaderCellNodeSpec,
7
+ } from "../../runtime/table-schema.ts";
8
+
9
+ /**
10
+ * ProseMirror schema for the supported live surface slice.
11
+ *
12
+ * Maps canonical document node types to PM nodes and marks.
13
+ * This schema is used for rendering and input capture only —
14
+ * ProseMirror does not own the canonical document state.
15
+ */
16
+ export const editorSchema = new Schema({
17
+ nodes: {
18
+ doc: {
19
+ content: "block+",
20
+ },
21
+
22
+ paragraph: {
23
+ content: "inline*",
24
+ group: "block",
25
+ attrs: {
26
+ styleId: { default: null },
27
+ numberingInstanceId: { default: null },
28
+ numberingLevel: { default: null },
29
+ alignment: { default: null },
30
+ },
31
+ parseDOM: [{ tag: "p" }],
32
+ toDOM(node) {
33
+ const classes: string[] = ["leading-relaxed"];
34
+ const styleId = node.attrs.styleId as string | null;
35
+ if (styleId) {
36
+ const lower = styleId.toLowerCase();
37
+ if (lower === "heading1") classes.push("text-2xl font-medium");
38
+ else if (lower === "heading2") classes.push("text-xl font-medium");
39
+ else if (lower === "heading3") classes.push("text-lg font-medium");
40
+ }
41
+ const attrs: Record<string, string> = { class: classes.join(" ") };
42
+ const alignment = node.attrs.alignment as string | null;
43
+ if (alignment) attrs.style = `text-align: ${alignment}`;
44
+ return ["p", attrs, 0];
45
+ },
46
+ },
47
+
48
+ text: {
49
+ group: "inline",
50
+ },
51
+
52
+ hard_break: {
53
+ inline: true,
54
+ group: "inline",
55
+ selectable: false,
56
+ parseDOM: [{ tag: "br" }],
57
+ toDOM() {
58
+ return ["br"];
59
+ },
60
+ },
61
+
62
+ tab_char: {
63
+ inline: true,
64
+ group: "inline",
65
+ atom: true,
66
+ selectable: false,
67
+ toDOM() {
68
+ return ["span", { class: "inline-block w-8", "data-node-type": "tab" }, "\u00A0"];
69
+ },
70
+ },
71
+
72
+ image_atom: {
73
+ inline: true,
74
+ group: "inline",
75
+ atom: true,
76
+ attrs: {
77
+ mediaId: { default: "" },
78
+ altText: { default: null },
79
+ state: { default: "editable" },
80
+ display: { default: "inline" },
81
+ detail: { default: null },
82
+ },
83
+ toDOM(node) {
84
+ const isMissing = node.attrs.state === "missing";
85
+ const isFloating = node.attrs.display === "floating";
86
+ return [
87
+ "span",
88
+ {
89
+ class: `inline-flex items-center gap-1 mx-0.5 px-1.5 py-0.5 rounded text-xs border-none ${
90
+ isMissing ? "text-danger bg-delete-soft" : "text-secondary bg-surface"
91
+ }`,
92
+ "data-node-type": "image",
93
+ title: (node.attrs.detail as string) ?? (node.attrs.altText as string) ?? "Image",
94
+ },
95
+ "\uD83D\uDCF7 " + ((node.attrs.altText as string) ?? (isMissing ? "Missing" : isFloating ? "Floating image" : "Image")),
96
+ ];
97
+ },
98
+ },
99
+
100
+ sdt_block: {
101
+ group: "block",
102
+ content: "block+",
103
+ isolating: true,
104
+ attrs: {
105
+ sdtType: { default: null },
106
+ alias: { default: null },
107
+ tag: { default: null },
108
+ lock: { default: null },
109
+ },
110
+ toDOM(node) {
111
+ const meta = [node.attrs.alias, node.attrs.tag, node.attrs.sdtType].filter(Boolean).join(" · ");
112
+ return [
113
+ "section",
114
+ {
115
+ class: "my-2 rounded-xl border border-primary/15 bg-surface-raised/60 px-3 py-2",
116
+ "data-node-type": "sdt_block",
117
+ },
118
+ [
119
+ "div",
120
+ {
121
+ class: "mb-2 text-[11px] uppercase tracking-[0.18em] text-tertiary",
122
+ contenteditable: "false",
123
+ },
124
+ meta || "Content control",
125
+ ],
126
+ ["div", 0],
127
+ ];
128
+ },
129
+ },
130
+
131
+ opaque_inline: {
132
+ inline: true,
133
+ group: "inline",
134
+ atom: true,
135
+ selectable: false,
136
+ attrs: {
137
+ fragmentId: { default: "" },
138
+ warningId: { default: "" },
139
+ label: { default: "Locked" },
140
+ detail: { default: "" },
141
+ },
142
+ toDOM(node) {
143
+ return [
144
+ "span",
145
+ {
146
+ class: "inline-flex items-center gap-1 mx-0.5 px-1.5 py-0.5 rounded text-xs text-comment bg-warning-soft",
147
+ "data-node-type": "opaque_inline",
148
+ title: node.attrs.detail as string,
149
+ },
150
+ "\uD83D\uDD12 " + (node.attrs.label as string),
151
+ ];
152
+ },
153
+ },
154
+
155
+ table: tableNodeSpec,
156
+ table_row: tableRowNodeSpec,
157
+ table_cell: tableCellNodeSpec,
158
+ table_header_cell: tableHeaderCellNodeSpec,
159
+
160
+ // ---- Complex rendering atoms (read-only previews) ----
161
+
162
+ chart_atom: {
163
+ inline: true,
164
+ group: "inline",
165
+ atom: true,
166
+ selectable: false,
167
+ attrs: {
168
+ previewMediaId: { default: null },
169
+ detail: { default: null },
170
+ },
171
+ toDOM(node) {
172
+ return [
173
+ "span",
174
+ {
175
+ class: "inline-flex items-center gap-1 mx-0.5 px-1.5 py-0.5 rounded text-xs text-blue-700 bg-blue-50 border border-blue-200",
176
+ "data-node-type": "chart_atom",
177
+ contenteditable: "false",
178
+ title: (node.attrs.detail as string) ?? "Chart",
179
+ },
180
+ "\uD83D\uDCC8 Chart",
181
+ ];
182
+ },
183
+ },
184
+
185
+ smartart_atom: {
186
+ inline: true,
187
+ group: "inline",
188
+ atom: true,
189
+ selectable: false,
190
+ attrs: {
191
+ previewMediaId: { default: null },
192
+ detail: { default: null },
193
+ },
194
+ toDOM(node) {
195
+ return [
196
+ "span",
197
+ {
198
+ class: "inline-flex items-center gap-1 mx-0.5 px-1.5 py-0.5 rounded text-xs text-purple-700 bg-purple-50 border border-purple-200",
199
+ "data-node-type": "smartart_atom",
200
+ contenteditable: "false",
201
+ title: (node.attrs.detail as string) ?? "SmartArt",
202
+ },
203
+ "\uD83D\uDDFA SmartArt",
204
+ ];
205
+ },
206
+ },
207
+
208
+ shape_atom: {
209
+ inline: true,
210
+ group: "inline",
211
+ atom: true,
212
+ selectable: false,
213
+ attrs: {
214
+ text: { default: null },
215
+ geometry: { default: null },
216
+ detail: { default: null },
217
+ },
218
+ toDOM(node) {
219
+ const text = node.attrs.text as string | null;
220
+ const label = text ? `Shape: ${text}` : "Shape";
221
+ return [
222
+ "span",
223
+ {
224
+ class: "inline-flex items-center gap-1 mx-0.5 px-1.5 py-0.5 rounded text-xs text-green-700 bg-green-50 border border-green-200",
225
+ "data-node-type": "shape_atom",
226
+ contenteditable: "false",
227
+ title: (node.attrs.detail as string) ?? label,
228
+ },
229
+ "\u25A1 " + label,
230
+ ];
231
+ },
232
+ },
233
+
234
+ wordart_atom: {
235
+ inline: true,
236
+ group: "inline",
237
+ atom: true,
238
+ selectable: false,
239
+ attrs: {
240
+ text: { default: "" },
241
+ geometry: { default: null },
242
+ detail: { default: null },
243
+ },
244
+ toDOM(node) {
245
+ const text = node.attrs.text as string;
246
+ return [
247
+ "span",
248
+ {
249
+ class: "inline-flex items-center gap-1 mx-0.5 px-1.5 py-0.5 rounded text-xs text-orange-700 bg-orange-50 border border-orange-200 font-medium italic",
250
+ "data-node-type": "wordart_atom",
251
+ contenteditable: "false",
252
+ title: (node.attrs.detail as string) ?? `WordArt: ${text}`,
253
+ },
254
+ "\u2728 " + (text || "WordArt"),
255
+ ];
256
+ },
257
+ },
258
+
259
+ vml_atom: {
260
+ inline: true,
261
+ group: "inline",
262
+ atom: true,
263
+ selectable: false,
264
+ attrs: {
265
+ text: { default: null },
266
+ shapeType: { default: null },
267
+ detail: { default: null },
268
+ },
269
+ toDOM(node) {
270
+ const text = node.attrs.text as string | null;
271
+ const label = text ? `VML: ${text}` : "VML shape";
272
+ return [
273
+ "span",
274
+ {
275
+ class: "inline-flex items-center gap-1 mx-0.5 px-1.5 py-0.5 rounded text-xs text-gray-600 bg-gray-100 border border-gray-300",
276
+ "data-node-type": "vml_atom",
277
+ contenteditable: "false",
278
+ title: (node.attrs.detail as string) ?? label,
279
+ },
280
+ "\u25A6 " + label,
281
+ ];
282
+ },
283
+ },
284
+
285
+ opaque_block: {
286
+ group: "block",
287
+ atom: true,
288
+ selectable: false,
289
+ attrs: {
290
+ fragmentId: { default: "" },
291
+ warningId: { default: "" },
292
+ label: { default: "Locked" },
293
+ detail: { default: "" },
294
+ },
295
+ toDOM(node) {
296
+ return [
297
+ "div",
298
+ {
299
+ class: "border-l-2 border-dashed border-warning/30 pl-4 py-2 rounded-r bg-warning-soft/20 my-2",
300
+ contenteditable: "false",
301
+ "data-node-type": "opaque_block",
302
+ },
303
+ [
304
+ "div",
305
+ { class: "flex items-center gap-1.5 text-xs text-tertiary mb-1" },
306
+ "\uD83D\uDD12 " + (node.attrs.label as string),
307
+ ],
308
+ ["p", { class: "text-sm text-secondary" }, node.attrs.detail as string],
309
+ ];
310
+ },
311
+ },
312
+ },
313
+
314
+ marks: {
315
+ bold: {
316
+ parseDOM: [{ tag: "strong" }, { tag: "b" }],
317
+ toDOM() {
318
+ return ["strong", 0];
319
+ },
320
+ },
321
+ italic: {
322
+ parseDOM: [{ tag: "em" }, { tag: "i" }],
323
+ toDOM() {
324
+ return ["em", 0];
325
+ },
326
+ },
327
+ underline: {
328
+ parseDOM: [{ tag: "u" }],
329
+ toDOM() {
330
+ return ["u", 0];
331
+ },
332
+ },
333
+ strikethrough: {
334
+ parseDOM: [{ tag: "s" }, { tag: "del" }],
335
+ toDOM() {
336
+ return ["s", 0];
337
+ },
338
+ },
339
+ superscript: {
340
+ excludes: "subscript",
341
+ parseDOM: [{ tag: "sup" }],
342
+ toDOM() {
343
+ return ["sup", 0];
344
+ },
345
+ },
346
+ subscript: {
347
+ excludes: "superscript",
348
+ parseDOM: [{ tag: "sub" }],
349
+ toDOM() {
350
+ return ["sub", 0];
351
+ },
352
+ },
353
+ small_caps: {
354
+ parseDOM: [
355
+ {
356
+ style: "font-variant",
357
+ getAttrs: (value) => (value === "small-caps" ? null : false),
358
+ },
359
+ ],
360
+ toDOM() {
361
+ return ["span", { style: "font-variant: small-caps" }, 0];
362
+ },
363
+ },
364
+ all_caps: {
365
+ parseDOM: [
366
+ {
367
+ style: "text-transform",
368
+ getAttrs: (value) => (value === "uppercase" ? null : false),
369
+ },
370
+ ],
371
+ toDOM() {
372
+ return ["span", { style: "text-transform: uppercase" }, 0];
373
+ },
374
+ },
375
+ font_family: {
376
+ attrs: { family: { default: null } },
377
+ parseDOM: [
378
+ {
379
+ style: "font-family",
380
+ getAttrs: (value) => ({ family: (value as string).replace(/['"]/g, "") }),
381
+ },
382
+ ],
383
+ toDOM(mark) {
384
+ return ["span", { style: `font-family: ${mark.attrs.family as string}` }, 0];
385
+ },
386
+ },
387
+ font_size: {
388
+ attrs: { size: { default: null } },
389
+ parseDOM: [
390
+ {
391
+ style: "font-size",
392
+ getAttrs: (value) => {
393
+ const match = (value as string).match(/^(\d+(?:\.\d+)?)/);
394
+ return match ? { size: Number.parseFloat(match[1]) } : false;
395
+ },
396
+ },
397
+ ],
398
+ toDOM(mark) {
399
+ return ["span", { style: `font-size: ${mark.attrs.size as number}pt` }, 0];
400
+ },
401
+ },
402
+ text_color: {
403
+ attrs: { color: { default: null } },
404
+ parseDOM: [
405
+ {
406
+ style: "color",
407
+ getAttrs: (value) => ({ color: value }),
408
+ },
409
+ ],
410
+ toDOM(mark) {
411
+ const color = mark.attrs.color as string;
412
+ return ["span", { style: `color: ${color}` }, 0];
413
+ },
414
+ },
415
+ highlight: {
416
+ attrs: { color: { default: "yellow" } },
417
+ parseDOM: [
418
+ {
419
+ tag: "mark",
420
+ getAttrs: (dom) => ({ color: (dom as HTMLElement).style.backgroundColor || "yellow" }),
421
+ },
422
+ ],
423
+ toDOM(mark) {
424
+ return ["mark", { style: `background-color: ${mark.attrs.color as string}` }, 0];
425
+ },
426
+ },
427
+ link: {
428
+ attrs: { href: { default: "" } },
429
+ inclusive: false,
430
+ parseDOM: [
431
+ {
432
+ tag: "a[href]",
433
+ getAttrs(dom) {
434
+ return { href: (dom as HTMLElement).getAttribute("href") };
435
+ },
436
+ },
437
+ ],
438
+ toDOM(mark) {
439
+ return [
440
+ "a",
441
+ {
442
+ href: mark.attrs.href as string,
443
+ class: "text-accent underline decoration-1 underline-offset-2",
444
+ target: "_blank",
445
+ rel: "noopener noreferrer",
446
+ },
447
+ 0,
448
+ ];
449
+ },
450
+ },
451
+ },
452
+ });