@shadow-garden/bapbong-model 0.2.1 → 0.4.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: {
@@ -119,6 +150,8 @@ var schema = new import_prosemirror_model.Schema({
119
150
  const tag = attrs.heading ? `h${attrs.heading}` : "p";
120
151
  const dom = style ? { style } : {};
121
152
  if (attrs.styleId) dom["data-style"] = attrs.styleId;
153
+ if (node.attrs["borders"])
154
+ dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
122
155
  return [tag, dom, 0];
123
156
  }
124
157
  },
@@ -145,7 +178,8 @@ var schema = new import_prosemirror_model.Schema({
145
178
  height: { default: null },
146
179
  // wp:anchor (floating image): { wrap: 'square'|'topAndBottom'|'none',
147
180
  // hAlign?, hOffset?, hRel?, vOffset?, vRel?, distL?, distR?, distT?,
148
- // distB? } in px, or null for inline images. Importer-set.
181
+ // distB?, behind? } in px (behind = behindDoc: paint under the text),
182
+ // or null for inline images. Importer-set.
149
183
  float: { default: null },
150
184
  // Drawn vector shape (wps rect / straight connector) riding this box:
151
185
  // { kind: 'rect'|'line', stroke?, strokeWidth?, fill?, flipV? } — src
@@ -201,12 +235,28 @@ var schema = new import_prosemirror_model.Schema({
201
235
  // w:tblPr/w:jc — 'center' | 'right' table alignment, or null (left).
202
236
  align: { default: null }
203
237
  },
204
- parseDOM: [{ tag: "table" }],
205
- toDOM: (node) => [
206
- "table",
207
- node.attrs["borders"] ? { "data-borders": "1" } : {},
208
- ["tbody", 0]
209
- ]
238
+ // Complex attrs round-trip as data-* JSON — ProseMirror's clipboard is
239
+ // a toDOM parseDOM pass, so without this an internal copy/paste
240
+ // dropped borders / cell padding / alignment.
241
+ parseDOM: [
242
+ {
243
+ tag: "table",
244
+ getAttrs: (el) => ({
245
+ borders: dataJson(el, "data-borders"),
246
+ cellPadding: dataJson(el, "data-cell-padding"),
247
+ align: el.getAttribute("data-align")
248
+ })
249
+ }
250
+ ],
251
+ toDOM: (node) => {
252
+ const a = node.attrs;
253
+ const dom = {};
254
+ if (a["borders"]) dom["data-borders"] = JSON.stringify(a["borders"]);
255
+ if (a["cellPadding"])
256
+ dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
257
+ if (a["align"]) dom["data-align"] = String(a["align"]);
258
+ return ["table", dom, ["tbody", 0]];
259
+ }
210
260
  },
211
261
  table_row: {
212
262
  content: "table_cell+",
@@ -219,10 +269,24 @@ var schema = new import_prosemirror_model.Schema({
219
269
  // w:trHeight — { value: px, exact: boolean } or null (auto).
220
270
  height: { default: null }
221
271
  },
222
- // No getAttrs (same rationale as paragraph): the importer sets attrs
223
- // directly; revisit when HTML paste lands.
224
- parseDOM: [{ tag: "tr" }],
225
- toDOM: (node) => node.attrs["header"] ? ["tr", { "data-header": "true" }, 0] : ["tr", 0]
272
+ parseDOM: [
273
+ {
274
+ tag: "tr",
275
+ getAttrs: (el) => ({
276
+ header: el.getAttribute("data-header") === "true",
277
+ cantSplit: el.getAttribute("data-cant-split") === "true",
278
+ height: dataJson(el, "data-height")
279
+ })
280
+ }
281
+ ],
282
+ toDOM: (node) => {
283
+ const dom = {};
284
+ if (node.attrs["header"]) dom["data-header"] = "true";
285
+ if (node.attrs["cantSplit"]) dom["data-cant-split"] = "true";
286
+ if (node.attrs["height"])
287
+ dom["data-height"] = JSON.stringify(node.attrs["height"]);
288
+ return ["tr", dom, 0];
289
+ }
226
290
  },
227
291
  table_cell: {
228
292
  content: "block+",
@@ -241,7 +305,10 @@ var schema = new import_prosemirror_model.Schema({
241
305
  padding: { default: null }
242
306
  // w:tcMar per-side margin override (px)
243
307
  },
244
- parseDOM: [{ tag: "td" }, { tag: "th" }],
308
+ parseDOM: [
309
+ { tag: "td", getAttrs: pastedCellAttrs },
310
+ { tag: "th", getAttrs: pastedCellAttrs }
311
+ ],
245
312
  toDOM(node) {
246
313
  const attrs = {};
247
314
  if (node.attrs["colspan"] !== 1)
@@ -250,6 +317,14 @@ var schema = new import_prosemirror_model.Schema({
250
317
  attrs["rowspan"] = String(node.attrs["rowspan"]);
251
318
  if (node.attrs["background"])
252
319
  attrs["style"] = `background-color: ${node.attrs["background"]}`;
320
+ if (node.attrs["colwidth"])
321
+ attrs["data-colwidth"] = JSON.stringify(node.attrs["colwidth"]);
322
+ if (node.attrs["vAlign"])
323
+ attrs["data-valign"] = String(node.attrs["vAlign"]);
324
+ if (node.attrs["borders"])
325
+ attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
326
+ if (node.attrs["padding"])
327
+ attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
253
328
  return ["td", attrs, 0];
254
329
  }
255
330
  }
@@ -513,6 +588,8 @@ function formatCounter(n, fmt) {
513
588
  return toRoman(n).toLowerCase();
514
589
  case "upperRoman":
515
590
  return toRoman(n);
591
+ case "decimalZero":
592
+ return String(n).padStart(2, "0");
516
593
  default:
517
594
  return String(n);
518
595
  }
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: {
@@ -91,6 +122,8 @@ var schema = new Schema({
91
122
  const tag = attrs.heading ? `h${attrs.heading}` : "p";
92
123
  const dom = style ? { style } : {};
93
124
  if (attrs.styleId) dom["data-style"] = attrs.styleId;
125
+ if (node.attrs["borders"])
126
+ dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
94
127
  return [tag, dom, 0];
95
128
  }
96
129
  },
@@ -117,7 +150,8 @@ var schema = new Schema({
117
150
  height: { default: null },
118
151
  // wp:anchor (floating image): { wrap: 'square'|'topAndBottom'|'none',
119
152
  // hAlign?, hOffset?, hRel?, vOffset?, vRel?, distL?, distR?, distT?,
120
- // distB? } in px, or null for inline images. Importer-set.
153
+ // distB?, behind? } in px (behind = behindDoc: paint under the text),
154
+ // or null for inline images. Importer-set.
121
155
  float: { default: null },
122
156
  // Drawn vector shape (wps rect / straight connector) riding this box:
123
157
  // { kind: 'rect'|'line', stroke?, strokeWidth?, fill?, flipV? } — src
@@ -173,12 +207,28 @@ var schema = new Schema({
173
207
  // w:tblPr/w:jc — 'center' | 'right' table alignment, or null (left).
174
208
  align: { default: null }
175
209
  },
176
- parseDOM: [{ tag: "table" }],
177
- toDOM: (node) => [
178
- "table",
179
- node.attrs["borders"] ? { "data-borders": "1" } : {},
180
- ["tbody", 0]
181
- ]
210
+ // Complex attrs round-trip as data-* JSON — ProseMirror's clipboard is
211
+ // a toDOM parseDOM pass, so without this an internal copy/paste
212
+ // dropped borders / cell padding / alignment.
213
+ parseDOM: [
214
+ {
215
+ tag: "table",
216
+ getAttrs: (el) => ({
217
+ borders: dataJson(el, "data-borders"),
218
+ cellPadding: dataJson(el, "data-cell-padding"),
219
+ align: el.getAttribute("data-align")
220
+ })
221
+ }
222
+ ],
223
+ toDOM: (node) => {
224
+ const a = node.attrs;
225
+ const dom = {};
226
+ if (a["borders"]) dom["data-borders"] = JSON.stringify(a["borders"]);
227
+ if (a["cellPadding"])
228
+ dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
229
+ if (a["align"]) dom["data-align"] = String(a["align"]);
230
+ return ["table", dom, ["tbody", 0]];
231
+ }
182
232
  },
183
233
  table_row: {
184
234
  content: "table_cell+",
@@ -191,10 +241,24 @@ var schema = new Schema({
191
241
  // w:trHeight — { value: px, exact: boolean } or null (auto).
192
242
  height: { default: null }
193
243
  },
194
- // No getAttrs (same rationale as paragraph): the importer sets attrs
195
- // directly; revisit when HTML paste lands.
196
- parseDOM: [{ tag: "tr" }],
197
- toDOM: (node) => node.attrs["header"] ? ["tr", { "data-header": "true" }, 0] : ["tr", 0]
244
+ parseDOM: [
245
+ {
246
+ tag: "tr",
247
+ getAttrs: (el) => ({
248
+ header: el.getAttribute("data-header") === "true",
249
+ cantSplit: el.getAttribute("data-cant-split") === "true",
250
+ height: dataJson(el, "data-height")
251
+ })
252
+ }
253
+ ],
254
+ toDOM: (node) => {
255
+ const dom = {};
256
+ if (node.attrs["header"]) dom["data-header"] = "true";
257
+ if (node.attrs["cantSplit"]) dom["data-cant-split"] = "true";
258
+ if (node.attrs["height"])
259
+ dom["data-height"] = JSON.stringify(node.attrs["height"]);
260
+ return ["tr", dom, 0];
261
+ }
198
262
  },
199
263
  table_cell: {
200
264
  content: "block+",
@@ -213,7 +277,10 @@ var schema = new Schema({
213
277
  padding: { default: null }
214
278
  // w:tcMar per-side margin override (px)
215
279
  },
216
- parseDOM: [{ tag: "td" }, { tag: "th" }],
280
+ parseDOM: [
281
+ { tag: "td", getAttrs: pastedCellAttrs },
282
+ { tag: "th", getAttrs: pastedCellAttrs }
283
+ ],
217
284
  toDOM(node) {
218
285
  const attrs = {};
219
286
  if (node.attrs["colspan"] !== 1)
@@ -222,6 +289,14 @@ var schema = new Schema({
222
289
  attrs["rowspan"] = String(node.attrs["rowspan"]);
223
290
  if (node.attrs["background"])
224
291
  attrs["style"] = `background-color: ${node.attrs["background"]}`;
292
+ if (node.attrs["colwidth"])
293
+ attrs["data-colwidth"] = JSON.stringify(node.attrs["colwidth"]);
294
+ if (node.attrs["vAlign"])
295
+ attrs["data-valign"] = String(node.attrs["vAlign"]);
296
+ if (node.attrs["borders"])
297
+ attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
298
+ if (node.attrs["padding"])
299
+ attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
225
300
  return ["td", attrs, 0];
226
301
  }
227
302
  }
@@ -485,6 +560,8 @@ function formatCounter(n, fmt) {
485
560
  return toRoman(n).toLowerCase();
486
561
  case "upperRoman":
487
562
  return toRoman(n);
563
+ case "decimalZero":
564
+ return String(n).padStart(2, "0");
488
565
  default:
489
566
  return String(n);
490
567
  }
@@ -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,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"}
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,2PA6YjB,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.1",
3
+ "version": "0.4.0",
4
4
  "description": "bapbong — ProseMirror document model / schema",
5
5
  "license": "MIT",
6
6
  "repository": {