@shadow-garden/bapbong-model 0.13.0 → 0.15.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
@@ -113,6 +113,22 @@ function astToLinear(row) {
113
113
  const hi = astToLinear(n.hi);
114
114
  return n.op + (lo ? sub(lo) : "") + (hi ? sup(hi) : "") + paren(astToLinear(n.body));
115
115
  }
116
+ case "func":
117
+ return `${astToLinear(n.name)}\u2061${paren(astToLinear(n.body))}`;
118
+ case "acc":
119
+ return astToLinear(n.body) + n.chr;
120
+ case "lim": {
121
+ const l = astToLinear(n.lim);
122
+ return astToLinear(n.base) + (l ? n.below ? sub(l) : sup(l) : "");
123
+ }
124
+ case "mat": {
125
+ const lines = [];
126
+ for (let i = 0; i < n.cells.length; i += n.cols)
127
+ lines.push(
128
+ n.cells.slice(i, i + n.cols).map((c) => astToLinear(c)).join("&")
129
+ );
130
+ return `(${lines.join("@")})`;
131
+ }
116
132
  }
117
133
  };
118
134
  return row.map(one).join("");
@@ -133,9 +149,227 @@ function isEqRow(v) {
133
149
  return typeof n.l === "string" && typeof n.r === "string" && isEqRow(n.body);
134
150
  if (t === "big")
135
151
  return typeof n.op === "string" && isEqRow(n.lo) && isEqRow(n.hi) && isEqRow(n.body);
152
+ if (t === "func")
153
+ return isEqRow(n.name) && isEqRow(n.body);
154
+ if (t === "acc")
155
+ return typeof n.chr === "string" && isEqRow(n.body);
156
+ if (t === "lim")
157
+ return typeof n.below === "boolean" && isEqRow(n.base) && isEqRow(n.lim);
158
+ if (t === "mat") {
159
+ const m = n;
160
+ return typeof m.cols === "number" && m.cols > 0 && Array.isArray(m.cells) && m.cells.every((c) => isEqRow(c));
161
+ }
136
162
  return false;
137
163
  });
138
164
  }
