@shadow-garden/bapbong-model 0.5.0 → 0.7.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 +150 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +146 -10
- package/dist/lib/bookmarks.d.ts +39 -0
- package/dist/lib/bookmarks.d.ts.map +1 -0
- package/dist/lib/model.d.ts +2 -2
- package/dist/lib/model.d.ts.map +1 -1
- package/dist/lib/numbering.d.ts +19 -0
- package/dist/lib/numbering.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,12 +20,55 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// packages/model/src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
anchorName: () => anchorName,
|
|
24
|
+
bookmarkLabel: () => bookmarkLabel,
|
|
23
25
|
commentSchema: () => commentSchema,
|
|
24
26
|
createNumberingCounter: () => createNumberingCounter,
|
|
27
|
+
fieldAt: () => fieldAt,
|
|
28
|
+
findBookmark: () => findBookmark,
|
|
25
29
|
schema: () => schema
|
|
26
30
|
});
|
|
27
31
|
module.exports = __toCommonJS(index_exports);
|
|
28
32
|
|
|
33
|
+
// packages/model/src/lib/bookmarks.ts
|
|
34
|
+
function anchorName(href) {
|
|
35
|
+
return href && href.startsWith("#") && href.length > 1 ? href.slice(1) : null;
|
|
36
|
+
}
|
|
37
|
+
function findBookmark(doc, name) {
|
|
38
|
+
let found = null;
|
|
39
|
+
doc.descendants((node, pos) => {
|
|
40
|
+
if (found !== null) return false;
|
|
41
|
+
if (node.type.name !== "paragraph") return true;
|
|
42
|
+
const names = node.attrs["bookmarks"];
|
|
43
|
+
if (names?.includes(name)) found = pos + 1;
|
|
44
|
+
return false;
|
|
45
|
+
});
|
|
46
|
+
return found;
|
|
47
|
+
}
|
|
48
|
+
function bookmarkLabel(doc, name, max = 60) {
|
|
49
|
+
const pos = findBookmark(doc, name);
|
|
50
|
+
if (pos === null) return null;
|
|
51
|
+
const para = doc.nodeAt(pos - 1);
|
|
52
|
+
const text = (para?.textContent ?? "").replace(/^[\s.:–—-]+/, "").trim();
|
|
53
|
+
if (!text) return null;
|
|
54
|
+
return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
|
|
55
|
+
}
|
|
56
|
+
function fieldAt(doc, pos) {
|
|
57
|
+
let hit = null;
|
|
58
|
+
let run = null;
|
|
59
|
+
doc.forEach((node, offset) => {
|
|
60
|
+
const f = node.attrs["field"];
|
|
61
|
+
if (f && run && run.field === f) {
|
|
62
|
+
run.to = offset + node.nodeSize;
|
|
63
|
+
} else {
|
|
64
|
+
if (run && hit === run) return;
|
|
65
|
+
run = f ? { field: f, from: offset, to: offset + node.nodeSize } : null;
|
|
66
|
+
}
|
|
67
|
+
if (run && hit === null && pos >= run.from && pos <= run.to) hit = run;
|
|
68
|
+
});
|
|
69
|
+
return hit;
|
|
70
|
+
}
|
|
71
|
+
|
|
29
72
|
// packages/model/src/lib/model.ts
|
|
30
73
|
var import_prosemirror_model = require("prosemirror-model");
|
|
31
74
|
function dataJson(el, name) {
|
|
@@ -43,7 +86,8 @@ function pastedParagraphAttrs(el, heading) {
|
|
|
43
86
|
return {
|
|
44
87
|
heading,
|
|
45
88
|
align: m ? m[1].toLowerCase() : null,
|
|
46
|
-
borders: dataJson(el, "data-borders")
|
|
89
|
+
borders: dataJson(el, "data-borders"),
|
|
90
|
+
carry: dataJson(el, "data-carry")
|
|
47
91
|
};
|
|
48
92
|
}
|
|
49
93
|
function pastedImageAttrs(el) {
|
|
@@ -80,7 +124,8 @@ function pastedCellAttrs(el) {
|
|
|
80
124
|
background: bg ? bg[1].trim() : null,
|
|
81
125
|
vAlign: e.getAttribute("data-valign"),
|
|
82
126
|
borders: dataJson(el, "data-borders"),
|
|
83
|
-
padding: dataJson(el, "data-padding")
|
|
127
|
+
padding: dataJson(el, "data-padding"),
|
|
128
|
+
carry: dataJson(el, "data-carry")
|
|
84
129
|
};
|
|
85
130
|
}
|
|
86
131
|
var schema = new import_prosemirror_model.Schema({
|
|
@@ -132,11 +177,33 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
132
177
|
tabs: { default: null },
|
|
133
178
|
// w:spacing — { before?, after?, line?, lineRule? }, or null.
|
|
134
179
|
spacing: { default: null },
|
|
180
|
+
// w:bookmarkStart names anchored in this paragraph (["_Toc89595219"]),
|
|
181
|
+
// or null. Link hrefs of the form "#name" resolve against these —
|
|
182
|
+
// paragraph-level is the right altitude: Word's TOC bookmarks wrap a
|
|
183
|
+
// heading's text, and jumping to the heading is what a reader wants.
|
|
184
|
+
bookmarks: { default: null },
|
|
185
|
+
// The generated field this paragraph belongs to ({ kind: 'toc',
|
|
186
|
+
// instr } for a TOC entry), or null for ordinary content. Word paints
|
|
187
|
+
// such content with field shading and regenerates it on update.
|
|
188
|
+
field: { default: null },
|
|
135
189
|
// w:pageBreakBefore — start this paragraph on a new page.
|
|
136
190
|
pageBreakBefore: { default: false },
|
|
191
|
+
// w:keepNext — stay on the same page as the next block's first line.
|
|
192
|
+
keepNext: { default: false },
|
|
193
|
+
// w:keepLines — never split this paragraph across pages.
|
|
194
|
+
keepLines: { default: false },
|
|
195
|
+
// w:widowControl — Word's default is ON; false only when the document
|
|
196
|
+
// explicitly disables widow/orphan control for this paragraph.
|
|
197
|
+
widowControl: { default: true },
|
|
137
198
|
// w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
|
|
138
199
|
// Importer-set; painted as a box around the paragraph's lines.
|
|
139
|
-
borders: { default: null }
|
|
200
|
+
borders: { default: null },
|
|
201
|
+
// Carry-through fidelity (docx round-trip): OOXML paragraph
|
|
202
|
+
// properties the model does NOT represent, preserved verbatim so a
|
|
203
|
+
// customer's save never drops them. { pPr?: string, markRPr?: string }
|
|
204
|
+
// — raw XML fragments (pPr extras / the paragraph-mark w:rPr), or
|
|
205
|
+
// null. Importer-set; the exporter splices them back into w:pPr.
|
|
206
|
+
carry: { default: null }
|
|
140
207
|
},
|
|
141
208
|
// HTML paste path: recover heading level from h1–h6 and alignment from
|
|
142
209
|
// inline style. Other attrs (list/indent/tabs/spacing) stay importer-only
|
|
@@ -156,6 +223,8 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
156
223
|
if (attrs.styleId) dom["data-style"] = attrs.styleId;
|
|
157
224
|
if (node.attrs["borders"])
|
|
158
225
|
dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
|
|
226
|
+
if (node.attrs["carry"])
|
|
227
|
+
dom["data-carry"] = JSON.stringify(node.attrs["carry"]);
|
|
159
228
|
return [tag, dom, 0];
|
|
160
229
|
}
|
|
161
230
|
},
|
|
@@ -237,7 +306,12 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
237
306
|
// insideV }, or null — OOXML tables are borderless unless declared.
|
|
238
307
|
borders: { default: null },
|
|
239
308
|
// w:tblPr/w:jc — 'center' | 'right' table alignment, or null (left).
|
|
240
|
-
align: { default: null }
|
|
309
|
+
align: { default: null },
|
|
310
|
+
// Carry-through fidelity: unmodelled w:tblPr children (tblStyle,
|
|
311
|
+
// tblLayout, tblLook, tblInd, floating tblpPr, …) as one raw XML
|
|
312
|
+
// string ({ tblPr: string }), or null. Importer-set; the exporter
|
|
313
|
+
// splices it back so a save never drops them.
|
|
314
|
+
carry: { default: null }
|
|
241
315
|
},
|
|
242
316
|
// Complex attrs round-trip as data-* JSON — ProseMirror's clipboard is
|
|
243
317
|
// a toDOM → parseDOM pass, so without this an internal copy/paste
|
|
@@ -248,7 +322,8 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
248
322
|
getAttrs: (el) => ({
|
|
249
323
|
borders: dataJson(el, "data-borders"),
|
|
250
324
|
cellPadding: dataJson(el, "data-cell-padding"),
|
|
251
|
-
align: el.getAttribute("data-align")
|
|
325
|
+
align: el.getAttribute("data-align"),
|
|
326
|
+
carry: dataJson(el, "data-carry")
|
|
252
327
|
})
|
|
253
328
|
}
|
|
254
329
|
],
|
|
@@ -259,6 +334,7 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
259
334
|
if (a["cellPadding"])
|
|
260
335
|
dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
|
|
261
336
|
if (a["align"]) dom["data-align"] = String(a["align"]);
|
|
337
|
+
if (a["carry"]) dom["data-carry"] = JSON.stringify(a["carry"]);
|
|
262
338
|
return ["table", dom, ["tbody", 0]];
|
|
263
339
|
}
|
|
264
340
|
},
|
|
@@ -271,7 +347,10 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
271
347
|
// (Word's default) means the paginator may split the row mid-content.
|
|
272
348
|
cantSplit: { default: false },
|
|
273
349
|
// w:trHeight — { value: px, exact: boolean } or null (auto).
|
|
274
|
-
height: { default: null }
|
|
350
|
+
height: { default: null },
|
|
351
|
+
// Carry-through fidelity: unmodelled w:trPr children ({ trPr: string
|
|
352
|
+
// } — gridBefore/wBefore, cnfStyle, …), or null. Importer-set.
|
|
353
|
+
carry: { default: null }
|
|
275
354
|
},
|
|
276
355
|
parseDOM: [
|
|
277
356
|
{
|
|
@@ -279,7 +358,8 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
279
358
|
getAttrs: (el) => ({
|
|
280
359
|
header: el.getAttribute("data-header") === "true",
|
|
281
360
|
cantSplit: el.getAttribute("data-cant-split") === "true",
|
|
282
|
-
height: dataJson(el, "data-height")
|
|
361
|
+
height: dataJson(el, "data-height"),
|
|
362
|
+
carry: dataJson(el, "data-carry")
|
|
283
363
|
})
|
|
284
364
|
}
|
|
285
365
|
],
|
|
@@ -289,6 +369,8 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
289
369
|
if (node.attrs["cantSplit"]) dom["data-cant-split"] = "true";
|
|
290
370
|
if (node.attrs["height"])
|
|
291
371
|
dom["data-height"] = JSON.stringify(node.attrs["height"]);
|
|
372
|
+
if (node.attrs["carry"])
|
|
373
|
+
dom["data-carry"] = JSON.stringify(node.attrs["carry"]);
|
|
292
374
|
return ["tr", dom, 0];
|
|
293
375
|
}
|
|
294
376
|
},
|
|
@@ -306,8 +388,11 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
306
388
|
// w:vAlign — 'center' | 'bottom' (top default)
|
|
307
389
|
borders: { default: null },
|
|
308
390
|
// w:tcBorders per-side visibility override
|
|
309
|
-
padding: { default: null }
|
|
391
|
+
padding: { default: null },
|
|
310
392
|
// w:tcMar per-side margin override (px)
|
|
393
|
+
// Carry-through fidelity: unmodelled w:tcPr children ({ tcPr: string
|
|
394
|
+
// } — textDirection, noWrap, tcFitText, …), or null. Importer-set.
|
|
395
|
+
carry: { default: null }
|
|
311
396
|
},
|
|
312
397
|
parseDOM: [
|
|
313
398
|
{ tag: "td", getAttrs: pastedCellAttrs },
|
|
@@ -329,6 +414,8 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
329
414
|
attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
|
|
330
415
|
if (node.attrs["padding"])
|
|
331
416
|
attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
|
|
417
|
+
if (node.attrs["carry"])
|
|
418
|
+
attrs["data-carry"] = JSON.stringify(node.attrs["carry"]);
|
|
332
419
|
return ["td", attrs, 0];
|
|
333
420
|
}
|
|
334
421
|
}
|
|
@@ -354,6 +441,32 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
354
441
|
parseDOM: [{ tag: "s" }, { tag: "strike" }],
|
|
355
442
|
toDOM: () => ["s", 0]
|
|
356
443
|
},
|
|
444
|
+
// w:dstrike — double strikethrough
|
|
445
|
+
dstrike: {
|
|
446
|
+
parseDOM: [
|
|
447
|
+
{
|
|
448
|
+
style: "text-decoration-style=double",
|
|
449
|
+
getAttrs: (value) => value === "double" ? {} : false
|
|
450
|
+
}
|
|
451
|
+
],
|
|
452
|
+
toDOM: () => [
|
|
453
|
+
"span",
|
|
454
|
+
{
|
|
455
|
+
style: "text-decoration: line-through; text-decoration-style: double"
|
|
456
|
+
},
|
|
457
|
+
0
|
|
458
|
+
]
|
|
459
|
+
},
|
|
460
|
+
// w:smallCaps
|
|
461
|
+
smallCaps: {
|
|
462
|
+
parseDOM: [
|
|
463
|
+
{
|
|
464
|
+
style: "font-variant-caps",
|
|
465
|
+
getAttrs: (value) => value === "small-caps" ? {} : false
|
|
466
|
+
}
|
|
467
|
+
],
|
|
468
|
+
toDOM: () => ["span", { style: "font-variant-caps: small-caps" }, 0]
|
|
469
|
+
},
|
|
357
470
|
// w:color — hex "#RRGGBB"
|
|
358
471
|
textColor: {
|
|
359
472
|
attrs: { color: {} },
|
|
@@ -475,6 +588,28 @@ var schema = new import_prosemirror_model.Schema({
|
|
|
475
588
|
0
|
|
476
589
|
];
|
|
477
590
|
}
|
|
591
|
+
},
|
|
592
|
+
// Carry-through fidelity (docx round-trip): run properties the model does
|
|
593
|
+
// NOT represent (w:rtl, w:kern, w:szCs, …), preserved verbatim as one raw
|
|
594
|
+
// XML fragment so saving a customer's file never drops them. Invisible —
|
|
595
|
+
// no rendering; the docx exporter splices `xml` back into the run's rPr.
|
|
596
|
+
// Typing inside/at the edge of a carried run extends the mark (inclusive
|
|
597
|
+
// default), which is the faithful behavior for properties like w:rtl.
|
|
598
|
+
carryRPr: {
|
|
599
|
+
attrs: { xml: {} },
|
|
600
|
+
toDOM(mark) {
|
|
601
|
+
return ["span", { "data-carry-rpr": String(mark.attrs["xml"]) }, 0];
|
|
602
|
+
},
|
|
603
|
+
parseDOM: [
|
|
604
|
+
{
|
|
605
|
+
tag: "span[data-carry-rpr]",
|
|
606
|
+
getAttrs: (el) => ({
|
|
607
|
+
xml: el.getAttribute(
|
|
608
|
+
"data-carry-rpr"
|
|
609
|
+
) ?? ""
|
|
610
|
+
})
|
|
611
|
+
}
|
|
612
|
+
]
|
|
478
613
|
}
|
|
479
614
|
// The `comment` mark (w:commentRangeStart/End) is contributed by the comment
|
|
480
615
|
// plugin (@shadow-garden/bapbong-comments) via the editor's schema
|
|
@@ -614,14 +749,19 @@ function createNumberingCounter(defs) {
|
|
|
614
749
|
return lvlDef.lvlText.replace(/%(\d)/g, (_match, digit) => {
|
|
615
750
|
const lvl = Number(digit) - 1;
|
|
616
751
|
const value = arr[lvl] ?? startOf(lvl);
|
|
617
|
-
|
|
752
|
+
const fmt = lvlDef.isLgl ? "decimal" : def.levels[lvl]?.numFmt ?? "decimal";
|
|
753
|
+
return formatCounter(value, fmt);
|
|
618
754
|
});
|
|
619
755
|
}
|
|
620
|
-
return { next };
|
|
756
|
+
return { next, def: (numId, level) => defs?.[numId]?.levels[level] };
|
|
621
757
|
}
|
|
622
758
|
// Annotate the CommonJS export names for ESM import in node:
|
|
623
759
|
0 && (module.exports = {
|
|
760
|
+
anchorName,
|
|
761
|
+
bookmarkLabel,
|
|
624
762
|
commentSchema,
|
|
625
763
|
createNumberingCounter,
|
|
764
|
+
fieldAt,
|
|
765
|
+
findBookmark,
|
|
626
766
|
schema
|
|
627
767
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
// packages/model/src/lib/bookmarks.ts
|
|
2
|
+
function anchorName(href) {
|
|
3
|
+
return href && href.startsWith("#") && href.length > 1 ? href.slice(1) : null;
|
|
4
|
+
}
|
|
5
|
+
function findBookmark(doc, name) {
|
|
6
|
+
let found = null;
|
|
7
|
+
doc.descendants((node, pos) => {
|
|
8
|
+
if (found !== null) return false;
|
|
9
|
+
if (node.type.name !== "paragraph") return true;
|
|
10
|
+
const names = node.attrs["bookmarks"];
|
|
11
|
+
if (names?.includes(name)) found = pos + 1;
|
|
12
|
+
return false;
|
|
13
|
+
});
|
|
14
|
+
return found;
|
|
15
|
+
}
|
|
16
|
+
function bookmarkLabel(doc, name, max = 60) {
|
|
17
|
+
const pos = findBookmark(doc, name);
|
|
18
|
+
if (pos === null) return null;
|
|
19
|
+
const para = doc.nodeAt(pos - 1);
|
|
20
|
+
const text = (para?.textContent ?? "").replace(/^[\s.:–—-]+/, "").trim();
|
|
21
|
+
if (!text) return null;
|
|
22
|
+
return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
|
|
23
|
+
}
|
|
24
|
+
function fieldAt(doc, pos) {
|
|
25
|
+
let hit = null;
|
|
26
|
+
let run = null;
|
|
27
|
+
doc.forEach((node, offset) => {
|
|
28
|
+
const f = node.attrs["field"];
|
|
29
|
+
if (f && run && run.field === f) {
|
|
30
|
+
run.to = offset + node.nodeSize;
|
|
31
|
+
} else {
|
|
32
|
+
if (run && hit === run) return;
|
|
33
|
+
run = f ? { field: f, from: offset, to: offset + node.nodeSize } : null;
|
|
34
|
+
}
|
|
35
|
+
if (run && hit === null && pos >= run.from && pos <= run.to) hit = run;
|
|
36
|
+
});
|
|
37
|
+
return hit;
|
|
38
|
+
}
|
|
39
|
+
|
|
1
40
|
// packages/model/src/lib/model.ts
|
|
2
41
|
import { Schema } from "prosemirror-model";
|
|
3
42
|
function dataJson(el, name) {
|
|
@@ -15,7 +54,8 @@ function pastedParagraphAttrs(el, heading) {
|
|
|
15
54
|
return {
|
|
16
55
|
heading,
|
|
17
56
|
align: m ? m[1].toLowerCase() : null,
|
|
18
|
-
borders: dataJson(el, "data-borders")
|
|
57
|
+
borders: dataJson(el, "data-borders"),
|
|
58
|
+
carry: dataJson(el, "data-carry")
|
|
19
59
|
};
|
|
20
60
|
}
|
|
21
61
|
function pastedImageAttrs(el) {
|
|
@@ -52,7 +92,8 @@ function pastedCellAttrs(el) {
|
|
|
52
92
|
background: bg ? bg[1].trim() : null,
|
|
53
93
|
vAlign: e.getAttribute("data-valign"),
|
|
54
94
|
borders: dataJson(el, "data-borders"),
|
|
55
|
-
padding: dataJson(el, "data-padding")
|
|
95
|
+
padding: dataJson(el, "data-padding"),
|
|
96
|
+
carry: dataJson(el, "data-carry")
|
|
56
97
|
};
|
|
57
98
|
}
|
|
58
99
|
var schema = new Schema({
|
|
@@ -104,11 +145,33 @@ var schema = new Schema({
|
|
|
104
145
|
tabs: { default: null },
|
|
105
146
|
// w:spacing — { before?, after?, line?, lineRule? }, or null.
|
|
106
147
|
spacing: { default: null },
|
|
148
|
+
// w:bookmarkStart names anchored in this paragraph (["_Toc89595219"]),
|
|
149
|
+
// or null. Link hrefs of the form "#name" resolve against these —
|
|
150
|
+
// paragraph-level is the right altitude: Word's TOC bookmarks wrap a
|
|
151
|
+
// heading's text, and jumping to the heading is what a reader wants.
|
|
152
|
+
bookmarks: { default: null },
|
|
153
|
+
// The generated field this paragraph belongs to ({ kind: 'toc',
|
|
154
|
+
// instr } for a TOC entry), or null for ordinary content. Word paints
|
|
155
|
+
// such content with field shading and regenerates it on update.
|
|
156
|
+
field: { default: null },
|
|
107
157
|
// w:pageBreakBefore — start this paragraph on a new page.
|
|
108
158
|
pageBreakBefore: { default: false },
|
|
159
|
+
// w:keepNext — stay on the same page as the next block's first line.
|
|
160
|
+
keepNext: { default: false },
|
|
161
|
+
// w:keepLines — never split this paragraph across pages.
|
|
162
|
+
keepLines: { default: false },
|
|
163
|
+
// w:widowControl — Word's default is ON; false only when the document
|
|
164
|
+
// explicitly disables widow/orphan control for this paragraph.
|
|
165
|
+
widowControl: { default: true },
|
|
109
166
|
// w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
|
|
110
167
|
// Importer-set; painted as a box around the paragraph's lines.
|
|
111
|
-
borders: { default: null }
|
|
168
|
+
borders: { default: null },
|
|
169
|
+
// Carry-through fidelity (docx round-trip): OOXML paragraph
|
|
170
|
+
// properties the model does NOT represent, preserved verbatim so a
|
|
171
|
+
// customer's save never drops them. { pPr?: string, markRPr?: string }
|
|
172
|
+
// — raw XML fragments (pPr extras / the paragraph-mark w:rPr), or
|
|
173
|
+
// null. Importer-set; the exporter splices them back into w:pPr.
|
|
174
|
+
carry: { default: null }
|
|
112
175
|
},
|
|
113
176
|
// HTML paste path: recover heading level from h1–h6 and alignment from
|
|
114
177
|
// inline style. Other attrs (list/indent/tabs/spacing) stay importer-only
|
|
@@ -128,6 +191,8 @@ var schema = new Schema({
|
|
|
128
191
|
if (attrs.styleId) dom["data-style"] = attrs.styleId;
|
|
129
192
|
if (node.attrs["borders"])
|
|
130
193
|
dom["data-borders"] = JSON.stringify(node.attrs["borders"]);
|
|
194
|
+
if (node.attrs["carry"])
|
|
195
|
+
dom["data-carry"] = JSON.stringify(node.attrs["carry"]);
|
|
131
196
|
return [tag, dom, 0];
|
|
132
197
|
}
|
|
133
198
|
},
|
|
@@ -209,7 +274,12 @@ var schema = new Schema({
|
|
|
209
274
|
// insideV }, or null — OOXML tables are borderless unless declared.
|
|
210
275
|
borders: { default: null },
|
|
211
276
|
// w:tblPr/w:jc — 'center' | 'right' table alignment, or null (left).
|
|
212
|
-
align: { default: null }
|
|
277
|
+
align: { default: null },
|
|
278
|
+
// Carry-through fidelity: unmodelled w:tblPr children (tblStyle,
|
|
279
|
+
// tblLayout, tblLook, tblInd, floating tblpPr, …) as one raw XML
|
|
280
|
+
// string ({ tblPr: string }), or null. Importer-set; the exporter
|
|
281
|
+
// splices it back so a save never drops them.
|
|
282
|
+
carry: { default: null }
|
|
213
283
|
},
|
|
214
284
|
// Complex attrs round-trip as data-* JSON — ProseMirror's clipboard is
|
|
215
285
|
// a toDOM → parseDOM pass, so without this an internal copy/paste
|
|
@@ -220,7 +290,8 @@ var schema = new Schema({
|
|
|
220
290
|
getAttrs: (el) => ({
|
|
221
291
|
borders: dataJson(el, "data-borders"),
|
|
222
292
|
cellPadding: dataJson(el, "data-cell-padding"),
|
|
223
|
-
align: el.getAttribute("data-align")
|
|
293
|
+
align: el.getAttribute("data-align"),
|
|
294
|
+
carry: dataJson(el, "data-carry")
|
|
224
295
|
})
|
|
225
296
|
}
|
|
226
297
|
],
|
|
@@ -231,6 +302,7 @@ var schema = new Schema({
|
|
|
231
302
|
if (a["cellPadding"])
|
|
232
303
|
dom["data-cell-padding"] = JSON.stringify(a["cellPadding"]);
|
|
233
304
|
if (a["align"]) dom["data-align"] = String(a["align"]);
|
|
305
|
+
if (a["carry"]) dom["data-carry"] = JSON.stringify(a["carry"]);
|
|
234
306
|
return ["table", dom, ["tbody", 0]];
|
|
235
307
|
}
|
|
236
308
|
},
|
|
@@ -243,7 +315,10 @@ var schema = new Schema({
|
|
|
243
315
|
// (Word's default) means the paginator may split the row mid-content.
|
|
244
316
|
cantSplit: { default: false },
|
|
245
317
|
// w:trHeight — { value: px, exact: boolean } or null (auto).
|
|
246
|
-
height: { default: null }
|
|
318
|
+
height: { default: null },
|
|
319
|
+
// Carry-through fidelity: unmodelled w:trPr children ({ trPr: string
|
|
320
|
+
// } — gridBefore/wBefore, cnfStyle, …), or null. Importer-set.
|
|
321
|
+
carry: { default: null }
|
|
247
322
|
},
|
|
248
323
|
parseDOM: [
|
|
249
324
|
{
|
|
@@ -251,7 +326,8 @@ var schema = new Schema({
|
|
|
251
326
|
getAttrs: (el) => ({
|
|
252
327
|
header: el.getAttribute("data-header") === "true",
|
|
253
328
|
cantSplit: el.getAttribute("data-cant-split") === "true",
|
|
254
|
-
height: dataJson(el, "data-height")
|
|
329
|
+
height: dataJson(el, "data-height"),
|
|
330
|
+
carry: dataJson(el, "data-carry")
|
|
255
331
|
})
|
|
256
332
|
}
|
|
257
333
|
],
|
|
@@ -261,6 +337,8 @@ var schema = new Schema({
|
|
|
261
337
|
if (node.attrs["cantSplit"]) dom["data-cant-split"] = "true";
|
|
262
338
|
if (node.attrs["height"])
|
|
263
339
|
dom["data-height"] = JSON.stringify(node.attrs["height"]);
|
|
340
|
+
if (node.attrs["carry"])
|
|
341
|
+
dom["data-carry"] = JSON.stringify(node.attrs["carry"]);
|
|
264
342
|
return ["tr", dom, 0];
|
|
265
343
|
}
|
|
266
344
|
},
|
|
@@ -278,8 +356,11 @@ var schema = new Schema({
|
|
|
278
356
|
// w:vAlign — 'center' | 'bottom' (top default)
|
|
279
357
|
borders: { default: null },
|
|
280
358
|
// w:tcBorders per-side visibility override
|
|
281
|
-
padding: { default: null }
|
|
359
|
+
padding: { default: null },
|
|
282
360
|
// w:tcMar per-side margin override (px)
|
|
361
|
+
// Carry-through fidelity: unmodelled w:tcPr children ({ tcPr: string
|
|
362
|
+
// } — textDirection, noWrap, tcFitText, …), or null. Importer-set.
|
|
363
|
+
carry: { default: null }
|
|
283
364
|
},
|
|
284
365
|
parseDOM: [
|
|
285
366
|
{ tag: "td", getAttrs: pastedCellAttrs },
|
|
@@ -301,6 +382,8 @@ var schema = new Schema({
|
|
|
301
382
|
attrs["data-borders"] = JSON.stringify(node.attrs["borders"]);
|
|
302
383
|
if (node.attrs["padding"])
|
|
303
384
|
attrs["data-padding"] = JSON.stringify(node.attrs["padding"]);
|
|
385
|
+
if (node.attrs["carry"])
|
|
386
|
+
attrs["data-carry"] = JSON.stringify(node.attrs["carry"]);
|
|
304
387
|
return ["td", attrs, 0];
|
|
305
388
|
}
|
|
306
389
|
}
|
|
@@ -326,6 +409,32 @@ var schema = new Schema({
|
|
|
326
409
|
parseDOM: [{ tag: "s" }, { tag: "strike" }],
|
|
327
410
|
toDOM: () => ["s", 0]
|
|
328
411
|
},
|
|
412
|
+
// w:dstrike — double strikethrough
|
|
413
|
+
dstrike: {
|
|
414
|
+
parseDOM: [
|
|
415
|
+
{
|
|
416
|
+
style: "text-decoration-style=double",
|
|
417
|
+
getAttrs: (value) => value === "double" ? {} : false
|
|
418
|
+
}
|
|
419
|
+
],
|
|
420
|
+
toDOM: () => [
|
|
421
|
+
"span",
|
|
422
|
+
{
|
|
423
|
+
style: "text-decoration: line-through; text-decoration-style: double"
|
|
424
|
+
},
|
|
425
|
+
0
|
|
426
|
+
]
|
|
427
|
+
},
|
|
428
|
+
// w:smallCaps
|
|
429
|
+
smallCaps: {
|
|
430
|
+
parseDOM: [
|
|
431
|
+
{
|
|
432
|
+
style: "font-variant-caps",
|
|
433
|
+
getAttrs: (value) => value === "small-caps" ? {} : false
|
|
434
|
+
}
|
|
435
|
+
],
|
|
436
|
+
toDOM: () => ["span", { style: "font-variant-caps: small-caps" }, 0]
|
|
437
|
+
},
|
|
329
438
|
// w:color — hex "#RRGGBB"
|
|
330
439
|
textColor: {
|
|
331
440
|
attrs: { color: {} },
|
|
@@ -447,6 +556,28 @@ var schema = new Schema({
|
|
|
447
556
|
0
|
|
448
557
|
];
|
|
449
558
|
}
|
|
559
|
+
},
|
|
560
|
+
// Carry-through fidelity (docx round-trip): run properties the model does
|
|
561
|
+
// NOT represent (w:rtl, w:kern, w:szCs, …), preserved verbatim as one raw
|
|
562
|
+
// XML fragment so saving a customer's file never drops them. Invisible —
|
|
563
|
+
// no rendering; the docx exporter splices `xml` back into the run's rPr.
|
|
564
|
+
// Typing inside/at the edge of a carried run extends the mark (inclusive
|
|
565
|
+
// default), which is the faithful behavior for properties like w:rtl.
|
|
566
|
+
carryRPr: {
|
|
567
|
+
attrs: { xml: {} },
|
|
568
|
+
toDOM(mark) {
|
|
569
|
+
return ["span", { "data-carry-rpr": String(mark.attrs["xml"]) }, 0];
|
|
570
|
+
},
|
|
571
|
+
parseDOM: [
|
|
572
|
+
{
|
|
573
|
+
tag: "span[data-carry-rpr]",
|
|
574
|
+
getAttrs: (el) => ({
|
|
575
|
+
xml: el.getAttribute(
|
|
576
|
+
"data-carry-rpr"
|
|
577
|
+
) ?? ""
|
|
578
|
+
})
|
|
579
|
+
}
|
|
580
|
+
]
|
|
450
581
|
}
|
|
451
582
|
// The `comment` mark (w:commentRangeStart/End) is contributed by the comment
|
|
452
583
|
// plugin (@shadow-garden/bapbong-comments) via the editor's schema
|
|
@@ -586,13 +717,18 @@ function createNumberingCounter(defs) {
|
|
|
586
717
|
return lvlDef.lvlText.replace(/%(\d)/g, (_match, digit) => {
|
|
587
718
|
const lvl = Number(digit) - 1;
|
|
588
719
|
const value = arr[lvl] ?? startOf(lvl);
|
|
589
|
-
|
|
720
|
+
const fmt = lvlDef.isLgl ? "decimal" : def.levels[lvl]?.numFmt ?? "decimal";
|
|
721
|
+
return formatCounter(value, fmt);
|
|
590
722
|
});
|
|
591
723
|
}
|
|
592
|
-
return { next };
|
|
724
|
+
return { next, def: (numId, level) => defs?.[numId]?.levels[level] };
|
|
593
725
|
}
|
|
594
726
|
export {
|
|
727
|
+
anchorName,
|
|
728
|
+
bookmarkLabel,
|
|
595
729
|
commentSchema,
|
|
596
730
|
createNumberingCounter,
|
|
731
|
+
fieldAt,
|
|
732
|
+
findBookmark,
|
|
597
733
|
schema
|
|
598
734
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bookmarks and generated fields — the two things that make a table of
|
|
3
|
+
* contents behave like Word's rather than like a list of ordinary links.
|
|
4
|
+
*
|
|
5
|
+
* A `w:bookmarkStart` names a place in the document; a hyperlink whose href
|
|
6
|
+
* is `#name` points at it. Word's TOC wires every entry this way, with
|
|
7
|
+
* machine-generated `_Toc…` names it never shows the reader. Bookmarks ride
|
|
8
|
+
* the paragraph that contains them (see model.ts `bookmarks`), so they move
|
|
9
|
+
* with their heading through edits instead of decaying into stale offsets.
|
|
10
|
+
*/
|
|
11
|
+
import type { Node as PMNode } from 'prosemirror-model';
|
|
12
|
+
/** A generated field's identity, as it rides a paragraph's `field` attr. */
|
|
13
|
+
export interface FieldInfo {
|
|
14
|
+
/** Field kind — only 'toc' is modelled today. */
|
|
15
|
+
kind: string;
|
|
16
|
+
/** The field instruction, e.g. `TOC \o "1-3" \h \z \u`. */
|
|
17
|
+
instr: string;
|
|
18
|
+
}
|
|
19
|
+
/** An href pointing inside this document (`#name`) → the bookmark name, or
|
|
20
|
+
* null for external/absent links. */
|
|
21
|
+
export declare function anchorName(href: string | null | undefined): string | null;
|
|
22
|
+
/** Position of the paragraph anchoring `name`, or null when no paragraph
|
|
23
|
+
* claims it (a stale link, or a bookmark outside a paragraph). The position
|
|
24
|
+
* is the paragraph's first content slot — where a caret should land. */
|
|
25
|
+
export declare function findBookmark(doc: PMNode, name: string): number | null;
|
|
26
|
+
/** The text a reader should see for an internal link — the target paragraph's
|
|
27
|
+
* own text, trimmed to `max` — or null when the target is missing. Beats the
|
|
28
|
+
* raw `_Toc89595219`, which is machine bookkeeping. */
|
|
29
|
+
export declare function bookmarkLabel(doc: PMNode, name: string, max?: number): string | null;
|
|
30
|
+
/** The field a position sits inside, with the full paragraph range it spans,
|
|
31
|
+
* or null. A field covers CONSECUTIVE paragraphs carrying the same `field`
|
|
32
|
+
* attr object — the importer stamps one shared object per field, so identity
|
|
33
|
+
* distinguishes two adjacent TOCs. */
|
|
34
|
+
export declare function fieldAt(doc: PMNode, pos: number): {
|
|
35
|
+
field: FieldInfo;
|
|
36
|
+
from: number;
|
|
37
|
+
to: number;
|
|
38
|
+
} | null;
|
|
39
|
+
//# sourceMappingURL=bookmarks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bookmarks.d.ts","sourceRoot":"","sources":["../../src/lib/bookmarks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAExD,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf;AAED;sCACsC;AACtC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAEzE;AAED;;yEAEyE;AACzE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUrE;AAED;;wDAEwD;AACxD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,GAAG,SAAK,GACP,MAAM,GAAG,IAAI,CAUf;AAED;;;uCAGuC;AACvC,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkBvD"}
|
package/dist/lib/model.d.ts
CHANGED
|
@@ -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<"
|
|
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" | "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
|
/**
|
|
@@ -17,7 +17,7 @@ export type BapbongSchema = typeof schema;
|
|
|
17
17
|
* (@user). Comment bodies are stored as this schema's JSON on the comment
|
|
18
18
|
* thread, kept separate from the document schema.
|
|
19
19
|
*/
|
|
20
|
-
export declare const commentSchema: Schema<"
|
|
20
|
+
export declare const commentSchema: Schema<"paragraph" | "doc" | "text" | "mention", never>;
|
|
21
21
|
export type CommentSchema = typeof commentSchema;
|
|
22
22
|
/** Paragraph horizontal alignment (mirrors w:jc). */
|
|
23
23
|
export type Align = 'left' | 'center' | 'right' | 'justify';
|
package/dist/lib/model.d.ts.map
CHANGED
|
@@ -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;
|
|
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,kSAgfjB,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/dist/lib/numbering.d.ts
CHANGED
|
@@ -5,11 +5,28 @@
|
|
|
5
5
|
* the layout engine does this every pass, so inserting/deleting/reordering
|
|
6
6
|
* list items renumbers everything, like Word.
|
|
7
7
|
*/
|
|
8
|
+
/** Label (marker) run formatting from the lvl's w:rPr (plain data). */
|
|
9
|
+
export interface MarkerRunProps {
|
|
10
|
+
bold?: boolean;
|
|
11
|
+
italic?: boolean;
|
|
12
|
+
sizePt?: number;
|
|
13
|
+
family?: string;
|
|
14
|
+
color?: string;
|
|
15
|
+
}
|
|
8
16
|
/** One w:lvl of an abstract numbering definition (plain data — attr-safe). */
|
|
9
17
|
export interface NumberingLevelDef {
|
|
10
18
|
numFmt: string;
|
|
11
19
|
lvlText: string;
|
|
12
20
|
start: number;
|
|
21
|
+
/** Label alignment against its anchor (w:lvlJc); 'left' when omitted. */
|
|
22
|
+
jc?: 'center' | 'right';
|
|
23
|
+
/** What separates the label from the text (w:suff); 'tab' when omitted. */
|
|
24
|
+
suff?: 'space' | 'nothing';
|
|
25
|
+
/** Legal numbering (w:isLgl): every %n placeholder renders as decimal
|
|
26
|
+
* regardless of the referenced level's own numFmt. */
|
|
27
|
+
isLgl?: boolean;
|
|
28
|
+
/** Label formatting (w:lvl > w:rPr) — the number/bullet's own font. */
|
|
29
|
+
rPr?: MarkerRunProps;
|
|
13
30
|
}
|
|
14
31
|
/** Definitions keyed by numId. `key` groups numIds that share one abstract
|
|
15
32
|
* definition (their counters advance together, mirroring w:abstractNumId). */
|
|
@@ -22,6 +39,8 @@ export interface NumberingDefs {
|
|
|
22
39
|
/** Stateful counter: call `next` once per list paragraph, in document order. */
|
|
23
40
|
export interface NumberingCounter {
|
|
24
41
|
next(numId: string, level: number): string;
|
|
42
|
+
/** The level's definition (label styling for the layout), if any. */
|
|
43
|
+
def(numId: string, level: number): NumberingLevelDef | undefined;
|
|
25
44
|
}
|
|
26
45
|
export declare function createNumberingCounter(defs: NumberingDefs | null | undefined): NumberingCounter;
|
|
27
46
|
//# sourceMappingURL=numbering.d.ts.map
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"numbering.d.ts","sourceRoot":"","sources":["../../src/lib/numbering.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IACxB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B;2DACuD;IACvD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;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;IAC3C,qEAAqE;IACrE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAAC;CAClE;AA2DD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GACrC,gBAAgB,CA+BlB"}
|