@shadow-garden/bapbong-model 0.9.0 → 0.10.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
@@ -102,12 +102,15 @@ function pastedImageAttrs(el) {
102
102
  src,
103
103
  alt: e.getAttribute("alt") ?? "",
104
104
  width: dim(e.getAttribute("width")),
105
- height: dim(e.getAttribute("height"))
105
+ height: dim(e.getAttribute("height")),
106
+ crop: dataJson(el, "data-crop"),
107
+ outline: dataJson(el, "data-outline")
106
108
  };
107
109
  }
108
110
  function pastedLinkAttrs(el) {
109
- const href = (el.getAttribute("href") ?? "").trim();
110
- return /^(https?:|mailto:|#)/i.test(href) ? { href } : false;
111
+ const e = el;
112
+ const href = (e.getAttribute("href") ?? "").trim();
113
+ return /^(https?:|mailto:|#)/i.test(href) ? { href, targetFrame: e.getAttribute("data-target-frame") } : false;
111
114
  }
112
115
  function pastedCellAttrs(el) {
113
116
  const e = el;
@@ -124,6 +127,7 @@ function pastedCellAttrs(el) {
124
127
  background: bg ? bg[1].trim() : null,
125
128
  vAlign: e.getAttribute("data-valign"),
126
129
  borders: dataJson(el, "data-borders"),
130
+ diagonals: dataJson(el, "data-diagonals"),
127
131
  padding: dataJson(el, "data-padding"),
128
132
  carry: dataJson(el, "data-carry")
129
133
  };
@@ -195,6 +199,11 @@ var schema = new import_prosemirror_model.Schema({
195
199
  field: { default: null },
196
200
  // w:pageBreakBefore — start this paragraph on a new page.
197
201
  pageBreakBefore: { default: false },
202
+ // w:contextualSpacing — "ignore spacing above and below when using
203
+ // identical styles". Present ⇒ the flag is on; the two booleans say
204
+ // which side actually borders a paragraph of the SAME style, which is
205
+ // resolved at import (only there is both sides of a boundary visible).
206
+ contextualSpacing: { default: null },
198
207
  // w:keepNext — stay on the same page as the next block's first line.
199
208
  keepNext: { default: false },
200
209
  // w:keepLines — never split this paragraph across pages.
@@ -205,6 +214,10 @@ var schema = new import_prosemirror_model.Schema({
205
214
  // w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
206
215
  // Importer-set; painted as a box around the paragraph's lines.
207
216
  borders: { default: null },
217
+ // w:shd at the paragraph layer, resolved to a fill "#RRGGBB" (or
218
+ // null). Painted behind the paragraph's lines, in the same box the
219
+ // borders use.
220
+ shading: { default: null },
208
221
  // Carry-through fidelity (docx round-trip): OOXML paragraph
209
222
  // properties the model does NOT represent, preserved verbatim so a
210
223
  // customer's save never drops them. { pPr?: string, markRPr?: string }
@@ -230,6 +243,8 @@ var schema = new import_prosemirror_model.Schema({
230
243
  if (attrs.styleId) dom["data-style"] = attrs.styleId;
231
244
  if (node.attrs["borders"])
232
245
  dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
246
+ if (node.attrs["shading"])
247
+ dom["data-shading"] = String(node.attrs["shading"]);
233
248
  if (node.attrs["carry"])
234
249
  dom["data-carry"] = JSON.stringify(node.attrs["carry"]);
235
250
  return [tag, dom, 0];
@@ -271,7 +286,13 @@ var schema = new import_prosemirror_model.Schema({
271
286
  textbox: { default: null },
272
287
  // Clockwise rotation in degrees around the box center (a:xfrm@rot).
273
288
  // Paint-only: the layout box stays axis-aligned.
274
- rotation: { default: 0 }
289
+ rotation: { default: 0 },
290
+ // a:srcRect — { l, t, r, b } ratios of the BITMAP, inward from each
291
+ // edge, or null for the whole image. Negative values outset. The box
292
+ // keeps its size; the selected region scales to fill it.
293
+ crop: { default: null },
294
+ // a:ln on pic:spPr — Word's picture border, as a BorderSide, or null.
295
+ outline: { default: null }
275
296
  },
276
297
  parseDOM: [{ tag: "img[src]", getAttrs: pastedImageAttrs }],
277
298
  toDOM(node) {
@@ -282,6 +303,8 @@ var schema = new import_prosemirror_model.Schema({
282
303
  };
283
304
  if (a["width"] != null) attrs["width"] = String(a["width"]);
284
305
  if (a["height"] != null) attrs["height"] = String(a["height"]);
306
+ if (a["crop"]) attrs["data-crop"] = JSON.stringify(a["crop"]);
307
+ if (a["outline"]) attrs["data-outline"] = JSON.stringify(a["outline"]);
285
308
  return ["img", attrs];
286
309
  }
287
310
  },
@@ -395,6 +418,8 @@ var schema = new import_prosemirror_model.Schema({
395
418
  // w:vAlign — 'center' | 'bottom' (top default)
396
419
  borders: { default: null },
397
420
  // w:tcBorders per-side visibility override
421
+ // w:tcBorders/w:tl2br + w:br2tl — rules across the cell's corners
422
+ diagonals: { default: null },
398
423
  padding: { default: null },
399
424
  // w:tcMar per-side margin override (px)
400
425
  // Carry-through fidelity: unmodelled w:tcPr children ({ tcPr: string
@@ -419,6 +444,8 @@ var schema = new import_prosemirror_model.Schema({
419
444
  attrs["data-valign"] = String(node.attrs["vAlign"]);
420
445
  if (node.attrs["borders"])
421
446
  attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
447
+ if (node.attrs["diagonals"])
448
+ attrs["data-diagonals"] = JSON.stringify(node.attrs["diagonals"]);
422
449
  if (node.attrs["padding"])
423
450
  attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
424
451
  if (node.attrs["carry"])
@@ -537,6 +564,29 @@ var schema = new import_prosemirror_model.Schema({
537
564
  0
538
565
  ]
539
566
  },
567
+ // w:kern — the smallest font size (HALF-POINTS) that gets pair kerning.
568
+ // A threshold, not a switch: whether it bites depends on the run's own
569
+ // size, so the declared number is what the model keeps and the layout
570
+ // compares. No DOM representation — CSS font-kerning cannot express a
571
+ // size threshold, so an external paste simply has no opinion.
572
+ kern: {
573
+ attrs: { halfPoints: {} },
574
+ parseDOM: [
575
+ {
576
+ tag: "span[data-kern]",
577
+ getAttrs: (el) => {
578
+ const raw = el.getAttribute("data-kern");
579
+ const n = Number(raw);
580
+ return Number.isFinite(n) ? { halfPoints: n } : false;
581
+ }
582
+ }
583
+ ],
584
+ toDOM: (mark) => [
585
+ "span",
586
+ { "data-kern": String(mark.attrs["halfPoints"]) },
587
+ 0
588
+ ]
589
+ },
540
590
  // w:w — horizontal glyph scale as a PERCENT (100 = normal). Squeezes the
541
591
  // glyphs and their advances; independent of letterSpacing, which rides on
542
592
  // top at its absolute value.
@@ -617,7 +667,11 @@ var schema = new import_prosemirror_model.Schema({
617
667
  },
618
668
  // w:hyperlink — external URL or "#anchor"
619
669
  link: {
620
- attrs: { href: {} },
670
+ // w:hyperlink @w:tgtFrame the frame the link was meant to open in
671
+ // ("_blank", "_top", or a frame name), from the HTML-frames era. There
672
+ // is no frame here to obey it and nothing acts on it; it is modelled so
673
+ // that saving the file gives the attribute back instead of dropping it.
674
+ attrs: { href: {}, targetFrame: { default: null } },
621
675
  inclusive: false,
622
676
  parseDOM: [{ tag: "a[href]", getAttrs: pastedLinkAttrs }],
623
677
  toDOM(mark) {
@@ -626,7 +680,8 @@ var schema = new import_prosemirror_model.Schema({
626
680
  {
627
681
  href: mark.attrs["href"],
628
682
  rel: "noopener",
629
- target: "_blank"
683
+ target: "_blank",
684
+ ...mark.attrs["targetFrame"] ? { "data-target-frame": String(mark.attrs["targetFrame"]) } : {}
630
685
  },
631
686
  0
632
687
  ];
package/dist/index.js CHANGED
@@ -70,12 +70,15 @@ function pastedImageAttrs(el) {
70
70
  src,
71
71
  alt: e.getAttribute("alt") ?? "",
72
72
  width: dim(e.getAttribute("width")),
73
- height: dim(e.getAttribute("height"))
73
+ height: dim(e.getAttribute("height")),
74
+ crop: dataJson(el, "data-crop"),
75
+ outline: dataJson(el, "data-outline")
74
76
  };
75
77
  }
76
78
  function pastedLinkAttrs(el) {
77
- const href = (el.getAttribute("href") ?? "").trim();
78
- return /^(https?:|mailto:|#)/i.test(href) ? { href } : false;
79
+ const e = el;
80
+ const href = (e.getAttribute("href") ?? "").trim();
81
+ return /^(https?:|mailto:|#)/i.test(href) ? { href, targetFrame: e.getAttribute("data-target-frame") } : false;
79
82
  }
80
83
  function pastedCellAttrs(el) {
81
84
  const e = el;
@@ -92,6 +95,7 @@ function pastedCellAttrs(el) {
92
95
  background: bg ? bg[1].trim() : null,
93
96
  vAlign: e.getAttribute("data-valign"),
94
97
  borders: dataJson(el, "data-borders"),
98
+ diagonals: dataJson(el, "data-diagonals"),
95
99
  padding: dataJson(el, "data-padding"),
96
100
  carry: dataJson(el, "data-carry")
97
101
  };
@@ -163,6 +167,11 @@ var schema = new Schema({
163
167
  field: { default: null },
164
168
  // w:pageBreakBefore — start this paragraph on a new page.
165
169
  pageBreakBefore: { default: false },
170
+ // w:contextualSpacing — "ignore spacing above and below when using
171
+ // identical styles". Present ⇒ the flag is on; the two booleans say
172
+ // which side actually borders a paragraph of the SAME style, which is
173
+ // resolved at import (only there is both sides of a boundary visible).
174
+ contextualSpacing: { default: null },
166
175
  // w:keepNext — stay on the same page as the next block's first line.
167
176
  keepNext: { default: false },
168
177
  // w:keepLines — never split this paragraph across pages.
@@ -173,6 +182,10 @@ var schema = new Schema({
173
182
  // w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
174
183
  // Importer-set; painted as a box around the paragraph's lines.
175
184
  borders: { default: null },
185
+ // w:shd at the paragraph layer, resolved to a fill "#RRGGBB" (or
186
+ // null). Painted behind the paragraph's lines, in the same box the
187
+ // borders use.
188
+ shading: { default: null },
176
189
  // Carry-through fidelity (docx round-trip): OOXML paragraph
177
190
  // properties the model does NOT represent, preserved verbatim so a
178
191
  // customer's save never drops them. { pPr?: string, markRPr?: string }
@@ -198,6 +211,8 @@ var schema = new Schema({
198
211
  if (attrs.styleId) dom["data-style"] = attrs.styleId;
199
212
  if (node.attrs["borders"])
200
213
  dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
214
+ if (node.attrs["shading"])
215
+ dom["data-shading"] = String(node.attrs["shading"]);
201
216
  if (node.attrs["carry"])
202
217
  dom["data-carry"] = JSON.stringify(node.attrs["carry"]);
203
218
  return [tag, dom, 0];
@@ -239,7 +254,13 @@ var schema = new Schema({
239
254
  textbox: { default: null },
240
255
  // Clockwise rotation in degrees around the box center (a:xfrm@rot).
241
256
  // Paint-only: the layout box stays axis-aligned.
242
- rotation: { default: 0 }
257
+ rotation: { default: 0 },
258
+ // a:srcRect — { l, t, r, b } ratios of the BITMAP, inward from each
259
+ // edge, or null for the whole image. Negative values outset. The box
260
+ // keeps its size; the selected region scales to fill it.
261
+ crop: { default: null },
262
+ // a:ln on pic:spPr — Word's picture border, as a BorderSide, or null.
263
+ outline: { default: null }
243
264
  },
244
265
  parseDOM: [{ tag: "img[src]", getAttrs: pastedImageAttrs }],
245
266
  toDOM(node) {
@@ -250,6 +271,8 @@ var schema = new Schema({
250
271
  };
251
272
  if (a["width"] != null) attrs["width"] = String(a["width"]);
252
273
  if (a["height"] != null) attrs["height"] = String(a["height"]);
274
+ if (a["crop"]) attrs["data-crop"] = JSON.stringify(a["crop"]);
275
+ if (a["outline"]) attrs["data-outline"] = JSON.stringify(a["outline"]);
253
276
  return ["img", attrs];
254
277
  }
255
278
  },
@@ -363,6 +386,8 @@ var schema = new Schema({
363
386
  // w:vAlign — 'center' | 'bottom' (top default)
364
387
  borders: { default: null },
365
388
  // w:tcBorders per-side visibility override
389
+ // w:tcBorders/w:tl2br + w:br2tl — rules across the cell's corners
390
+ diagonals: { default: null },
366
391
  padding: { default: null },
367
392
  // w:tcMar per-side margin override (px)
368
393
  // Carry-through fidelity: unmodelled w:tcPr children ({ tcPr: string
@@ -387,6 +412,8 @@ var schema = new Schema({
387
412
  attrs["data-valign"] = String(node.attrs["vAlign"]);
388
413
  if (node.attrs["borders"])
389
414
  attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
415
+ if (node.attrs["diagonals"])
416
+ attrs["data-diagonals"] = JSON.stringify(node.attrs["diagonals"]);
390
417
  if (node.attrs["padding"])
391
418
  attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
392
419
  if (node.attrs["carry"])
@@ -505,6 +532,29 @@ var schema = new Schema({
505
532
  0
506
533
  ]
507
534
  },
535
+ // w:kern — the smallest font size (HALF-POINTS) that gets pair kerning.
536
+ // A threshold, not a switch: whether it bites depends on the run's own
537
+ // size, so the declared number is what the model keeps and the layout
538
+ // compares. No DOM representation — CSS font-kerning cannot express a
539
+ // size threshold, so an external paste simply has no opinion.
540
+ kern: {
541
+ attrs: { halfPoints: {} },
542
+ parseDOM: [
543
+ {
544
+ tag: "span[data-kern]",
545
+ getAttrs: (el) => {
546
+ const raw = el.getAttribute("data-kern");
547
+ const n = Number(raw);
548
+ return Number.isFinite(n) ? { halfPoints: n } : false;
549
+ }
550
+ }
551
+ ],
552
+ toDOM: (mark) => [
553
+ "span",
554
+ { "data-kern": String(mark.attrs["halfPoints"]) },
555
+ 0
556
+ ]
557
+ },
508
558
  // w:w — horizontal glyph scale as a PERCENT (100 = normal). Squeezes the
509
559
  // glyphs and their advances; independent of letterSpacing, which rides on
510
560
  // top at its absolute value.
@@ -585,7 +635,11 @@ var schema = new Schema({
585
635
  },
586
636
  // w:hyperlink — external URL or "#anchor"
587
637
  link: {
588
- attrs: { href: {} },
638
+ // w:hyperlink @w:tgtFrame the frame the link was meant to open in
639
+ // ("_blank", "_top", or a frame name), from the HTML-frames era. There
640
+ // is no frame here to obey it and nothing acts on it; it is modelled so
641
+ // that saving the file gives the attribute back instead of dropping it.
642
+ attrs: { href: {}, targetFrame: { default: null } },
589
643
  inclusive: false,
590
644
  parseDOM: [{ tag: "a[href]", getAttrs: pastedLinkAttrs }],
591
645
  toDOM(mark) {
@@ -594,7 +648,8 @@ var schema = new Schema({
594
648
  {
595
649
  href: mark.attrs["href"],
596
650
  rel: "noopener",
597
- target: "_blank"
651
+ target: "_blank",
652
+ ...mark.attrs["targetFrame"] ? { "data-target-frame": String(mark.attrs["targetFrame"]) } : {}
598
653
  },
599
654
  0
600
655
  ];
@@ -8,7 +8,7 @@ import { Schema } from 'prosemirror-model';
8
8
  * extend THIS schema so the importer, layout engine, and (canvas) painter all
9
9
  * agree on one document model.
10
10
  */
11
- export declare const schema: Schema<"paragraph" | "doc" | "text" | "hard_break" | "image" | "page_field" | "table" | "table_row" | "table_cell", "strong" | "em" | "underline" | "strike" | "dstrike" | "smallCaps" | "textColor" | "fontSize" | "vertAlign" | "letterSpacing" | "charScale" | "position" | "highlight" | "fontFamily" | "link" | "footnote" | "carryRPr">;
11
+ export declare const schema: Schema<"paragraph" | "doc" | "text" | "hard_break" | "image" | "page_field" | "table" | "table_row" | "table_cell", "strong" | "em" | "underline" | "strike" | "dstrike" | "smallCaps" | "textColor" | "fontSize" | "vertAlign" | "letterSpacing" | "kern" | "charScale" | "position" | "highlight" | "fontFamily" | "link" | "footnote" | "carryRPr">;
12
12
  /** Concrete schema type, handy for typing Node/Mark across packages. */
13
13
  export type BapbongSchema = typeof schema;
14
14
  /**
@@ -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;AAkF3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,+UA0jBjB,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;AAwF3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,wVA+mBjB,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.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "bapbong — ProseMirror document model / schema",
5
5
  "license": "MIT",
6
6
  "repository": {