165
+ var frac = () => ({ t: "frac", num: [], den: [] });
166
+ var scr = (slots) => ({
167
+ t: "scr",
168
+ base: [],
169
+ sub: [],
170
+ sup: [],
171
+ slots
172
+ });
173
+ var rad = (deg) => ({
174
+ t: "rad",
175
+ // A degree the template fills in — the 3 of a cube root — is content like
176
+ // any other: the caret can reach it and type over it.
177
+ deg: deg ? upright(deg) : [],
178
+ body: [],
179
+ showDeg: deg !== null
180
+ });
181
+ var fence = (l, r) => ({
182
+ t: "fence",
183
+ l,
184
+ r,
185
+ body: []
186
+ });
187
+ var upright = (s) => [...s].map((ch) => ({ t: "chr", ch }));
188
+ var func = (name) => ({
189
+ t: "func",
190
+ name: upright(name),
191
+ body: []
192
+ });
193
+ var acc = (chr) => ({ t: "acc", chr, body: [] });
194
+ var funcSub = (name) => ({
195
+ t: "func",
196
+ name: [{ t: "scr", base: upright(name), sub: [], sup: [], slots: "sub" }],
197
+ body: []
198
+ });
199
+ var mat = (rows, cols) => ({
200
+ t: "mat",
201
+ cols,
202
+ cells: Array.from({ length: rows * cols }, () => [])
203
+ });
204
+ var braced = (l, r, rows, cols) => ({
205
+ t: "fence",
206
+ l,
207
+ r,
208
+ body: [mat(rows, cols)]
209
+ });
210
+ var limFunc = (name) => ({
211
+ t: "func",
212
+ name: [{ t: "lim", base: upright(name), lim: [], below: true }],
213
+ body: []
214
+ });
215
+ var big = (op, limits = false) => ({
216
+ t: "big",
217
+ op,
218
+ lo: [],
219
+ hi: [],
220
+ body: [],
221
+ showLo: limits,
222
+ showHi: limits
223
+ });
224
+ var EQ_STRUCTURES = [
225
+ { group: "Fraction", name: "Stacked", node: frac(), focus: ["num"] },
226
+ { group: "Script", name: "Superscript", node: scr("sup"), focus: ["base"] },
227
+ { group: "Script", name: "Subscript", node: scr("sub"), focus: ["base"] },
228
+ {
229
+ group: "Script",
230
+ name: "Sub and super",
231
+ node: scr("both"),
232
+ focus: ["base"]
233
+ },
234
+ { group: "Radical", name: "Square root", node: rad(null), focus: ["body"] },
235
+ { group: "Radical", name: "Cube root", node: rad("3"), focus: ["body"] },
236
+ { group: "Radical", name: "Nth root", node: rad(""), focus: ["deg"] },
237
+ { group: "Integral", name: "Integral", node: big("\u222B"), focus: ["body"] },
238
+ { group: "Integral", name: "Definite", node: big("\u222B", true), focus: ["lo"] },
239
+ { group: "Integral", name: "Double", node: big("\u222C"), focus: ["body"] },
240
+ { group: "Integral", name: "Contour", node: big("\u222E"), focus: ["body"] },
241
+ {
242
+ group: "Large operator",
243
+ name: "Summation",
244
+ node: big("\u2211"),
245
+ focus: ["body"]
246
+ },
247
+ {
248
+ group: "Large operator",
249
+ name: "Sum with limits",
250
+ node: big("\u2211", true),
251
+ focus: ["lo"]
252
+ },
253
+ { group: "Large operator", name: "Product", node: big("\u220F"), focus: ["body"] },
254
+ {
255
+ group: "Large operator",
256
+ name: "Product with limits",
257
+ node: big("\u220F", true),
258
+ focus: ["lo"]
259
+ },
260
+ { group: "Large operator", name: "Union", node: big("\u22C3"), focus: ["body"] },
261
+ {
262
+ group: "Large operator",
263
+ name: "Intersection",
264
+ node: big("\u22C2"),
265
+ focus: ["body"]
266
+ },
267
+ {
268
+ group: "Bracket",
269
+ name: "Parentheses",
270
+ node: fence("(", ")"),
271
+ focus: ["body"]
272
+ },
273
+ {
274
+ group: "Bracket",
275
+ name: "Brackets",
276
+ node: fence("[", "]"),
277
+ focus: ["body"]
278
+ },
279
+ { group: "Bracket", name: "Braces", node: fence("{", "}"), focus: ["body"] },
280
+ {
281
+ group: "Bracket",
282
+ name: "Absolute value",
283
+ node: fence("|", "|"),
284
+ focus: ["body"]
285
+ },
286
+ { group: "Bracket", name: "Norm", node: fence("\u2016", "\u2016"), focus: ["body"] },
287
+ { group: "Bracket", name: "Angle", node: fence("\u27E8", "\u27E9"), focus: ["body"] },
288
+ { group: "Bracket", name: "Floor", node: fence("\u230A", "\u230B"), focus: ["body"] },
289
+ { group: "Bracket", name: "Ceiling", node: fence("\u2308", "\u2309"), focus: ["body"] },
290
+ { group: "Function", name: "sin", node: func("sin"), focus: ["body"] },
291
+ { group: "Function", name: "cos", node: func("cos"), focus: ["body"] },
292
+ { group: "Function", name: "tan", node: func("tan"), focus: ["body"] },
293
+ { group: "Function", name: "cot", node: func("cot"), focus: ["body"] },
294
+ { group: "Function", name: "sec", node: func("sec"), focus: ["body"] },
295
+ { group: "Function", name: "csc", node: func("csc"), focus: ["body"] },
296
+ { group: "Function", name: "arcsin", node: func("arcsin"), focus: ["body"] },
297
+ { group: "Function", name: "arccos", node: func("arccos"), focus: ["body"] },
298
+ { group: "Function", name: "arctan", node: func("arctan"), focus: ["body"] },
299
+ { group: "Function", name: "sinh", node: func("sinh"), focus: ["body"] },
300
+ { group: "Function", name: "cosh", node: func("cosh"), focus: ["body"] },
301
+ { group: "Function", name: "tanh", node: func("tanh"), focus: ["body"] },
302
+ { group: "Function", name: "exp", node: func("exp"), focus: ["body"] },
303
+ // The name is empty and editable — for anything the list does not carry.
304
+ { group: "Function", name: "Custom", node: func(""), focus: ["name"] },
305
+ { group: "Accent", name: "Bar", node: acc("\u0305"), focus: ["body"] },
306
+ { group: "Accent", name: "Vector", node: acc("\u20D7"), focus: ["body"] },
307
+ { group: "Accent", name: "Hat", node: acc("\u0302"), focus: ["body"] },
308
+ { group: "Accent", name: "Tilde", node: acc("\u0303"), focus: ["body"] },
309
+ { group: "Accent", name: "Dot", node: acc("\u0307"), focus: ["body"] },
310
+ { group: "Accent", name: "Double dot", node: acc("\u0308"), focus: ["body"] },
311
+ // Word keeps the logarithms and the limit operators in ONE gallery, and so
312
+ // do we: they are the same shape — a name that may carry something under
313
+ // or beside it, applied to an expression.
314
+ // The base rides the NAME, not the argument, and the caret opens on it —
315
+ // it is the part you came to this entry to type.
316
+ {
317
+ group: "Limit and log",
318
+ name: "log base",
319
+ node: funcSub("log"),
320
+ focus: ["name", 0, "sub"]
321
+ },
322
+ { group: "Limit and log", name: "log", node: func("log"), focus: ["body"] },
323
+ {
324
+ group: "Limit and log",
325
+ name: "lim",
326
+ node: limFunc("lim"),
327
+ focus: ["name", 0, "lim"]
328
+ },
329
+ {
330
+ group: "Limit and log",
331
+ name: "min",
332
+ node: limFunc("min"),
333
+ focus: ["name", 0, "lim"]
334
+ },
335
+ {
336
+ group: "Limit and log",
337
+ name: "max",
338
+ node: limFunc("max"),
339
+ focus: ["name", 0, "lim"]
340
+ },
341
+ { group: "Limit and log", name: "ln", node: func("ln"), focus: ["body"] },
342
+ { group: "Matrix", name: "1\xD72", node: mat(1, 2), focus: ["c0"] },
343
+ { group: "Matrix", name: "2\xD71", node: mat(2, 1), focus: ["c0"] },
344
+ { group: "Matrix", name: "2\xD72", node: mat(2, 2), focus: ["c0"] },
345
+ { group: "Matrix", name: "3\xD73", node: mat(3, 3), focus: ["c0"] },
346
+ {
347
+ group: "Matrix",
348
+ name: "Bracketed 2\xD72",
349
+ node: braced("[", "]", 2, 2),
350
+ focus: ["body", 0, "c0"]
351
+ },
352
+ {
353
+ group: "Matrix",
354
+ name: "Determinant 2\xD72",
355
+ node: braced("|", "|", 2, 2),
356
+ focus: ["body", 0, "c0"]
357
+ },
358
+ // Two and three equations under one brace — how a system is set in
359
+ // Vietnamese exam papers, and awkward to build out of the pieces.
360
+ {
361
+ group: "Matrix",
362
+ name: "System of 2",
363
+ node: braced("{", "", 2, 1),
364
+ focus: ["body", 0, "c0"]
365
+ },
366
+ {
367
+ group: "Matrix",
368
+ name: "System of 3",
369
+ node: braced("{", "", 3, 1),
370
+ focus: ["body", 0, "c0"]
371
+ }
372
+ ];
139
373
 
