@shadow-garden/bapbong-model 0.6.0 → 0.8.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
@@ -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) {
@@ -134,8 +177,24 @@ var schema = new import_prosemirror_model.Schema({
134
177
  tabs: { default: null },
135
178
  // w:spacing — { before?, after?, line?, lineRule? }, or null.
136
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 },
137
189
  // w:pageBreakBefore — start this paragraph on a new page.
138
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 },
139
198
  // w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
140
199
  // Importer-set; painted as a box around the paragraph's lines.
141
200
  borders: { default: null },
@@ -382,6 +441,32 @@ var schema = new import_prosemirror_model.Schema({
382
441
  parseDOM: [{ tag: "s" }, { tag: "strike" }],
383
442
  toDOM: () => ["s", 0]
384
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
+ },
385
470
  // w:color — hex "#RRGGBB"
386
471
  textColor: {
387
472
  attrs: { color: {} },
@@ -426,6 +511,69 @@ var schema = new import_prosemirror_model.Schema({
426
511
  ],
427
512
  toDOM: (mark) => [mark.attrs["value"] === "sub" ? "sub" : "sup", 0]
428
513
  },
514
+ // w:spacing (rPr) — tracking in twips, positive = expanded. Absolute:
515
+ // unlike the font size it does not shrink for superscript or small caps.
516
+ letterSpacing: {
517
+ attrs: { twips: {} },
518
+ parseDOM: [
519
+ {
520
+ style: "letter-spacing",
521
+ getAttrs: (value) => {
522
+ const m = /^(-?[\d.]+)pt$/.exec(String(value));
523
+ return m ? { twips: Math.round(Number(m[1]) * 20) } : false;
524
+ }
525
+ }
526
+ ],
527
+ toDOM: (mark) => [
528
+ "span",
529
+ { style: `letter-spacing: ${mark.attrs["twips"] / 20}pt` },
530
+ 0
531
+ ]
532
+ },
533
+ // w:w — horizontal glyph scale as a PERCENT (100 = normal). Squeezes the
534
+ // glyphs and their advances; independent of letterSpacing, which rides on
535
+ // top at its absolute value.
536
+ charScale: {
537
+ attrs: { percent: {} },
538
+ parseDOM: [
539
+ {
540
+ style: "transform",
541
+ getAttrs: (value) => {
542
+ const m = /^scaleX\(([\d.]+)\)$/.exec(String(value).trim());
543
+ return m ? { percent: Math.round(Number(m[1]) * 100) } : false;
544
+ }
545
+ }
546
+ ],
547
+ toDOM: (mark) => [
548
+ "span",
549
+ {
550
+ style: `display: inline-block; transform: scaleX(${mark.attrs["percent"] / 100})`
551
+ },
552
+ 0
553
+ ]
554
+ },
555
+ // w:position — baseline shift in half-points, positive up. Unlike
556
+ // super/subscript this does NOT resize the glyphs; Word treats the two
557
+ // as independent and documents combine them.
558
+ position: {
559
+ attrs: { halfPoints: {} },
560
+ parseDOM: [
561
+ {
562
+ style: "vertical-align",
563
+ getAttrs: (value) => {
564
+ const m = /^(-?[\d.]+)pt$/.exec(String(value));
565
+ return m ? { halfPoints: Number(m[1]) * 2 } : false;
566
+ }
567
+ }
568
+ ],
569
+ toDOM: (mark) => [
570
+ "span",
571
+ {
572
+ style: `vertical-align: ${mark.attrs["halfPoints"] / 2}pt`
573
+ },
574
+ 0
575
+ ]
576
+ },
429
577
  // w:highlight / w:shd w:fill — run background color ("#RRGGBB")
430
578
  highlight: {
431
579
  attrs: { color: {} },
@@ -664,14 +812,19 @@ function createNumberingCounter(defs) {
664
812
  return lvlDef.lvlText.replace(/%(\d)/g, (_match, digit) => {
665
813
  const lvl = Number(digit) - 1;
666
814
  const value = arr[lvl] ?? startOf(lvl);
667
- return formatCounter(value, def.levels[lvl]?.numFmt ?? "decimal");
815
+ const fmt = lvlDef.isLgl ? "decimal" : def.levels[lvl]?.numFmt ?? "decimal";
816
+ return formatCounter(value, fmt);
668
817
  });
669
818
  }
670
- return { next };
819
+ return { next, def: (numId, level) => defs?.[numId]?.levels[level] };
671
820
  }
672
821
  // Annotate the CommonJS export names for ESM import in node:
673
822
  0 && (module.exports = {
823
+ anchorName,
824
+ bookmarkLabel,
674
825
  commentSchema,
675
826
  createNumberingCounter,
827
+ fieldAt,
828
+ findBookmark,
676
829
  schema
677
830
  });
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './lib/bookmarks.js';
1
2
  export * from './lib/model.js';
2
3
  export * from './lib/numbering.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -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) {
@@ -106,8 +145,24 @@ var schema = new Schema({
106
145
  tabs: { default: null },
107
146
  // w:spacing — { before?, after?, line?, lineRule? }, or null.
108
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 },
109
157
  // w:pageBreakBefore — start this paragraph on a new page.
110
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 },
111
166
  // w:pBdr — { top?, bottom?, left?, right? } of BorderSide, or null.
112
167
  // Importer-set; painted as a box around the paragraph's lines.
113
168
  borders: { default: null },
@@ -354,6 +409,32 @@ var schema = new Schema({
354
409
  parseDOM: [{ tag: "s" }, { tag: "strike" }],
355
410
  toDOM: () => ["s", 0]
356
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
+ },
357
438
  // w:color — hex "#RRGGBB"
358
439
  textColor: {
359
440
  attrs: { color: {} },
@@ -398,6 +479,69 @@ var schema = new Schema({
398
479
  ],
399
480
  toDOM: (mark) => [mark.attrs["value"] === "sub" ? "sub" : "sup", 0]
400
481
  },
482
+ // w:spacing (rPr) — tracking in twips, positive = expanded. Absolute:
483
+ // unlike the font size it does not shrink for superscript or small caps.
484
+ letterSpacing: {
485
+ attrs: { twips: {} },
486
+ parseDOM: [
487
+ {
488
+ style: "letter-spacing",
489
+ getAttrs: (value) => {
490
+ const m = /^(-?[\d.]+)pt$/.exec(String(value));
491
+ return m ? { twips: Math.round(Number(m[1]) * 20) } : false;
492
+ }
493
+ }
494
+ ],
495
+ toDOM: (mark) => [
496
+ "span",
497
+ { style: `letter-spacing: ${mark.attrs["twips"] / 20}pt` },
498
+ 0
499
+ ]
500
+ },
501
+ // w:w — horizontal glyph scale as a PERCENT (100 = normal). Squeezes the
502
+ // glyphs and their advances; independent of letterSpacing, which rides on
503
+ // top at its absolute value.
504
+ charScale: {
505
+ attrs: { percent: {} },
506
+ parseDOM: [
507
+ {
508
+ style: "transform",
509
+ getAttrs: (value) => {
510
+ const m = /^scaleX\(([\d.]+)\)$/.exec(String(value).trim());
511
+ return m ? { percent: Math.round(Number(m[1]) * 100) } : false;
512
+ }
513
+ }
514
+ ],
515
+ toDOM: (mark) => [
516
+ "span",
517
+ {
518
+ style: `display: inline-block; transform: scaleX(${mark.attrs["percent"] / 100})`
519
+ },
520
+ 0
521
+ ]
522
+ },
523
+ // w:position — baseline shift in half-points, positive up. Unlike
524
+ // super/subscript this does NOT resize the glyphs; Word treats the two
525
+ // as independent and documents combine them.
526
+ position: {
527
+ attrs: { halfPoints: {} },
528
+ parseDOM: [
529
+ {
530
+ style: "vertical-align",
531
+ getAttrs: (value) => {
532
+ const m = /^(-?[\d.]+)pt$/.exec(String(value));
533
+ return m ? { halfPoints: Number(m[1]) * 2 } : false;
534
+ }
535
+ }
536
+ ],
537
+ toDOM: (mark) => [
538
+ "span",
539
+ {
540
+ style: `vertical-align: ${mark.attrs["halfPoints"] / 2}pt`
541
+ },
542
+ 0
543
+ ]
544
+ },
401
545
  // w:highlight / w:shd w:fill — run background color ("#RRGGBB")
402
546
  highlight: {
403
547
  attrs: { color: {} },
@@ -636,13 +780,18 @@ function createNumberingCounter(defs) {
636
780
  return lvlDef.lvlText.replace(/%(\d)/g, (_match, digit) => {
637
781
  const lvl = Number(digit) - 1;
638
782
  const value = arr[lvl] ?? startOf(lvl);
639
- return formatCounter(value, def.levels[lvl]?.numFmt ?? "decimal");
783
+ const fmt = lvlDef.isLgl ? "decimal" : def.levels[lvl]?.numFmt ?? "decimal";
784
+ return formatCounter(value, fmt);
640
785
  });
641
786
  }
642
- return { next };
787
+ return { next, def: (numId, level) => defs?.[numId]?.levels[level] };
643
788
  }
644
789
  export {
790
+ anchorName,
791
+ bookmarkLabel,
645
792
  commentSchema,
646
793
  createNumberingCounter,
794
+ fieldAt,
795
+ findBookmark,
647
796
  schema
648
797
  };
@@ -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"}
@@ -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<"doc" | "paragraph" | "text" | "hard_break" | "image" | "page_field" | "table" | "table_row" | "table_cell", "strong" | "em" | "underline" | "strike" | "textColor" | "fontSize" | "vertAlign" | "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" | "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
  /**
@@ -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<"doc" | "paragraph" | "text" | "mention", never>;
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';
@@ -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,wQAscjB,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;AAkF3C;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,+UAmjBjB,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"}
@@ -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;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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadow-garden/bapbong-model",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "bapbong — ProseMirror document model / schema",
5
5
  "license": "MIT",
6
6
  "repository": {