@vectojs/markdown 0.12.0 → 0.13.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.
@@ -32,6 +32,42 @@ export interface MarkdownTheme {
32
32
  /** Base font size in px. */
33
33
  fontSize?: number;
34
34
  }
35
+ /** A simple concrete container entity for nested layouts. */
36
+ declare class MarkdownContainer extends Entity {
37
+ isPointInside(_globalX: number, _globalY: number): boolean;
38
+ render(_r: any): void;
39
+ }
40
+ /**
41
+ * One display formula: a `$$..$$` block or a closed ```` ```math ```` fence.
42
+ *
43
+ * A named class rather than a bare {@link MarkdownContainer} because the formula
44
+ * needs a stable handle, and after the switch to an inline object it has none:
45
+ * the typeset raster lives in a `paint` closure captured by the span, so removing
46
+ * the `Image` entity left nothing exposing either the source or the SVG bytes.
47
+ * Devtools, tests, and anything auditing what a formula actually rendered all
48
+ * want that. `markstream-vue` reaches the same conclusion from the DOM side and
49
+ * publishes `data-markstream-mode` on its math node for the same reason.
50
+ *
51
+ * Deliberately carries no typeset-vs-source flag. A formula MathJax has not
52
+ * converted yet renders as a bare {@link CodeBlock} of its TeX, which this class
53
+ * does not wrap — wrapping it would put a container between `content` and a
54
+ * `CodeBlock` that the streamed `setCode` path locates by type. So a flag would
55
+ * have exactly one reachable value, which is the dead-API trap that cost CTX-0208
56
+ * a debugging pass. Add it together with wrapping the fallback, or not at all.
57
+ */
58
+ export declare class MathBlock extends MarkdownContainer {
59
+ /**
60
+ * The TeX source, exactly as written between the delimiters.
61
+ *
62
+ * Also the projected text and the accessible name, so this is the one string a
63
+ * reader can find, select, and copy.
64
+ */
65
+ readonly formula: string;
66
+ /** The `data:image/svg+xml` URI of the typeset glyphs. */
67
+ readonly svgUri: string;
68
+ constructor(formula: string, svgUri: string);
69
+ getDevtoolsDescriptor(): DevtoolsDescriptor;
70
+ }
35
71
  /**
36
72
  * A single self-rendering entity for fenced code blocks.
37
73
  *
@@ -851,3 +887,4 @@ export declare class Markdown extends UIComponent {
851
887
  /** Structural — children draw themselves. */
852
888
  render(_r: IRenderer): void;
853
889
  }
890
+ export {};
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  CodeBlock: () => CodeBlock,
34
34
  Markdown: () => Markdown,
35
+ MathBlock: () => MathBlock,
35
36
  codeAtlas: () => codeAtlas,
36
37
  codeAtlasStats: () => codeAtlasStats,
37
38
  isMathJaxReady: () => isMathJaxReady,
@@ -871,6 +872,33 @@ var MarkdownContainer = class extends import_core.Entity {
871
872
  render(_r) {
872
873
  }
873
874
  };