140
374
  // packages/model/src/lib/model.ts
141
375
  function dataJson(el, name) {
@@ -193,8 +427,8 @@ function pastedCellAttrs(el) {
193
427
  colspan: span("colspan"),
194
428
  rowspan: span("rowspan"),
195
429
  colwidth: dataJson(el, "data-colwidth"),
196
- background: bg ? bg[1].trim() : null,
197
- vAlign: e.getAttribute("data-valign"),
430
+ background: bg ? bg[1].trim() : e.getAttribute("data-background") === "none" ? false : null,
431
+ vAlign: e.getAttribute("data-valign") === "none" ? false : e.getAttribute("data-valign"),
198
432
  borders: dataJson(el, "data-borders"),
199
433
  diagonals: dataJson(el, "data-diagonals"),
200
434
  padding: dataJson(el, "data-padding"),
@@ -224,6 +458,13 @@ var schema = new import_prosemirror_model.Schema({
224
458
  // CommentNode[] (contracts) — comment threads keyed to `comment` marks.
225
459
  // Edited via setDocAttribute so add/reply/resolve/delete undo cleanly.
226
460
  comments: { default: null },
461
+ // TableStyleSheet (contracts) — every table style the document's
462
+ // tables name, fully resolved (basedOn rolled up, theme colours hex).
463
+ // LIVE data, not a bake: tables carry styleId/look attrs and the
464
+ // layout applies the sheet per cell, so flipping a tblLook gate or
465
+ // switching styles is one small attr transaction. Importer-set;
466
+ // extended when the editor applies a style the sheet lacks.
467
+ tableStyles: { default: null },
227
468
  // Per-section header/footer story OVERRIDES, keyed by section index →
228
469
  // story ('headers'|'footers') → variant ('default'|'first'|'even') →
229
470
  // the full story doc as JSON. The first chrome EDIT the model supports
@@ -430,6 +671,11 @@ var schema = new import_prosemirror_model.Schema({
430
671
  // The same equation as an AST (EqNode[]) — what conversion turns
431
672
  // into a real 2D equation node. Null when undecodable.
432
673
  equationAst: { default: null },
674
+ // `o:OLEObject/@ProgID` when this box is an EMBEDDED OBJECT rather
675
+ // than a picture ("Equation.DSMT4" for MathType). The bitmap is only
676
+ // the object's preview, so the editor offers object tools, not the
677
+ // picture toolkit. Null for real pictures.
678
+ oleProgId: { default: null },
433
679
  // w:position on the run holding a legacy object — baseline shift in
434
680
  // px, positive UP (same convention as InlineRun.raise). MathType
435
681
  // lowers every equation so its baseline meets the text line's.
@@ -502,6 +748,14 @@ var schema = new import_prosemirror_model.Schema({
502
748
  // the importer). null = Word's implicit outdent by the left cell
503
749
  // margin. Importer-set; the element itself rides carry for export.
504
750
  indent: { default: null },
751
+ // w:tblStyle — the table style this table names, or null. The style's
752
+ // definition lives in doc.attrs.tableStyles; the LAYOUT applies it,
753
+ // so this attr (with `look`) is the whole apply-a-style transaction.
754
+ styleId: { default: null },
755
+ // w:tblLook — the six conditional-formatting gates (TableLook,
756
+ // contracts), or null for Word's default 04A0 (firstRow + firstCol +
757
+ // hBand on).
758
+ look: { default: null },
505
759
  // Carry-through fidelity: unmodelled w:tblPr children (tblStyle,
506
760
  // tblLayout, tblLook, tblInd, floating tblpPr, …) as one raw XML
507
761
  // string ({ tblPr: string }), or null. Importer-set; the exporter
@@ -519,6 +773,8 @@ var schema = new import_prosemirror_model.Schema({
519
773
  cellPadding: dataJson(el, "data-cell-padding"),
520
774
  align: el.getAttribute("data-align"),
521
775
  indent: dataJson(el, "data-indent"),
776
+ styleId: el.getAttribute("data-style-id"),
777
+ look: dataJson(el, "data-look"),
522
778
  carry: dataJson(el, "data-carry")
523
779
  })
524
780
  }
@@ -531,6 +787,8 @@ var schema = new import_prosemirror_model.Schema({
531
787
  dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
532
788
  if (a["align"]) dom["data-align"] = String(a["align"]);
533
789
  if (a["indent"] != null) dom["data-indent"] = String(a["indent"]);
790
+ if (a["styleId"]) dom["data-style-id"] = String(a["styleId"]);
791
+ if (a["look"]) dom["data-look"] = JSON.stringify(a["look"]);
534
792
  if (a["carry"]) dom["data-carry"] = JSON.stringify(a["carry"]);
535
793
  return ["table", dom, ["tbody", 0]];
536
794
  }
@@ -579,10 +837,13 @@ var schema = new import_prosemirror_model.Schema({
579
837
  rowspan: { default: 1 },
580
838
  colwidth: { default: null },
581
839
  // px widths of the spanned columns, or null
840
+ // w:shd w:fill — cell fill "#RRGGBB". `false` is an EXPLICIT no-fill
841
+ // (w:fill="auto"), which must beat a table style's fill; null means
842
+ // the cell says nothing and the style layer may paint.
582
843
  background: { default: null },
583
- // w:shd w:fill cell fill "#RRGGBB"
844
+ // w:vAlign'center' | 'bottom' (top is Word's default). `false` is
845
+ // an explicit reset ("top"/"both" declared), beating a style's.
584
846
  vAlign: { default: null },
585
- // w:vAlign — 'center' | 'bottom' (top default)
586
847
  borders: { default: null },
587
848
  // w:tcBorders per-side visibility override
588
849
  // w:tcBorders/w:tl2br + w:br2tl — rules across the cell's corners
@@ -605,10 +866,13 @@ var schema = new import_prosemirror_model.Schema({
605
866
  attrs["rowspan"] = String(node.attrs["rowspan"]);
606
867
  if (node.attrs["background"])
607
868
  attrs["style"] = `background-color: ${node.attrs["background"]}`;
869
+ else if (node.attrs["background"] === false)
870
+ attrs["data-background"] = "none";
608
871
  if (node.attrs["colwidth"])
609
872
  attrs["data-colwidth"] = JSON.stringify(node.attrs["colwidth"]);
610
873
  if (node.attrs["vAlign"])
611
874
  attrs["data-valign"] = String(node.attrs["vAlign"]);
875
+ else if (node.attrs["vAlign"] === false) attrs["data-valign"] = "none";
612
876
  if (node.attrs["borders"])
613
877
  attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
614
878
  if (node.attrs["diagonals"])
package/dist/index.js CHANGED
@@ -81,6 +81,22 @@ function astToLinear(row) {
81
81
  const hi = astToLinear(n.hi);
82
82
  return n.op + (lo ? sub(lo) : "") + (hi ? sup(hi) : "") + paren(astToLinear(n.body));
83
83
  }
84
+ case "func":
85
+ return `${astToLinear(n.name)}\u2061${paren(astToLinear(n.body))}`;
86
+ case "acc":
87
+ return astToLinear(n.body) + n.chr;
88
+ case "lim": {
89
+ const l = astToLinear(n.lim);
90
+ return astToLinear(n.base) + (l ? n.below ? sub(l) : sup(l) : "");
91
+ }
92
+ case "mat": {
93
+ const lines = [];
94
+ for (let i = 0; i < n.cells.length; i += n.cols)
95
+ lines.push(
96
+ n.cells.slice(i, i + n.cols).map((c) => astToLinear(c)).join("&")
97
+ );
98
+ return `(${lines.join("@")})`;
99
+ }
84
100
  }
85
101
  };
86
102
  return row.map(one).join("");
@@ -101,9 +117,227 @@ function isEqRow(v) {
101
117
  return typeof n.l === "string" && typeof n.r === "string" && isEqRow(n.body);
102
118
  if (t === "big")
103
119
  return typeof n.op === "string" && isEqRow(n.lo) && isEqRow(n.hi) && isEqRow(n.body);
120
+ if (t === "func")
121
+ return isEqRow(n.name) && isEqRow(n.body);
122
+ if (t === "acc")
123
+ return typeof n.chr === "string" && isEqRow(n.body);
124
+ if (t === "lim")
125
+ return typeof n.below === "boolean" && isEqRow(n.base) && isEqRow(n.lim);
126
+ if (t === "mat") {
127
+ const m = n;
128
+ return typeof m.cols === "number" && m.cols > 0 && Array.isArray(m.cells) && m.cells.every((c) => isEqRow(c));
129
+ }
104
130
  return false;
105
131
  });
106
132
  }
133
+ var frac = () => ({ t: "frac", num: [], den: [] });
134
+ var scr = (slots) => ({
135
+ t: "scr",
136
+ base: [],
137
+ sub: [],
138
+ sup: [],
139
+ slots
140
+ });
141
+ var rad = (deg) => ({
142
+ t: "rad",
143
+ // A degree the template fills in — the 3 of a cube root — is content like
144
+ // any other: the caret can reach it and type over it.
145
+ deg: deg ? upright(deg) : [],
146
+ body: [],
147
+ showDeg: deg !== null
148
+ });
149
+ var fence = (l, r) => ({
150
+ t: "fence",
151
+ l,
152
+ r,
153
+ body: []
154
+ });
155
+ var upright = (s) => [...s].map((ch) => ({ t: "chr", ch }));
156
+ var func = (name) => ({
157
+ t: "func",
158
+ name: upright(name),
159
+ body: []
160
+ });
161
+ var acc = (chr) => ({ t: "acc", chr, body: [] });
162
+ var funcSub = (name) => ({
163
+ t: "func",
164
+ name: [{ t: "scr", base: upright(name), sub: [], sup: [], slots: "sub" }],
165
+ body: []
166
+ });
167
+ var mat = (rows, cols) => ({
168
+ t: "mat",
169
+ cols,
170
+ cells: Array.from({ length: rows * cols }, () => [])
171
+ });
172
+ var braced = (l, r, rows, cols) => ({
173
+ t: "fence",
174
+ l,
175
+ r,
176
+ body: [mat(rows, cols)]
177
+ });
178
+ var limFunc = (name) => ({
179
+ t: "func",
180
+ name: [{ t: "lim", base: upright(name), lim: [], below: true }],
181
+ body: []
182
+ });
183
+ var big = (op, limits = false) => ({
184
+ t: "big",
185
+ op,
186
+ lo: [],
187
+ hi: [],
188
+ body: [],
189
+ showLo: limits,
190
+ showHi: limits
191
+ });
192
+ var EQ_STRUCTURES = [
193
+ { group: "Fraction", name: "Stacked", node: frac(), focus: ["num"] },
194
+ { group: "Script", name: "Superscript", node: scr("sup"), focus: ["base"] },
195
+ { group: "Script", name: "Subscript", node: scr("sub"), focus: ["base"] },
196
+ {
197
+ group: "Script",
198
+ name: "Sub and super",
199
+ node: scr("both"),
200
+ focus: ["base"]
201
+ },
202
+ { group: "Radical", name: "Square root", node: rad(null), focus: ["body"] },
203
+ { group: "Radical", name: "Cube root", node: rad("3"), focus: ["body"] },
204
+ { group: "Radical", name: "Nth root", node: rad(""), focus: ["deg"] },
205
+ { group: "Integral", name: "Integral", node: big("\u222B"), focus: ["body"] },
206
+ { group: "Integral", name: "Definite", node: big("\u222B", true), focus: ["lo"] },
207
+ { group: "Integral", name: "Double", node: big("\u222C"), focus: ["body"] },
208
+ { group: "Integral", name: "Contour", node: big("\u222E"), focus: ["body"] },
209
+ {
210
+ group: "Large operator",
211
+ name: "Summation",
212
+ node: big("\u2211"),
213
+ focus: ["body"]
214
+ },
215
+ {
216
+ group: "Large operator",
217
+ name: "Sum with limits",
218
+ node: big("\u2211", true),
219
+ focus: ["lo"]
220
+ },
221
+ { group: "Large operator", name: "Product", node: big("\u220F"), focus: ["body"] },
222
+ {
223
+ group: "Large operator",
224
+ name: "Product with limits",
225
+ node: big("\u220F", true),
226
+ focus: ["lo"]
227
+ },
228
+ { group: "Large operator", name: "Union", node: big("\u22C3"), focus: ["body"] },
229
+ {
230
+ group: "Large operator",
231
+ name: "Intersection",
232
+ node: big("\u22C2"),
233
+ focus: ["body"]
234
+ },
235
+ {
236
+ group: "Bracket",
237
+ name: "Parentheses",
238
+ node: fence("(", ")"),
239
+ focus: ["body"]
240
+ },
241
+ {
242
+ group: "Bracket",
243
+ name: "Brackets",
244
+ node: fence("[", "]"),
245
+ focus: ["body"]
246
+ },
247
+ { group: "Bracket", name: "Braces", node: fence("{", "}"), focus: ["body"] },
248
+ {
249
+ group: "Bracket",
250
+ name: "Absolute value",
251
+ node: fence("|", "|"),
252
+ focus: ["body"]
253
+ },
254
+ { group: "Bracket", name: "Norm", node: fence("\u2016", "\u2016"), focus: ["body"] },
255
+ { group: "Bracket", name: "Angle", node: fence("\u27E8", "\u27E9"), focus: ["body"] },
256
+ { group: "Bracket", name: "Floor", node: fence("\u230A", "\u230B"), focus: ["body"] },
257
+ { group: "Bracket", name: "Ceiling", node: fence("\u2308", "\u2309"), focus: ["body"] },
258
+ { group: "Function", name: "sin", node: func("sin"), focus: ["body"] },
259
+ { group: "Function", name: "cos", node: func("cos"), focus: ["body"] },
260
+ { group: "Function", name: "tan", node: func("tan"), focus: ["body"] },
261
+ { group: "Function", name: "cot", node: func("cot"), focus: ["body"] },
262
+ { group: "Function", name: "sec", node: func("sec"), focus: ["body"] },
263
+ { group: "Function", name: "csc", node: func("csc"), focus: ["body"] },
264
+ { group: "Function", name: "arcsin", node: func("arcsin"), focus: ["body"] },
265
+ { group: "Function", name: "arccos", node: func("arccos"), focus: ["body"] },
266
+ { group: "Function", name: "arctan", node: func("arctan"), focus: ["body"] },
267
+ { group: "Function", name: "sinh", node: func("sinh"), focus: ["body"] },
268
+ { group: "Function", name: "cosh", node: func("cosh"), focus: ["body"] },
269
+ { group: "Function", name: "tanh", node: func("tanh"), focus: ["body"] },
270
+ { group: "Function", name: "exp", node: func("exp"), focus: ["body"] },
271
+ // The name is empty and editable — for anything the list does not carry.
272
+ { group: "Function", name: "Custom", node: func(""), focus: ["name"] },
273
+ { group: "Accent", name: "Bar", node: acc("\u0305"), focus: ["body"] },
274
+ { group: "Accent", name: "Vector", node: acc("\u20D7"), focus: ["body"] },
275
+ { group: "Accent", name: "Hat", node: acc("\u0302"), focus: ["body"] },
276
+ { group: "Accent", name: "Tilde", node: acc("\u0303"), focus: ["body"] },
277
+ { group: "Accent", name: "Dot", node: acc("\u0307"), focus: ["body"] },
278
+ { group: "Accent", name: "Double dot", node: acc("\u0308"), focus: ["body"] },
279
+ // Word keeps the logarithms and the limit operators in ONE gallery, and so
280
+ // do we: they are the same shape — a name that may carry something under
281
+ // or beside it, applied to an expression.
282
+ // The base rides the NAME, not the argument, and the caret opens on it —
283
+ // it is the part you came to this entry to type.
284
+ {
285
+ group: "Limit and log",
286
+ name: "log base",
287
+ node: funcSub("log"),
288
+ focus: ["name", 0, "sub"]
289
+ },
290
+ { group: "Limit and log", name: "log", node: func("log"), focus: ["body"] },
291
+ {
292
+ group: "Limit and log",
293
+ name: "lim",
294
+ node: limFunc("lim"),
295
+ focus: ["name", 0, "lim"]
296
+ },
297
+ {
298
+ group: "Limit and log",
299
+ name: "min",
300
+ node: limFunc("min"),
301
+ focus: ["name", 0, "lim"]
302
+ },
303
+ {
304
+ group: "Limit and log",
305
+ name: "max",
306
+ node: limFunc("max"),
307
+ focus: ["name", 0, "lim"]
308
+ },
309
+ { group: "Limit and log", name: "ln", node: func("ln"), focus: ["body"] },
310
+ { group: "Matrix", name: "1\xD72", node: mat(1, 2), focus: ["c0"] },
311
+ { group: "Matrix", name: "2\xD71", node: mat(2, 1), focus: ["c0"] },
312
+ { group: "Matrix", name: "2\xD72", node: mat(2, 2), focus: ["c0"] },
313
+ { group: "Matrix", name: "3\xD73", node: mat(3, 3), focus: ["c0"] },
314
+ {
315
+ group: "Matrix",
316
+ name: "Bracketed 2\xD72",
317
+ node: braced("[", "]", 2, 2),
318
+ focus: ["body", 0, "c0"]
319
+ },
320
+ {
321
+ group: "Matrix",
322
+ name: "Determinant 2\xD72",
323
+ node: braced("|", "|", 2, 2),
324
+ focus: ["body", 0, "c0"]
325
+ },
326
+ // Two and three equations under one brace — how a system is set in
327
+ // Vietnamese exam papers, and awkward to build out of the pieces.
328
+ {
329
+ group: "Matrix",
330
+ name: "System of 2",
331
+ node: braced("{", "", 2, 1),
332
+ focus: ["body", 0, "c0"]
333
+ },
334
+ {
335
+ group: "Matrix",
336
+ name: "System of 3",
337
+ node: braced("{", "", 3, 1),
338
+ focus: ["body", 0, "c0"]
339
+ }
340
+ ];
107
341
 
108
342
  // packages/model/src/lib/model.ts
109
343
  function dataJson(el, name) {
@@ -161,8 +395,8 @@ function pastedCellAttrs(el) {
161
395
  colspan: span("colspan"),
162
396
  rowspan: span("rowspan"),
163
397
  colwidth: dataJson(el, "data-colwidth"),
164
- background: bg ? bg[1].trim() : null,
165
- vAlign: e.getAttribute("data-valign"),
398
+ background: bg ? bg[1].trim() : e.getAttribute("data-background") === "none" ? false : null,
399
+ vAlign: e.getAttribute("data-valign") === "none" ? false : e.getAttribute("data-valign"),
166
400
  borders: dataJson(el, "data-borders"),
167
401
  diagonals: dataJson(el, "data-diagonals"),
168
402
  padding: dataJson(el, "data-padding"),
@@ -192,6 +426,13 @@ var schema = new Schema({
192
426
  // CommentNode[] (contracts) — comment threads keyed to `comment` marks.
193
427
  // Edited via setDocAttribute so add/reply/resolve/delete undo cleanly.
194
428
  comments: { default: null },
429
+ // TableStyleSheet (contracts) — every table style the document's
430
+ // tables name, fully resolved (basedOn rolled up, theme colours hex).
431
+ // LIVE data, not a bake: tables carry styleId/look attrs and the
432
+ // layout applies the sheet per cell, so flipping a tblLook gate or
433
+ // switching styles is one small attr transaction. Importer-set;
434
+ // extended when the editor applies a style the sheet lacks.
435
+ tableStyles: { default: null },
195
436
  // Per-section header/footer story OVERRIDES, keyed by section index →
196
437
  // story ('headers'|'footers') → variant ('default'|'first'|'even') →
197
438
  // the full story doc as JSON. The first chrome EDIT the model supports
@@ -398,6 +639,11 @@ var schema = new Schema({
398
639
  // The same equation as an AST (EqNode[]) — what conversion turns
399
640
  // into a real 2D equation node. Null when undecodable.
400
641
  equationAst: { default: null },
642
+ // `o:OLEObject/@ProgID` when this box is an EMBEDDED OBJECT rather
643
+ // than a picture ("Equation.DSMT4" for MathType). The bitmap is only
644
+ // the object's preview, so the editor offers object tools, not the
645
+ // picture toolkit. Null for real pictures.
646
+ oleProgId: { default: null },
401
647
  // w:position on the run holding a legacy object — baseline shift in
402
648
  // px, positive UP (same convention as InlineRun.raise). MathType
403
649
  // lowers every equation so its baseline meets the text line's.
@@ -470,6 +716,14 @@ var schema = new Schema({
470
716
  // the importer). null = Word's implicit outdent by the left cell
471
717
  // margin. Importer-set; the element itself rides carry for export.
472
718
  indent: { default: null },
719
+ // w:tblStyle — the table style this table names, or null. The style's
720
+ // definition lives in doc.attrs.tableStyles; the LAYOUT applies it,
721
+ // so this attr (with `look`) is the whole apply-a-style transaction.
722
+ styleId: { default: null },
723
+ // w:tblLook — the six conditional-formatting gates (TableLook,
724
+ // contracts), or null for Word's default 04A0 (firstRow + firstCol +
725
+ // hBand on).
726
+ look: { default: null },
473
727
  // Carry-through fidelity: unmodelled w:tblPr children (tblStyle,
474
728
  // tblLayout, tblLook, tblInd, floating tblpPr, …) as one raw XML
475
729
  // string ({ tblPr: string }), or null. Importer-set; the exporter
@@ -487,6 +741,8 @@ var schema = new Schema({
487
741
  cellPadding: dataJson(el, "data-cell-padding"),
488
742
  align: el.getAttribute("data-align"),
489
743
  indent: dataJson(el, "data-indent"),
744
+ styleId: el.getAttribute("data-style-id"),
745
+ look: dataJson(el, "data-look"),
490
746
  carry: dataJson(el, "data-carry")
491
747
  })
492
748
  }
@@ -499,6 +755,8 @@ var schema = new Schema({
499
755
  dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
500
756
  if (a["align"]) dom["data-align"] = String(a["align"]);
501
757
  if (a["indent"] != null) dom["data-indent"] = String(a["indent"]);
758
+ if (a["styleId"]) dom["data-style-id"] = String(a["styleId"]);
759
+ if (a["look"]) dom["data-look"] = JSON.stringify(a["look"]);
502
760
  if (a["carry"]) dom["data-carry"] = JSON.stringify(a["carry"]);
503
761
  return ["table", dom, ["tbody", 0]];
504
762
  }
@@ -547,10 +805,13 @@ var schema = new Schema({
547
805
  rowspan: { default: 1 },
548
806
  colwidth: { default: null },
549
807
  // px widths of the spanned columns, or null
808
+ // w:shd w:fill — cell fill "#RRGGBB". `false` is an EXPLICIT no-fill
809
+ // (w:fill="auto"), which must beat a table style's fill; null means
810
+ // the cell says nothing and the style layer may paint.
550
811
  background: { default: null },
551
- // w:shd w:fill cell fill "#RRGGBB"
812
+ // w:vAlign'center' | 'bottom' (top is Word's default). `false` is
813
+ // an explicit reset ("top"/"both" declared), beating a style's.
552
814
  vAlign: { default: null },
553
- // w:vAlign — 'center' | 'bottom' (top default)
554
815
  borders: { default: null },
555
816
  // w:tcBorders per-side visibility override
556
817
  // w:tcBorders/w:tl2br + w:br2tl — rules across the cell's corners
@@ -573,10 +834,13 @@ var schema = new Schema({
573
834
  attrs["rowspan"] = String(node.attrs["rowspan"]);
574
835
  if (node.attrs["background"])
575
836
  attrs["style"] = `background-color: ${node.attrs["background"]}`;
837
+ else if (node.attrs["background"] === false)
838
+ attrs["data-background"] = "none";
576
839
  if (node.attrs["colwidth"])
577
840
  attrs["data-colwidth"] = JSON.stringify(node.attrs["colwidth"]);
578
841
  if (node.attrs["vAlign"])
579
842
  attrs["data-valign"] = String(node.attrs["vAlign"]);
843
+ else if (node.attrs["vAlign"] === false) attrs["data-valign"] = "none";
580
844
  if (node.attrs["borders"])
581
845
  attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
582
846
  if (node.attrs["diagonals"])
@@ -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;AA2F3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,+XAsuBjB,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;IACxC;;;6EAGyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;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;AAkG3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,+XAswBjB,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;IACxC;;;6EAGyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;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.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "bapbong — ProseMirror document model / schema",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -55,6 +55,6 @@
55
55
  },
56
56
  "dependencies": {
57
57
  "prosemirror-model": "^1.25.7",
58
- "@shadow-garden/bapbong-contracts": "^0.14.0"
58
+ "@shadow-garden/bapbong-contracts": "^0.16.0"
59
59
  }
60
60
  }