@shadow-garden/bapbong-model 0.2.0 → 0.3.0

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,10 +28,23 @@ 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 dataJson(el, name) {
32
+ const raw = el.getAttribute(name);
33
+ if (!raw) return null;
34
+ try {
35
+ return JSON.parse(raw);
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
31
40
  function pastedParagraphAttrs(el, heading) {
32
41
  const style = el.getAttribute("style") ?? "";
33
42
  const m = /(?:^|;)\s*text-align\s*:\s*(center|right|justify)/i.exec(style);
34
- return { heading, align: m ? m[1].toLowerCase() : null };
43
+ return {
44
+ heading,
45
+ align: m ? m[1].toLowerCase() : null,
46
+ borders: dataJson(el, "data-borders")
47
+ };
35
48
  }
36
49
  function pastedImageAttrs(el) {
37
50
  const e = el;
@@ -52,6 +65,24 @@ function pastedLinkAttrs(el) {
52
65
  const href = (el.getAttribute("href") ?? "").trim();
53
66
  return /^(https?:|mailto:|#)/i.test(href) ? { href } : false;
54
67
  }
68
+ function pastedCellAttrs(el) {
69
+ const e = el;
70
+ const span = (name) => {
71
+ const n = parseInt(e.getAttribute(name) ?? "1", 10);
72
+ return Number.isFinite(n) && n > 0 ? n : 1;
73
+ };
74
+ const style = e.getAttribute("style") ?? "";
75
+ const bg = /(?:^|;)\s*background-color\s*:\s*([^;]+)/i.exec(style);
76
+ return {
77
+ colspan: span("colspan"),
78
+ rowspan: span("rowspan"),
79
+ colwidth: dataJson(el, "data-colwidth"),
80
+ background: bg ? bg[1].trim() : null,
81
+ vAlign: e.getAttribute("data-valign"),
82
+ borders: dataJson(el, "data-borders"),
83
+ padding: dataJson(el, "data-padding")
84
+ };
85
+ }
55
86
  var schema = new import_prosemirror_model.Schema({
56
87
  nodes: {
57
88
  doc: {
@@ -98,7 +129,10 @@ var schema = new import_prosemirror_model.Schema({
98
129
  // w:spacing — { before?, after?, line?, lineRule? }, or null.
99
130
  spacing: { default: null },
100
131
  // w:pageBreakBefore — start this paragraph on a new page.
101
- pageBreakBefore: { default: false }
132
+ pageBreakBefore: { default: false },
133
+ // w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
134
+ // Importer-set; painted as a box around the paragraph's lines.
135
+ borders: { default: null }
102
136
  },
103
137
  // HTML paste path: recover heading level from h1–h6 and alignment from
104
138
  // inline style. Other attrs (list/indent/tabs/spacing) stay importer-only
@@ -116,6 +150,8 @@ var schema = new import_prosemirror_model.Schema({
116
150
  const tag = attrs.heading ? `h${attrs.heading}` : "p";
117
151
  const dom = style ? { style } : {};
118
152
  if (attrs.styleId) dom["data-style"] = attrs.styleId;
153
+ if (node.attrs["borders"])
154
+ dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
119
155
  return [tag, dom, 0];
120
156
  }
121
157
  },
@@ -198,12 +234,28 @@ var schema = new import_prosemirror_model.Schema({
198
234
  // w:tblPr/w:jc — 'center' | 'right' table alignment, or null (left).
199
235
  align: { default: null }
200
236
  },
201
- parseDOM: [{ tag: "table" }],
202
- toDOM: (node) => [
203
- "table",
204
- node.attrs["borders"] ? { "data-borders": "1" } : {},
205
- ["tbody", 0]
206
- ]
237
+ // Complex attrs round-trip as data-* JSON — ProseMirror's clipboard is
238
+ // a toDOM parseDOM pass, so without this an internal copy/paste
239
+ // dropped borders / cell padding / alignment.
240
+ parseDOM: [
241
+ {
242
+ tag: "table",
243
+ getAttrs: (el) => ({
244
+ borders: dataJson(el, "data-borders"),
245
+ cellPadding: dataJson(el, "data-cell-padding"),
246
+ align: el.getAttribute("data-align")
247
+ })
248
+ }
249
+ ],
250
+ toDOM: (node) => {
251
+ const a = node.attrs;
252
+ const dom = {};
253
+ if (a["borders"]) dom["data-borders"] = JSON.stringify(a["borders"]);
254
+ if (a["cellPadding"])
255
+ dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
256
+ if (a["align"]) dom["data-align"] = String(a["align"]);
257
+ return ["table", dom, ["tbody", 0]];
258
+ }
207
259
  },
208
260
  table_row: {
209
261
  content: "table_cell+",
@@ -216,10 +268,24 @@ var schema = new import_prosemirror_model.Schema({
216
268
  // w:trHeight — { value: px, exact: boolean } or null (auto).
217
269
  height: { default: null }
218
270
  },
219
- // No getAttrs (same rationale as paragraph): the importer sets attrs
220
- // directly; revisit when HTML paste lands.
221
- parseDOM: [{ tag: "tr" }],
222
- toDOM: (node) => node.attrs["header"] ? ["tr", { "data-header": "true" }, 0] : ["tr", 0]
271
+ parseDOM: [
272
+ {
273
+ tag: "tr",
274
+ getAttrs: (el) => ({
275
+ header: el.getAttribute("data-header") === "true",
276
+ cantSplit: el.getAttribute("data-cant-split") === "true",
277
+ height: dataJson(el, "data-height")
278
+ })
279
+ }
280
+ ],
281
+ toDOM: (node) => {
282
+ const dom = {};
283
+ if (node.attrs["header"]) dom["data-header"] = "true";
284
+ if (node.attrs["cantSplit"]) dom["data-cant-split"] = "true";
285
+ if (node.attrs["height"])
286
+ dom["data-height"] = JSON.stringify(node.attrs["height"]);
287
+ return ["tr", dom, 0];
288
+ }
223
289
  },
224
290
  table_cell: {
225
291
  content: "block+",
@@ -233,10 +299,15 @@ var schema = new import_prosemirror_model.Schema({
233
299
  // w:shd w:fill — cell fill "#RRGGBB"
234
300
  vAlign: { default: null },
235
301
  // w:vAlign — 'center' | 'bottom' (top default)
236
- borders: { default: null }
302
+ borders: { default: null },
237
303
  // w:tcBorders per-side visibility override
304
+ padding: { default: null }
305
+ // w:tcMar per-side margin override (px)
238
306
  },
239
- parseDOM: [{ tag: "td" }, { tag: "th" }],
307
+ parseDOM: [
308
+ { tag: "td", getAttrs: pastedCellAttrs },
309
+ { tag: "th", getAttrs: pastedCellAttrs }
310
+ ],
240
311
  toDOM(node) {
241
312
  const attrs = {};
242
313
  if (node.attrs["colspan"] !== 1)
@@ -245,6 +316,14 @@ var schema = new import_prosemirror_model.Schema({
245
316
  attrs["rowspan"] = String(node.attrs["rowspan"]);
246
317
  if (node.attrs["background"])
247
318
  attrs["style"] = `background-color: ${node.attrs["background"]}`;
319
+ if (node.attrs["colwidth"])
320
+ attrs["data-colwidth"] = JSON.stringify(node.attrs["colwidth"]);
321
+ if (node.attrs["vAlign"])
322
+ attrs["data-valign"] = String(node.attrs["vAlign"]);
323
+ if (node.attrs["borders"])
324
+ attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
325
+ if (node.attrs["padding"])
326
+ attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
248
327
  return ["td", attrs, 0];
249
328
  }
250
329
  }
@@ -508,6 +587,8 @@ function formatCounter(n, fmt) {
508
587
  return toRoman(n).toLowerCase();
509
588
  case "upperRoman":
510
589
  return toRoman(n);
590
+ case "decimalZero":
591
+ return String(n).padStart(2, "0");
511
592
  default:
512
593
  return String(n);
513
594
  }
package/dist/index.js CHANGED
@@ -1,9 +1,22 @@
1
1
  // packages/model/src/lib/model.ts
2
2
  import { Schema } from "prosemirror-model";
3
+ function dataJson(el, name) {
4
+ const raw = el.getAttribute(name);
5
+ if (!raw) return null;
6
+ try {
7
+ return JSON.parse(raw);
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
3
12
  function pastedParagraphAttrs(el, heading) {
4
13
  const style = el.getAttribute("style") ?? "";
5
14
  const m = /(?:^|;)\s*text-align\s*:\s*(center|right|justify)/i.exec(style);
6
- return { heading, align: m ? m[1].toLowerCase() : null };
15
+ return {
16
+ heading,
17
+ align: m ? m[1].toLowerCase() : null,
18
+ borders: dataJson(el, "data-borders")
19
+ };
7
20
  }
8
21
  function pastedImageAttrs(el) {
9
22
  const e = el;
@@ -24,6 +37,24 @@ function pastedLinkAttrs(el) {
24
37
  const href = (el.getAttribute("href") ?? "").trim();
25
38
  return /^(https?:|mailto:|#)/i.test(href) ? { href } : false;
26
39
  }
40
+ function pastedCellAttrs(el) {
41
+ const e = el;
42
+ const span = (name) => {
43
+ const n = parseInt(e.getAttribute(name) ?? "1", 10);
44
+ return Number.isFinite(n) && n > 0 ? n : 1;
45
+ };
46
+ const style = e.getAttribute("style") ?? "";
47
+ const bg = /(?:^|;)\s*background-color\s*:\s*([^;]+)/i.exec(style);
48
+ return {
49
+ colspan: span("colspan"),
50
+ rowspan: span("rowspan"),
51
+ colwidth: dataJson(el, "data-colwidth"),
52
+ background: bg ? bg[1].trim() : null,
53
+ vAlign: e.getAttribute("data-valign"),
54
+ borders: dataJson(el, "data-borders"),
55
+ padding: dataJson(el, "data-padding")
56
+ };
57
+ }
27
58
  var schema = new Schema({
28
59
  nodes: {
29
60
  doc: {
@@ -70,7 +101,10 @@ var schema = new Schema({
70
101
  // w:spacing — { before?, after?, line?, lineRule? }, or null.
71
102
  spacing: { default: null },
72
103
  // w:pageBreakBefore — start this paragraph on a new page.
73
- pageBreakBefore: { default: false }
104
+ pageBreakBefore: { default: false },
105
+ // w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
106
+ // Importer-set; painted as a box around the paragraph's lines.
107
+ borders: { default: null }
74
108
  },
75
109
  // HTML paste path: recover heading level from h1–h6 and alignment from
76
110
  // inline style. Other attrs (list/indent/tabs/spacing) stay importer-only
@@ -88,6 +122,8 @@ var schema = new Schema({
88
122
  const tag = attrs.heading ? `h${attrs.heading}` : "p";
89
123
  const dom = style ? { style } : {};
90
124
  if (attrs.styleId) dom["data-style"] = attrs.styleId;
125
+ if (node.attrs["borders"])
126
+ dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
91
127
  return [tag, dom, 0];
92
128
  }
93
129
  },
@@ -170,12 +206,28 @@ var schema = new Schema({
170
206
  // w:tblPr/w:jc — 'center' | 'right' table alignment, or null (left).
171
207
  align: { default: null }
172
208
  },
173
- parseDOM: [{ tag: "table" }],
174
- toDOM: (node) => [
175
- "table",
176
- node.attrs["borders"] ? { "data-borders": "1" } : {},
177
- ["tbody", 0]
178
- ]
209
+ // Complex attrs round-trip as data-* JSON — ProseMirror's clipboard is
210
+ // a toDOM parseDOM pass, so without this an internal copy/paste
211
+ // dropped borders / cell padding / alignment.
212
+ parseDOM: [
213
+ {
214
+ tag: "table",
215
+ getAttrs: (el) => ({
216
+ borders: dataJson(el, "data-borders"),
217
+ cellPadding: dataJson(el, "data-cell-padding"),
218
+ align: el.getAttribute("data-align")
219
+ })
220
+ }
221
+ ],
222
+ toDOM: (node) => {
223
+ const a = node.attrs;
224
+ const dom = {};
225
+ if (a["borders"]) dom["data-borders"] = JSON.stringify(a["borders"]);
226
+ if (a["cellPadding"])
227
+ dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
228
+ if (a["align"]) dom["data-align"] = String(a["align"]);
229
+ return ["table", dom, ["tbody", 0]];
230
+ }
179
231
  },
180
232
  table_row: {
181
233
  content: "table_cell+",
@@ -188,10 +240,24 @@ var schema = new Schema({
188
240
  // w:trHeight — { value: px, exact: boolean } or null (auto).
189
241
  height: { default: null }
190
242
  },
191
- // No getAttrs (same rationale as paragraph): the importer sets attrs
192
- // directly; revisit when HTML paste lands.
193
- parseDOM: [{ tag: "tr" }],
194
- toDOM: (node) => node.attrs["header"] ? ["tr", { "data-header": "true" }, 0] : ["tr", 0]
243
+ parseDOM: [
244
+ {
245
+ tag: "tr",
246
+ getAttrs: (el) => ({
247
+ header: el.getAttribute("data-header") === "true",
248
+ cantSplit: el.getAttribute("data-cant-split") === "true",
249
+ height: dataJson(el, "data-height")
250
+ })
251
+ }
252
+ ],
253
+ toDOM: (node) => {
254
+ const dom = {};
255
+ if (node.attrs["header"]) dom["data-header"] = "true";
256
+ if (node.attrs["cantSplit"]) dom["data-cant-split"] = "true";
257
+ if (node.attrs["height"])
258
+ dom["data-height"] = JSON.stringify(node.attrs["height"]);
259
+ return ["tr", dom, 0];
260
+ }
195
261
  },
196
262
  table_cell: {
197
263
  content: "block+",
@@ -205,10 +271,15 @@ var schema = new Schema({
205
271
  // w:shd w:fill — cell fill "#RRGGBB"
206
272
  vAlign: { default: null },
207
273
  // w:vAlign — 'center' | 'bottom' (top default)
208
- borders: { default: null }
274
+ borders: { default: null },
209
275
  // w:tcBorders per-side visibility override
276
+ padding: { default: null }
277
+ // w:tcMar per-side margin override (px)
210
278
  },
211
- parseDOM: [{ tag: "td" }, { tag: "th" }],
279
+ parseDOM: [
280
+ { tag: "td", getAttrs: pastedCellAttrs },
281
+ { tag: "th", getAttrs: pastedCellAttrs }
282
+ ],
212
283
  toDOM(node) {
213
284
  const attrs = {};
214
285
  if (node.attrs["colspan"] !== 1)
@@ -217,6 +288,14 @@ var schema = new Schema({
217
288
  attrs["rowspan"] = String(node.attrs["rowspan"]);
218
289
  if (node.attrs["background"])
219
290
  attrs["style"] = `background-color: ${node.attrs["background"]}`;
291
+ if (node.attrs["colwidth"])
292
+ attrs["data-colwidth"] = JSON.stringify(node.attrs["colwidth"]);
293
+ if (node.attrs["vAlign"])
294
+ attrs["data-valign"] = String(node.attrs["vAlign"]);
295
+ if (node.attrs["borders"])
296
+ attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
297
+ if (node.attrs["padding"])
298
+ attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
220
299
  return ["td", attrs, 0];
221
300
  }
222
301
  }
@@ -480,6 +559,8 @@ function formatCounter(n, fmt) {
480
559
  return toRoman(n).toLowerCase();
481
560
  case "upperRoman":
482
561
  return toRoman(n);
562
+ case "decimalZero":
563
+ return String(n).padStart(2, "0");
483
564
  default:
484
565
  return String(n);
485
566
  }
@@ -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;AA0C3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,2PA8VjB,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"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/lib/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAgF3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,2PA4YjB,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"}
@@ -1 +1 @@
1
- {"version":3,"file":"numbering.d.ts","sourceRoot":"","sources":["../../src/lib/numbering.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;+EAC+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,CAAC,KAAK,EAAE,MAAM,GAAG;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;KAC3C,CAAC;CACH;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5C;AA8CD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,gBAAgB,CA2B/F"}
1
+ {"version":3,"file":"numbering.d.ts","sourceRoot":"","sources":["../../src/lib/numbering.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;+EAC+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,CAAC,KAAK,EAAE,MAAM,GAAG;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;KAC3C,CAAC;CACH;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5C;AA2DD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GACrC,gBAAgB,CA2BlB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadow-garden/bapbong-model",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "bapbong — ProseMirror document model / schema",
5
5
  "license": "MIT",
6
6
  "repository": {