@shadow-garden/bapbong-model 0.1.0 → 0.2.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/dist/index.cjs +130 -25
- package/dist/index.js +130 -25
- package/dist/lib/model.d.ts +1 -0
- package/dist/lib/model.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,30 @@ module.exports = __toCommonJS(index_exports);
|
|
|
28
28
|
|
|
29
29
|
// packages/model/src/lib/model.ts
|
|
30
30
|
var import_prosemirror_model = require("prosemirror-model");
|
|
31
|
+
function pastedParagraphAttrs(el, heading) {
|
|
32
|
+
const style = el.getAttribute("style") ?? "";
|
|
33
|
+
const m = /(?:^|;)\s*text-align\s*:\s*(center|right|justify)/i.exec(style);
|
|
34
|
+
return { heading, align: m ? m[1].toLowerCase() : null };
|
|
35
|
+
}
|
|
36
|
+
function pastedImageAttrs(el) {
|
|
37
|
+
const e = el;
|
|
38
|
+
const src = e.getAttribute("src") ?? "";
|
|
39
|
+
if (!/^data:image\//i.test(src)) return false;
|
|
40
|
+
const dim = (v) => {
|
|
41
|
+
const n = parseFloat(v ?? "");
|
|
42
|
+
return Number.isFinite(n) && n > 0 ? Math.round(n) : null;
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
src,
|
|
46
|
+
alt: e.getAttribute("alt") ?? "",
|
|
47
|
+
width: dim(e.getAttribute("width")),
|
|
48
|
+
height: dim(e.getAttribute("height"))
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function pastedLinkAttrs(el) {
|
|
52
|
+
const href = (el.getAttribute("href") ?? "").trim();
|
|
53
|
+
return /^(https?:|mailto:|#)/i.test(href) ? { href } : false;
|
|
54
|
+
}
|
|
31
55
|
var schema = new import_prosemirror_model.Schema({
|
|
32
56
|
nodes: {
|
|
33
57
|
doc: {
|
|
@@ -63,23 +87,39 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
63
87
|
// an <h1>–<h6> in toDOM so the a11y mirror is semantic), or null for a
|
|
64
88
|
// body paragraph.
|
|
65
89
|
heading: { default: null },
|
|
90
|
+
// Named Word paragraph style with no outline level: 'Title' |
|
|
91
|
+
// 'Subtitle', or null. Mutually exclusive with `heading` — the
|
|
92
|
+
// setParagraphStyle command is the only writer and keeps the
|
|
93
|
+
// invariant (styleId set ⇒ heading null).
|
|
94
|
+
styleId: { default: null },
|
|
66
95
|
// w:tabs — [{ pos, val: 'left'|'right'|'center'|'decimal', leader? }]
|
|
67
96
|
// in px from the paragraph's content left edge, or null. Importer-set.
|
|
68
97
|
tabs: { default: null },
|
|
69
98
|
// w:spacing — { before?, after?, line?, lineRule? }, or null.
|
|
70
99
|
spacing: { default: null },
|
|
71
100
|
// w:pageBreakBefore — start this paragraph on a new page.
|
|
72
|
-
pageBreakBefore: { default: false }
|
|
101
|
+
pageBreakBefore: { default: false },
|
|
102
|
+
// w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
|
|
103
|
+
// Importer-set; painted as a box around the paragraph's lines.
|
|
104
|
+
borders: { default: null }
|
|
73
105
|
},
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
parseDOM: [
|
|
106
|
+
// HTML paste path: recover heading level from h1–h6 and alignment from
|
|
107
|
+
// inline style. Other attrs (list/indent/tabs/spacing) stay importer-only
|
|
108
|
+
// — pasted HTML rarely carries them faithfully.
|
|
109
|
+
parseDOM: [
|
|
110
|
+
{ tag: "p", getAttrs: (el) => pastedParagraphAttrs(el, null) },
|
|
111
|
+
...[1, 2, 3, 4, 5, 6].map((level) => ({
|
|
112
|
+
tag: `h${level}`,
|
|
113
|
+
getAttrs: (el) => pastedParagraphAttrs(el, level)
|
|
114
|
+
}))
|
|
115
|
+
],
|
|
78
116
|
toDOM(node) {
|
|
79
117
|
const attrs = node.attrs;
|
|
80
118
|
const style = paragraphStyle(attrs);
|
|
81
119
|
const tag = attrs.heading ? `h${attrs.heading}` : "p";
|
|
82
|
-
|
|
120
|
+
const dom = style ? { style } : {};
|
|
121
|
+
if (attrs.styleId) dom["data-style"] = attrs.styleId;
|
|
122
|
+
return [tag, dom, 0];
|
|
83
123
|
}
|
|
84
124
|
},
|
|
85
125
|
text: { group: "inline" },
|
|
@@ -119,9 +159,13 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
119
159
|
// Paint-only: the layout box stays axis-aligned.
|
|
120
160
|
rotation: { default: 0 }
|
|
121
161
|
},
|
|
162
|
+
parseDOM: [{ tag: "img[src]", getAttrs: pastedImageAttrs }],
|
|
122
163
|
toDOM(node) {
|
|
123
164
|
const a = node.attrs;
|
|
124
|
-
const attrs = {
|
|
165
|
+
const attrs = {
|
|
166
|
+
src: a["src"],
|
|
167
|
+
alt: a["alt"]
|
|
168
|
+
};
|
|
125
169
|
if (a["width"] != null) attrs["width"] = String(a["width"]);
|
|
126
170
|
if (a["height"] != null) attrs["height"] = String(a["height"]);
|
|
127
171
|
return ["img", attrs];
|
|
@@ -158,7 +202,11 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
158
202
|
align: { default: null }
|
|
159
203
|
},
|
|
160
204
|
parseDOM: [{ tag: "table" }],
|
|
161
|
-
toDOM: (node) => [
|
|
205
|
+
toDOM: (node) => [
|
|
206
|
+
"table",
|
|
207
|
+
node.attrs["borders"] ? { "data-borders": "1" } : {},
|
|
208
|
+
["tbody", 0]
|
|
209
|
+
]
|
|
162
210
|
},
|
|
163
211
|
table_row: {
|
|
164
212
|
content: "table_cell+",
|
|
@@ -188,15 +236,20 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
188
236
|
// w:shd w:fill — cell fill "#RRGGBB"
|
|
189
237
|
vAlign: { default: null },
|
|
190
238
|
// w:vAlign — 'center' | 'bottom' (top default)
|
|
191
|
-
borders: { default: null }
|
|
239
|
+
borders: { default: null },
|
|
192
240
|
// w:tcBorders per-side visibility override
|
|
241
|
+
padding: { default: null }
|
|
242
|
+
// w:tcMar per-side margin override (px)
|
|
193
243
|
},
|
|
194
244
|
parseDOM: [{ tag: "td" }, { tag: "th" }],
|
|
195
245
|
toDOM(node) {
|
|
196
246
|
const attrs = {};
|
|
197
|
-
if (node.attrs["colspan"] !== 1)
|
|
198
|
-
|
|
199
|
-
if (node.attrs["
|
|
247
|
+
if (node.attrs["colspan"] !== 1)
|
|
248
|
+
attrs["colspan"] = String(node.attrs["colspan"]);
|
|
249
|
+
if (node.attrs["rowspan"] !== 1)
|
|
250
|
+
attrs["rowspan"] = String(node.attrs["rowspan"]);
|
|
251
|
+
if (node.attrs["background"])
|
|
252
|
+
attrs["style"] = `background-color: ${node.attrs["background"]}`;
|
|
200
253
|
return ["td", attrs, 0];
|
|
201
254
|
}
|
|
202
255
|
}
|
|
@@ -225,9 +278,15 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
225
278
|
// w:color — hex "#RRGGBB"
|
|
226
279
|
textColor: {
|
|
227
280
|
attrs: { color: {} },
|
|
228
|
-
parseDOM: [
|
|
281
|
+
parseDOM: [
|
|
282
|
+
{ style: "color", getAttrs: (value) => ({ color: value }) }
|
|
283
|
+
],
|
|
229
284
|
toDOM(mark) {
|
|
230
|
-
return [
|
|
285
|
+
return [
|
|
286
|
+
"span",
|
|
287
|
+
{ style: `color: ${mark.attrs["color"]}` },
|
|
288
|
+
0
|
|
289
|
+
];
|
|
231
290
|
}
|
|
232
291
|
},
|
|
233
292
|
// w:sz — size in points
|
|
@@ -243,7 +302,11 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
243
302
|
}
|
|
244
303
|
],
|
|
245
304
|
toDOM(mark) {
|
|
246
|
-
return [
|
|
305
|
+
return [
|
|
306
|
+
"span",
|
|
307
|
+
{ style: `font-size: ${mark.attrs["size"]}pt` },
|
|
308
|
+
0
|
|
309
|
+
];
|
|
247
310
|
}
|
|
248
311
|
},
|
|
249
312
|
// w:vertAlign — superscript / subscript
|
|
@@ -260,26 +323,51 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
260
323
|
highlight: {
|
|
261
324
|
attrs: { color: {} },
|
|
262
325
|
parseDOM: [
|
|
263
|
-
{
|
|
326
|
+
{
|
|
327
|
+
style: "background-color",
|
|
328
|
+
getAttrs: (value) => ({ color: value })
|
|
329
|
+
}
|
|
264
330
|
],
|
|
265
331
|
toDOM(mark) {
|
|
266
|
-
return [
|
|
332
|
+
return [
|
|
333
|
+
"span",
|
|
334
|
+
{ style: `background-color: ${mark.attrs["color"]}` },
|
|
335
|
+
0
|
|
336
|
+
];
|
|
267
337
|
}
|
|
268
338
|
},
|
|
269
339
|
// w:rFonts — font family
|
|
270
340
|
fontFamily: {
|
|
271
341
|
attrs: { family: {} },
|
|
272
|
-
parseDOM: [
|
|
342
|
+
parseDOM: [
|
|
343
|
+
{
|
|
344
|
+
style: "font-family",
|
|
345
|
+
getAttrs: (value) => ({ family: value })
|
|
346
|
+
}
|
|
347
|
+
],
|
|
273
348
|
toDOM(mark) {
|
|
274
|
-
return [
|
|
349
|
+
return [
|
|
350
|
+
"span",
|
|
351
|
+
{ style: `font-family: ${mark.attrs["family"]}` },
|
|
352
|
+
0
|
|
353
|
+
];
|
|
275
354
|
}
|
|
276
355
|
},
|
|
277
356
|
// w:hyperlink — external URL or "#anchor"
|
|
278
357
|
link: {
|
|
279
358
|
attrs: { href: {} },
|
|
280
359
|
inclusive: false,
|
|
360
|
+
parseDOM: [{ tag: "a[href]", getAttrs: pastedLinkAttrs }],
|
|
281
361
|
toDOM(mark) {
|
|
282
|
-
return [
|
|
362
|
+
return [
|
|
363
|
+
"a",
|
|
364
|
+
{
|
|
365
|
+
href: mark.attrs["href"],
|
|
366
|
+
rel: "noopener",
|
|
367
|
+
target: "_blank"
|
|
368
|
+
},
|
|
369
|
+
0
|
|
370
|
+
];
|
|
283
371
|
}
|
|
284
372
|
},
|
|
285
373
|
// w:footnoteReference — the carrier text is the superscript number; `num`
|
|
@@ -293,12 +381,20 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
293
381
|
// `el` is an HTMLElement at runtime; this package has no DOM lib, so
|
|
294
382
|
// narrow structurally rather than naming the type.
|
|
295
383
|
getAttrs: (el) => ({
|
|
296
|
-
num: Number(
|
|
384
|
+
num: Number(
|
|
385
|
+
el.getAttribute(
|
|
386
|
+
"data-footnote"
|
|
387
|
+
)
|
|
388
|
+
) || 0
|
|
297
389
|
})
|
|
298
390
|
}
|
|
299
391
|
],
|
|
300
392
|
toDOM(mark) {
|
|
301
|
-
return [
|
|
393
|
+
return [
|
|
394
|
+
"sup",
|
|
395
|
+
{ "data-footnote": String(mark.attrs["num"]) },
|
|
396
|
+
0
|
|
397
|
+
];
|
|
302
398
|
}
|
|
303
399
|
}
|
|
304
400
|
// The `comment` mark (w:commentRangeStart/End) is contributed by the comment
|
|
@@ -311,7 +407,12 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
311
407
|
var commentSchema = new import_prosemirror_model.Schema({
|
|
312
408
|
nodes: {
|
|
313
409
|
doc: { content: "block+" },
|
|
314
|
-
paragraph: {
|
|
410
|
+
paragraph: {
|
|
411
|
+
group: "block",
|
|
412
|
+
content: "inline*",
|
|
413
|
+
parseDOM: [{ tag: "p" }],
|
|
414
|
+
toDOM: () => ["p", 0]
|
|
415
|
+
},
|
|
315
416
|
text: { group: "inline" },
|
|
316
417
|
// @mention: an inline atom carrying the mentioned user's id + display name.
|
|
317
418
|
// `leafText` lets textContent include "@Name" (search / plain-text preview).
|
|
@@ -332,7 +433,10 @@ var commentSchema = new import_prosemirror_model.Schema({
|
|
|
332
433
|
tag: "span.mention",
|
|
333
434
|
getAttrs: (el) => {
|
|
334
435
|
const e = el;
|
|
335
|
-
return {
|
|
436
|
+
return {
|
|
437
|
+
id: e.getAttribute("data-id"),
|
|
438
|
+
label: (e.textContent ?? "").replace(/^@/, "")
|
|
439
|
+
};
|
|
336
440
|
}
|
|
337
441
|
}
|
|
338
442
|
]
|
|
@@ -354,7 +458,8 @@ function paragraphStyle(attrs) {
|
|
|
354
458
|
if (sp) {
|
|
355
459
|
if (sp.before) parts.push(`margin-top: ${sp.before}px`);
|
|
356
460
|
if (sp.after) parts.push(`margin-bottom: ${sp.after}px`);
|
|
357
|
-
if (sp.line && sp.lineRule === "auto")
|
|
461
|
+
if (sp.line && sp.lineRule === "auto")
|
|
462
|
+
parts.push(`line-height: ${sp.line}`);
|
|
358
463
|
else if (sp.line) parts.push(`line-height: ${sp.line}px`);
|
|
359
464
|
}
|
|
360
465
|
return parts.join("; ");
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
// packages/model/src/lib/model.ts
|
|
2
2
|
import { Schema } from "prosemirror-model";
|
|
3
|
+
function pastedParagraphAttrs(el, heading) {
|
|
4
|
+
const style = el.getAttribute("style") ?? "";
|
|
5
|
+
const m = /(?:^|;)\s*text-align\s*:\s*(center|right|justify)/i.exec(style);
|
|
6
|
+
return { heading, align: m ? m[1].toLowerCase() : null };
|
|
7
|
+
}
|
|
8
|
+
function pastedImageAttrs(el) {
|
|
9
|
+
const e = el;
|
|
10
|
+
const src = e.getAttribute("src") ?? "";
|
|
11
|
+
if (!/^data:image\//i.test(src)) return false;
|
|
12
|
+
const dim = (v) => {
|
|
13
|
+
const n = parseFloat(v ?? "");
|
|
14
|
+
return Number.isFinite(n) && n > 0 ? Math.round(n) : null;
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
src,
|
|
18
|
+
alt: e.getAttribute("alt") ?? "",
|
|
19
|
+
width: dim(e.getAttribute("width")),
|
|
20
|
+
height: dim(e.getAttribute("height"))
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function pastedLinkAttrs(el) {
|
|
24
|
+
const href = (el.getAttribute("href") ?? "").trim();
|
|
25
|
+
return /^(https?:|mailto:|#)/i.test(href) ? { href } : false;
|
|
26
|
+
}
|
|
3
27
|
var schema = new Schema({
|
|
4
28
|
nodes: {
|
|
5
29
|
doc: {
|
|
@@ -35,23 +59,39 @@ var schema = new Schema({
|
|
|
35
59
|
// an <h1>–<h6> in toDOM so the a11y mirror is semantic), or null for a
|
|
36
60
|
// body paragraph.
|
|
37
61
|
heading: { default: null },
|
|
62
|
+
// Named Word paragraph style with no outline level: 'Title' |
|
|
63
|
+
// 'Subtitle', or null. Mutually exclusive with `heading` — the
|
|
64
|
+
// setParagraphStyle command is the only writer and keeps the
|
|
65
|
+
// invariant (styleId set ⇒ heading null).
|
|
66
|
+
styleId: { default: null },
|
|
38
67
|
// w:tabs — [{ pos, val: 'left'|'right'|'center'|'decimal', leader? }]
|
|
39
68
|
// in px from the paragraph's content left edge, or null. Importer-set.
|
|
40
69
|
tabs: { default: null },
|
|
41
70
|
// w:spacing — { before?, after?, line?, lineRule? }, or null.
|
|
42
71
|
spacing: { default: null },
|
|
43
72
|
// w:pageBreakBefore — start this paragraph on a new page.
|
|
44
|
-
pageBreakBefore: { default: false }
|
|
73
|
+
pageBreakBefore: { default: false },
|
|
74
|
+
// w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
|
|
75
|
+
// Importer-set; painted as a box around the paragraph's lines.
|
|
76
|
+
borders: { default: null }
|
|
45
77
|
},
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
parseDOM: [
|
|
78
|
+
// HTML paste path: recover heading level from h1–h6 and alignment from
|
|
79
|
+
// inline style. Other attrs (list/indent/tabs/spacing) stay importer-only
|
|
80
|
+
// — pasted HTML rarely carries them faithfully.
|
|
81
|
+
parseDOM: [
|
|
82
|
+
{ tag: "p", getAttrs: (el) => pastedParagraphAttrs(el, null) },
|
|
83
|
+
...[1, 2, 3, 4, 5, 6].map((level) => ({
|
|
84
|
+
tag: `h${level}`,
|
|
85
|
+
getAttrs: (el) => pastedParagraphAttrs(el, level)
|
|
86
|
+
}))
|
|
87
|
+
],
|
|
50
88
|
toDOM(node) {
|
|
51
89
|
const attrs = node.attrs;
|
|
52
90
|
const style = paragraphStyle(attrs);
|
|
53
91
|
const tag = attrs.heading ? `h${attrs.heading}` : "p";
|
|
54
|
-
|
|
92
|
+
const dom = style ? { style } : {};
|
|
93
|
+
if (attrs.styleId) dom["data-style"] = attrs.styleId;
|
|
94
|
+
return [tag, dom, 0];
|
|
55
95
|
}
|
|
56
96
|
},
|
|
57
97
|
text: { group: "inline" },
|
|
@@ -91,9 +131,13 @@ var schema = new Schema({
|
|
|
91
131
|
// Paint-only: the layout box stays axis-aligned.
|
|
92
132
|
rotation: { default: 0 }
|
|
93
133
|
},
|
|
134
|
+
parseDOM: [{ tag: "img[src]", getAttrs: pastedImageAttrs }],
|
|
94
135
|
toDOM(node) {
|
|
95
136
|
const a = node.attrs;
|
|
96
|
-
const attrs = {
|
|
137
|
+
const attrs = {
|
|
138
|
+
src: a["src"],
|
|
139
|
+
alt: a["alt"]
|
|
140
|
+
};
|
|
97
141
|
if (a["width"] != null) attrs["width"] = String(a["width"]);
|
|
98
142
|
if (a["height"] != null) attrs["height"] = String(a["height"]);
|
|
99
143
|
return ["img", attrs];
|
|
@@ -130,7 +174,11 @@ var schema = new Schema({
|
|
|
130
174
|
align: { default: null }
|
|
131
175
|
},
|
|
132
176
|
parseDOM: [{ tag: "table" }],
|
|
133
|
-
toDOM: (node) => [
|
|
177
|
+
toDOM: (node) => [
|
|
178
|
+
"table",
|
|
179
|
+
node.attrs["borders"] ? { "data-borders": "1" } : {},
|
|
180
|
+
["tbody", 0]
|
|
181
|
+
]
|
|
134
182
|
},
|
|
135
183
|
table_row: {
|
|
136
184
|
content: "table_cell+",
|
|
@@ -160,15 +208,20 @@ var schema = new Schema({
|
|
|
160
208
|
// w:shd w:fill — cell fill "#RRGGBB"
|
|
161
209
|
vAlign: { default: null },
|
|
162
210
|
// w:vAlign — 'center' | 'bottom' (top default)
|
|
163
|
-
borders: { default: null }
|
|
211
|
+
borders: { default: null },
|
|
164
212
|
// w:tcBorders per-side visibility override
|
|
213
|
+
padding: { default: null }
|
|
214
|
+
// w:tcMar per-side margin override (px)
|
|
165
215
|
},
|
|
166
216
|
parseDOM: [{ tag: "td" }, { tag: "th" }],
|
|
167
217
|
toDOM(node) {
|
|
168
218
|
const attrs = {};
|
|
169
|
-
if (node.attrs["colspan"] !== 1)
|
|
170
|
-
|
|
171
|
-
if (node.attrs["
|
|
219
|
+
if (node.attrs["colspan"] !== 1)
|
|
220
|
+
attrs["colspan"] = String(node.attrs["colspan"]);
|
|
221
|
+
if (node.attrs["rowspan"] !== 1)
|
|
222
|
+
attrs["rowspan"] = String(node.attrs["rowspan"]);
|
|
223
|
+
if (node.attrs["background"])
|
|
224
|
+
attrs["style"] = `background-color: ${node.attrs["background"]}`;
|
|
172
225
|
return ["td", attrs, 0];
|
|
173
226
|
}
|
|
174
227
|
}
|
|
@@ -197,9 +250,15 @@ var schema = new Schema({
|
|
|
197
250
|
// w:color — hex "#RRGGBB"
|
|
198
251
|
textColor: {
|
|
199
252
|
attrs: { color: {} },
|
|
200
|
-
parseDOM: [
|
|
253
|
+
parseDOM: [
|
|
254
|
+
{ style: "color", getAttrs: (value) => ({ color: value }) }
|
|
255
|
+
],
|
|
201
256
|
toDOM(mark) {
|
|
202
|
-
return [
|
|
257
|
+
return [
|
|
258
|
+
"span",
|
|
259
|
+
{ style: `color: ${mark.attrs["color"]}` },
|
|
260
|
+
0
|
|
261
|
+
];
|
|
203
262
|
}
|
|
204
263
|
},
|
|
205
264
|
// w:sz — size in points
|
|
@@ -215,7 +274,11 @@ var schema = new Schema({
|
|
|
215
274
|
}
|
|
216
275
|
],
|
|
217
276
|
toDOM(mark) {
|
|
218
|
-
return [
|
|
277
|
+
return [
|
|
278
|
+
"span",
|
|
279
|
+
{ style: `font-size: ${mark.attrs["size"]}pt` },
|
|
280
|
+
0
|
|
281
|
+
];
|
|
219
282
|
}
|
|
220
283
|
},
|
|
221
284
|
// w:vertAlign — superscript / subscript
|
|
@@ -232,26 +295,51 @@ var schema = new Schema({
|
|
|
232
295
|
highlight: {
|
|
233
296
|
attrs: { color: {} },
|
|
234
297
|
parseDOM: [
|
|
235
|
-
{
|
|
298
|
+
{
|
|
299
|
+
style: "background-color",
|
|
300
|
+
getAttrs: (value) => ({ color: value })
|
|
301
|
+
}
|
|
236
302
|
],
|
|
237
303
|
toDOM(mark) {
|
|
238
|
-
return [
|
|
304
|
+
return [
|
|
305
|
+
"span",
|
|
306
|
+
{ style: `background-color: ${mark.attrs["color"]}` },
|
|
307
|
+
0
|
|
308
|
+
];
|
|
239
309
|
}
|
|
240
310
|
},
|
|
241
311
|
// w:rFonts — font family
|
|
242
312
|
fontFamily: {
|
|
243
313
|
attrs: { family: {} },
|
|
244
|
-
parseDOM: [
|
|
314
|
+
parseDOM: [
|
|
315
|
+
{
|
|
316
|
+
style: "font-family",
|
|
317
|
+
getAttrs: (value) => ({ family: value })
|
|
318
|
+
}
|
|
319
|
+
],
|
|
245
320
|
toDOM(mark) {
|
|
246
|
-
return [
|
|
321
|
+
return [
|
|
322
|
+
"span",
|
|
323
|
+
{ style: `font-family: ${mark.attrs["family"]}` },
|
|
324
|
+
0
|
|
325
|
+
];
|
|
247
326
|
}
|
|
248
327
|
},
|
|
249
328
|
// w:hyperlink — external URL or "#anchor"
|
|
250
329
|
link: {
|
|
251
330
|
attrs: { href: {} },
|
|
252
331
|
inclusive: false,
|
|
332
|
+
parseDOM: [{ tag: "a[href]", getAttrs: pastedLinkAttrs }],
|
|
253
333
|
toDOM(mark) {
|
|
254
|
-
return [
|
|
334
|
+
return [
|
|
335
|
+
"a",
|
|
336
|
+
{
|
|
337
|
+
href: mark.attrs["href"],
|
|
338
|
+
rel: "noopener",
|
|
339
|
+
target: "_blank"
|
|
340
|
+
},
|
|
341
|
+
0
|
|
342
|
+
];
|
|
255
343
|
}
|
|
256
344
|
},
|
|
257
345
|
// w:footnoteReference — the carrier text is the superscript number; `num`
|
|
@@ -265,12 +353,20 @@ var schema = new Schema({
|
|
|
265
353
|
// `el` is an HTMLElement at runtime; this package has no DOM lib, so
|
|
266
354
|
// narrow structurally rather than naming the type.
|
|
267
355
|
getAttrs: (el) => ({
|
|
268
|
-
num: Number(
|
|
356
|
+
num: Number(
|
|
357
|
+
el.getAttribute(
|
|
358
|
+
"data-footnote"
|
|
359
|
+
)
|
|
360
|
+
) || 0
|
|
269
361
|
})
|
|
270
362
|
}
|
|
271
363
|
],
|
|
272
364
|
toDOM(mark) {
|
|
273
|
-
return [
|
|
365
|
+
return [
|
|
366
|
+
"sup",
|
|
367
|
+
{ "data-footnote": String(mark.attrs["num"]) },
|
|
368
|
+
0
|
|
369
|
+
];
|
|
274
370
|
}
|
|
275
371
|
}
|
|
276
372
|
// The `comment` mark (w:commentRangeStart/End) is contributed by the comment
|
|
@@ -283,7 +379,12 @@ var schema = new Schema({
|
|
|
283
379
|
var commentSchema = new Schema({
|
|
284
380
|
nodes: {
|
|
285
381
|
doc: { content: "block+" },
|
|
286
|
-
paragraph: {
|
|
382
|
+
paragraph: {
|
|
383
|
+
group: "block",
|
|
384
|
+
content: "inline*",
|
|
385
|
+
parseDOM: [{ tag: "p" }],
|
|
386
|
+
toDOM: () => ["p", 0]
|
|
387
|
+
},
|
|
287
388
|
text: { group: "inline" },
|
|
288
389
|
// @mention: an inline atom carrying the mentioned user's id + display name.
|
|
289
390
|
// `leafText` lets textContent include "@Name" (search / plain-text preview).
|
|
@@ -304,7 +405,10 @@ var commentSchema = new Schema({
|
|
|
304
405
|
tag: "span.mention",
|
|
305
406
|
getAttrs: (el) => {
|
|
306
407
|
const e = el;
|
|
307
|
-
return {
|
|
408
|
+
return {
|
|
409
|
+
id: e.getAttribute("data-id"),
|
|
410
|
+
label: (e.textContent ?? "").replace(/^@/, "")
|
|
411
|
+
};
|
|
308
412
|
}
|
|
309
413
|
}
|
|
310
414
|
]
|
|
@@ -326,7 +430,8 @@ function paragraphStyle(attrs) {
|
|
|
326
430
|
if (sp) {
|
|
327
431
|
if (sp.before) parts.push(`margin-top: ${sp.before}px`);
|
|
328
432
|
if (sp.after) parts.push(`margin-bottom: ${sp.after}px`);
|
|
329
|
-
if (sp.line && sp.lineRule === "auto")
|
|
433
|
+
if (sp.line && sp.lineRule === "auto")
|
|
434
|
+
parts.push(`line-height: ${sp.line}`);
|
|
330
435
|
else if (sp.line) parts.push(`line-height: ${sp.line}px`);
|
|
331
436
|
}
|
|
332
437
|
return parts.join("; ");
|
package/dist/lib/model.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export interface ParagraphAttrs {
|
|
|
42
42
|
indent: Indent | null;
|
|
43
43
|
spacing?: Spacing | null;
|
|
44
44
|
heading?: number | null;
|
|
45
|
+
styleId?: 'Title' | 'Subtitle' | null;
|
|
45
46
|
}
|
|
46
47
|
/** Value of a list paragraph's `list` attribute. The marker string ("1.",
|
|
47
48
|
* "2.a", "•") is NOT stored — it's recomputed at layout time from the doc's
|
package/dist/lib/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/lib/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/lib/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA0C3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,2PAkWjB,CAAC;AAEH,wEAAwE;AACxE,MAAM,MAAM,aAAa,GAAG,OAAO,MAAM,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,aAAa,yDA0CxB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC;AAEjD,qDAAqD;AACrD,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE5D;+EAC+E;AAC/E,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,2EAA2E;AAC3E,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;CACvC;AA0BD;;;4EAG4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|