@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 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
- // No getAttrs: nothing in the pipeline parses paragraphs from the DOM
75
- // yet (the importer builds nodes directly). align/indent still round-trip
76
- // out through toDOM. Revisit when HTML paste lands.
77
- parseDOM: [{ tag: "p" }],
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
- return [tag, style ? { style } : {}, 0];
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 = { src: a["src"], alt: a["alt"] };
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) => ["table", node.attrs["borders"] ? { "data-borders": "1" } : {}, ["tbody", 0]]
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) attrs["colspan"] = String(node.attrs["colspan"]);
198
- if (node.attrs["rowspan"] !== 1) attrs["rowspan"] = String(node.attrs["rowspan"]);
199
- if (node.attrs["background"]) attrs["style"] = `background-color: ${node.attrs["background"]}`;
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: [{ style: "color", getAttrs: (value) => ({ color: value }) }],
281
+ parseDOM: [
282
+ { style: "color", getAttrs: (value) => ({ color: value }) }
283
+ ],
229
284
  toDOM(mark) {
230
- return ["span", { style: `color: ${mark.attrs["color"]}` }, 0];
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 ["span", { style: `font-size: ${mark.attrs["size"]}pt` }, 0];
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
- { style: "background-color", getAttrs: (value) => ({ color: value }) }
326
+ {
327
+ style: "background-color",
328
+ getAttrs: (value) => ({ color: value })
329
+ }
264
330
  ],
265
331
  toDOM(mark) {
266
- return ["span", { style: `background-color: ${mark.attrs["color"]}` }, 0];
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: [{ style: "font-family", getAttrs: (value) => ({ family: value }) }],
342
+ parseDOM: [
343
+ {
344
+ style: "font-family",
345
+ getAttrs: (value) => ({ family: value })
346
+ }
347
+ ],
273
348
  toDOM(mark) {
274
- return ["span", { style: `font-family: ${mark.attrs["family"]}` }, 0];
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 ["a", { href: mark.attrs["href"], rel: "noopener", target: "_blank" }, 0];
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(el.getAttribute("data-footnote")) || 0
384
+ num: Number(
385
+ el.getAttribute(
386
+ "data-footnote"
387
+ )
388
+ ) || 0
297
389
  })
298
390
  }
299
391
  ],
300
392
  toDOM(mark) {
301
- return ["sup", { "data-footnote": String(mark.attrs["num"]) }, 0];
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: { group: "block", content: "inline*", parseDOM: [{ tag: "p" }], toDOM: () => ["p", 0] },
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 { id: e.getAttribute("data-id"), label: (e.textContent ?? "").replace(/^@/, "") };
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") parts.push(`line-height: ${sp.line}`);
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
- // No getAttrs: nothing in the pipeline parses paragraphs from the DOM
47
- // yet (the importer builds nodes directly). align/indent still round-trip
48
- // out through toDOM. Revisit when HTML paste lands.
49
- parseDOM: [{ tag: "p" }],
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
- return [tag, style ? { style } : {}, 0];
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 = { src: a["src"], alt: a["alt"] };
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) => ["table", node.attrs["borders"] ? { "data-borders": "1" } : {}, ["tbody", 0]]
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) attrs["colspan"] = String(node.attrs["colspan"]);
170
- if (node.attrs["rowspan"] !== 1) attrs["rowspan"] = String(node.attrs["rowspan"]);
171
- if (node.attrs["background"]) attrs["style"] = `background-color: ${node.attrs["background"]}`;
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: [{ style: "color", getAttrs: (value) => ({ color: value }) }],
253
+ parseDOM: [
254
+ { style: "color", getAttrs: (value) => ({ color: value }) }
255
+ ],
201
256
  toDOM(mark) {
202
- return ["span", { style: `color: ${mark.attrs["color"]}` }, 0];
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 ["span", { style: `font-size: ${mark.attrs["size"]}pt` }, 0];
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
- { style: "background-color", getAttrs: (value) => ({ color: value }) }
298
+ {
299
+ style: "background-color",
300
+ getAttrs: (value) => ({ color: value })
301
+ }
236
302
  ],
237
303
  toDOM(mark) {
238
- return ["span", { style: `background-color: ${mark.attrs["color"]}` }, 0];
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: [{ style: "font-family", getAttrs: (value) => ({ family: value }) }],
314
+ parseDOM: [
315
+ {
316
+ style: "font-family",
317
+ getAttrs: (value) => ({ family: value })
318
+ }
319
+ ],
245
320
  toDOM(mark) {
246
- return ["span", { style: `font-family: ${mark.attrs["family"]}` }, 0];
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 ["a", { href: mark.attrs["href"], rel: "noopener", target: "_blank" }, 0];
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(el.getAttribute("data-footnote")) || 0
356
+ num: Number(
357
+ el.getAttribute(
358
+ "data-footnote"
359
+ )
360
+ ) || 0
269
361
  })
270
362
  }
271
363
  ],
272
364
  toDOM(mark) {
273
- return ["sup", { "data-footnote": String(mark.attrs["num"]) }, 0];
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: { group: "block", content: "inline*", parseDOM: [{ tag: "p" }], toDOM: () => ["p", 0] },
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 { id: e.getAttribute("data-id"), label: (e.textContent ?? "").replace(/^@/, "") };
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") parts.push(`line-height: ${sp.line}`);
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("; ");
@@ -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
@@ -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;AAE3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,2PAyRjB,CAAC;AAEH,wEAAwE;AACxE,MAAM,MAAM,aAAa,GAAG,OAAO,MAAM,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,aAAa,yDA+BxB,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;CACzB;AAyBD;;;4EAG4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadow-garden/bapbong-model",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "bapbong — ProseMirror document model / schema",
5
5
  "license": "MIT",
6
6
  "repository": {