875
+ var MathBlock = class extends MarkdownContainer {
876
+ /**
877
+ * The TeX source, exactly as written between the delimiters.
878
+ *
879
+ * Also the projected text and the accessible name, so this is the one string a
880
+ * reader can find, select, and copy.
881
+ */
882
+ formula;
883
+ /** The `data:image/svg+xml` URI of the typeset glyphs. */
884
+ svgUri;
885
+ constructor(formula, svgUri) {
886
+ super();
887
+ this.formula = formula;
888
+ this.svgUri = svgUri;
889
+ }
890
+ getDevtoolsDescriptor() {
891
+ return {
892
+ kind: "MathBlock",
893
+ groups: [
894
+ {
895
+ label: "Math",
896
+ fields: [{ label: "formula", value: this.formula, readOnly: true }]
897
+ }
898
+ ]
899
+ };
900
+ }
901
+ };
874
902
  var KEYWORD_SETS = {
875
903
  js: /* @__PURE__ */ new Set([
876
904
  "const",
@@ -3393,23 +3421,40 @@ var Markdown = class _Markdown extends import_ui.UIComponent {
3393
3421
  if (!mathData) return null;
3394
3422
  const intrinsicW = exToPx(mathData.widthEx, t.fontSize);
3395
3423
  const intrinsicH = exToPx(mathData.heightEx, t.fontSize);
3396
- const mathImg = new import_ui.Image(mathData.uri, {
3397
- width: Math.min(availableWidth, intrinsicW),
3398
- height: intrinsicH * Math.min(1, availableWidth / intrinsicW),
3399
- alt: formula,
3400
- // The SVG decodes asynchronously and Image paints a placeholder until it
3401
- // lands. Without this an `onDemand` scene, which repaints only when marked
3402
- // dirty, leaves the formula a blank slab forever.
3403
- onLoad: () => {
3404
- this.scene?.markDirty();
3424
+ const scale = Math.min(1, availableWidth / intrinsicW);
3425
+ const width = intrinsicW * scale;
3426
+ const height = intrinsicH * scale;
3427
+ const uri = mathData.uri;
3428
+ const math = new import_ui.RichText(
3429
+ [
3430
+ {
3431
+ text: import_core.OBJECT_REPLACEMENT,
3432
+ object: {
3433
+ width,
3434
+ height,
3435
+ // The TeX source is what a reader copies and what a screen reader
3436
+ // announces. KaTeX's dual-layer contract carries the same string in an
3437
+ // `<annotation encoding="application/x-tex">`; here the projection is
3438
+ // the semantic layer, so one copy of the source serves both.
3439
+ alt: formula,
3440
+ paint: (surface, box) => paintInlineMath(uri, surface, box)
3441
+ }
3442
+ }
3443
+ ],
3444
+ {
3445
+ font: `${t.fontSize}px ${t.bodyFont}`,
3446
+ color: t.textColor,
3447
+ maxWidth: availableWidth,
3448
+ selectable: this.selectable
3405
3449
  }
3406
- });
3407
- const wrapper = new MarkdownContainer();
3408
- mathImg.x = 16;
3409
- mathImg.y = 8;
3410
- wrapper.add(mathImg);
3411
- wrapper.width = mathImg.width + 16;
3412
- wrapper.height = mathImg.height + 16;
3450
+ );
3451
+ this.subscribeInlineMathRepaint();
3452
+ const wrapper = new MathBlock(formula, uri);
3453
+ math.x = 16;
3454
+ math.y = 8;
3455
+ wrapper.add(math);
3456
+ wrapper.width = width + 16;
3457
+ wrapper.height = height + 16;
3413
3458
  return wrapper;
3414
3459
  }
3415
3460
  renderToken(token) {
@@ -3607,6 +3652,7 @@ var Markdown = class _Markdown extends import_ui.UIComponent {
3607
3652
  0 && (module.exports = {
3608
3653
  CodeBlock,
3609
3654
  Markdown,
3655
+ MathBlock,
3610
3656
  codeAtlas,
3611
3657
  codeAtlasStats,
3612
3658
  isMathJaxReady,
package/dist/index.mjs CHANGED
@@ -839,6 +839,33 @@ var MarkdownContainer = class extends Entity {
839
839
  render(_r) {
840
840
  }
841
841
  };
842
+ var MathBlock = class extends MarkdownContainer {
843
+ /**
844
+ * The TeX source, exactly as written between the delimiters.
845
+ *
846
+ * Also the projected text and the accessible name, so this is the one string a
847
+ * reader can find, select, and copy.
848
+ */
849
+ formula;
850
+ /** The `data:image/svg+xml` URI of the typeset glyphs. */
851
+ svgUri;
852
+ constructor(formula, svgUri) {
853
+ super();
854
+ this.formula = formula;
855
+ this.svgUri = svgUri;
856
+ }
857
+ getDevtoolsDescriptor() {
858
+ return {
859
+ kind: "MathBlock",
860
+ groups: [
861
+ {
862
+ label: "Math",
863
+ fields: [{ label: "formula", value: this.formula, readOnly: true }]
864
+ }
865
+ ]
866
+ };
867
+ }
868
+ };
842
869
  var KEYWORD_SETS = {
843
870
  js: /* @__PURE__ */ new Set([
844
871
  "const",
@@ -3361,23 +3388,40 @@ var Markdown = class _Markdown extends UIComponent {
3361
3388
  if (!mathData) return null;
3362
3389
  const intrinsicW = exToPx(mathData.widthEx, t.fontSize);
3363
3390
  const intrinsicH = exToPx(mathData.heightEx, t.fontSize);
3364
- const mathImg = new Image(mathData.uri, {
3365
- width: Math.min(availableWidth, intrinsicW),
3366
- height: intrinsicH * Math.min(1, availableWidth / intrinsicW),
3367
- alt: formula,
3368
- // The SVG decodes asynchronously and Image paints a placeholder until it
3369
- // lands. Without this an `onDemand` scene, which repaints only when marked
3370
- // dirty, leaves the formula a blank slab forever.
3371
- onLoad: () => {
3372
- this.scene?.markDirty();
3391
+ const scale = Math.min(1, availableWidth / intrinsicW);
3392
+ const width = intrinsicW * scale;
3393
+ const height = intrinsicH * scale;
3394
+ const uri = mathData.uri;
3395
+ const math = new RichText(
3396
+ [
3397
+ {
3398
+ text: OBJECT_REPLACEMENT,
3399
+ object: {
3400
+ width,
3401
+ height,
3402
+ // The TeX source is what a reader copies and what a screen reader
3403
+ // announces. KaTeX's dual-layer contract carries the same string in an
3404
+ // `<annotation encoding="application/x-tex">`; here the projection is
3405
+ // the semantic layer, so one copy of the source serves both.
3406
+ alt: formula,
3407
+ paint: (surface, box) => paintInlineMath(uri, surface, box)
3408
+ }
3409
+ }
3410
+ ],
3411
+ {
3412
+ font: `${t.fontSize}px ${t.bodyFont}`,
3413
+ color: t.textColor,
3414
+ maxWidth: availableWidth,
3415
+ selectable: this.selectable
3373
3416
  }
3374
- });
3375
- const wrapper = new MarkdownContainer();
3376
- mathImg.x = 16;
3377
- mathImg.y = 8;
3378
- wrapper.add(mathImg);
3379
- wrapper.width = mathImg.width + 16;
3380
- wrapper.height = mathImg.height + 16;
3417
+ );
3418
+ this.subscribeInlineMathRepaint();
3419
+ const wrapper = new MathBlock(formula, uri);
3420
+ math.x = 16;
3421
+ math.y = 8;
3422
+ wrapper.add(math);
3423
+ wrapper.width = width + 16;
3424
+ wrapper.height = height + 16;
3381
3425
  return wrapper;
3382
3426
  }
3383
3427
  renderToken(token) {
@@ -3574,6 +3618,7 @@ var Markdown = class _Markdown extends UIComponent {
3574
3618
  export {
3575
3619
  CodeBlock,
3576
3620
  Markdown,
3621
+ MathBlock,
3577
3622
  codeAtlas,
3578
3623
  codeAtlasStats,
3579
3624
  isMathJaxReady,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectojs/markdown",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },