temml 0.11.6 → 0.11.8

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/temml.mjs CHANGED
@@ -834,6 +834,9 @@ const stretchyCodePoint = {
834
834
  xtwoheadrightarrow: "\u21a0",
835
835
  xlongequal: "=",
836
836
  xrightleftarrows: "\u21c4",
837
+ xtofrom: "\u21c4",
838
+ xleftrightharpoons: "\u21cb",
839
+ xrightleftharpoons: "\u21cc",
837
840
  yields: "\u2192",
838
841
  yieldsLeft: "\u2190",
839
842
  mesomerism: "\u2194",
@@ -843,7 +846,9 @@ const stretchyCodePoint = {
843
846
  eqleftharpoondown: "\u21bd",
844
847
  "\\cdrightarrow": "\u2192",
845
848
  "\\cdleftarrow": "\u2190",
846
- "\\cdlongequal": "="
849
+ "\\cdlongequal": "=",
850
+ yieldsLeftRight: "\u21c4",
851
+ chemequilibrium: "\u21cc"
847
852
  };
848
853
 
849
854
  const mathMLnode = function(label) {
@@ -1771,7 +1776,7 @@ defineSymbol(math, inner, "\u22ef", "\\@cdots", true);
1771
1776
  defineSymbol(math, inner, "\u22f1", "\\ddots", true);
1772
1777
  defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro
1773
1778
  defineSymbol(text, textord, "\u22ee", "\\varvdots");
1774
- defineSymbol(math, accent, "\u02ca", "\\acute");
1779
+ defineSymbol(math, accent, "\u00b4", "\\acute");
1775
1780
  defineSymbol(math, accent, "\u0060", "\\grave");
1776
1781
  defineSymbol(math, accent, "\u00a8", "\\ddot");
1777
1782
  defineSymbol(math, accent, "\u2026", "\\dddot");
@@ -1797,7 +1802,7 @@ defineSymbol(math, mathord, "\u00d8", "\\O", true);
1797
1802
  defineSymbol(text, accent, "\u02ca", "\\'"); // acute
1798
1803
  defineSymbol(text, accent, "\u02cb", "\\`"); // grave
1799
1804
  defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex
1800
- defineSymbol(text, accent, "\u02dc", "\\~"); // tilde
1805
+ defineSymbol(text, accent, "\u007e", "\\~"); // tilde
1801
1806
  defineSymbol(text, accent, "\u02c9", "\\="); // macron
1802
1807
  defineSymbol(text, accent, "\u02d8", "\\u"); // breve
1803
1808
  defineSymbol(text, accent, "\u02d9", "\\."); // dot above
@@ -1809,7 +1814,7 @@ defineSymbol(text, accent, "\u02dd", "\\H"); // double acute
1809
1814
  defineSymbol(math, accent, "\u02ca", "\\'"); // acute
1810
1815
  defineSymbol(math, accent, "\u02cb", "\\`"); // grave
1811
1816
  defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex
1812
- defineSymbol(math, accent, "\u02dc", "\\~"); // tilde
1817
+ defineSymbol(math, accent, "\u007e", "\\~"); // tilde
1813
1818
  defineSymbol(math, accent, "\u02c9", "\\="); // macron
1814
1819
  defineSymbol(math, accent, "\u02d8", "\\u"); // breve
1815
1820
  defineSymbol(math, accent, "\u02d9", "\\."); // dot above
@@ -2466,46 +2471,61 @@ function buildMathML(tree, texExpression, style, settings) {
2466
2471
  return math;
2467
2472
  }
2468
2473
 
2474
+ // Identify letters to which we'll attach a combining accent character
2469
2475
  const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳";
2470
- const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ"
2471
- + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭";
2472
- const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota",
2473
- "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi",
2474
- "\\omega", "\\imath", "\\jmath"]);
2475
- const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta",
2476
- "\\lambda", "\\theta", "\\psi"]);
2476
+
2477
+ // From the KaTeX font metrics, identify letters whose accents need a italic correction.
2478
+ const smallNudge = "DHKLUcegorsuvxyzΠΥΨαδηιμνοτυχϵ";
2479
+ const mediumNudge = "BCEGIMNOPQRSTXZlpqtwΓΘΞΣΦΩβεζθξρςφψϑϕϱ";
2480
+ const largeNudge = "AFJdfΔΛ";
2477
2481
 
2478
2482
  const mathmlBuilder$a = (group, style) => {
2479
2483
  const accentNode = group.isStretchy
2480
2484
  ? stretchy.accentNode(group)
2481
2485
  : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]);
2482
-
2483
- if (group.label === "\\vec") {
2484
- accentNode.style.transform = "scale(0.75) translate(10%, 30%)";
2485
- } else {
2486
- accentNode.style.mathStyle = "normal";
2487
- accentNode.style.mathDepth = "0";
2488
- if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) {
2489
- let shift = "";
2490
- const ch = group.base.text;
2491
- if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift"; }
2492
- if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift"; }
2493
- if (shift) { accentNode.classes.push(shift); }
2494
- }
2495
- }
2496
2486
  if (!group.isStretchy) {
2497
- accentNode.setAttribute("stretchy", "false");
2498
- }
2499
-
2500
- const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"),
2501
- [buildGroup$1(group.base, style), accentNode]
2502
- );
2503
-
2487
+ accentNode.setAttribute("stretchy", "false"); // Keep Firefox from stretching \check
2488
+ }
2489
+ if (group.label !== "\\vec") {
2490
+ accentNode.style.mathDepth = "0"; // not scriptstyle
2491
+ // Don't use attribute accent="true" because MathML Core eliminates a needed space.
2492
+ }
2493
+ const tag = group.label === "\\c" ? "munder" : "mover";
2494
+ const needsWbkVertShift = needsWebkitVerticalShift.has(group.label);
2495
+ if (tag === "mover" && group.mode === "math" && (!group.isStretchy) && group.base.text
2496
+ && group.base.text.length === 1) {
2497
+ const text = group.base.text;
2498
+ const isVec = group.label === "\\vec";
2499
+ const vecPostfix = isVec === "\\vec" ? "-vec" : "";
2500
+ if (isVec) {
2501
+ accentNode.classes.push("tml-vec"); // Firefox sizing of \vec arrow
2502
+ }
2503
+ const wbkPostfix = isVec ? "-vec" : needsWbkVertShift ? "-acc" : "";
2504
+ if (smallNudge.indexOf(text) > -1) {
2505
+ accentNode.classes.push(`chr-sml${vecPostfix}`);
2506
+ accentNode.classes.push(`wbk-sml${wbkPostfix}`);
2507
+ } else if (mediumNudge.indexOf(text) > -1) {
2508
+ accentNode.classes.push(`chr-med${vecPostfix}`);
2509
+ accentNode.classes.push(`wbk-med${wbkPostfix}`);
2510
+ } else if (largeNudge.indexOf(text) > -1) {
2511
+ accentNode.classes.push(`chr-lrg${vecPostfix}`);
2512
+ accentNode.classes.push(`wbk-lrg${wbkPostfix}`);
2513
+ } else if (isVec) {
2514
+ accentNode.classes.push(`wbk-vec`);
2515
+ } else if (needsWbkVertShift) {
2516
+ accentNode.classes.push(`wbk-acc`);
2517
+ }
2518
+ } else if (needsWbkVertShift) {
2519
+ // text-mode accents
2520
+ accentNode.classes.push("wbk-acc");
2521
+ }
2522
+ const node = new mathMLTree.MathNode(tag, [buildGroup$1(group.base, style), accentNode]);
2504
2523
  return node;
2505
2524
  };
2506
2525
 
2507
2526
  const nonStretchyAccents = new Set([
2508
2527
  "\\acute",
2528
+ "\\check",
2509
2529
  "\\grave",
2510
2530
  "\\ddot",
2511
2531
  "\\dddot",
@@ -2520,7 +2540,7 @@ const nonStretchyAccents = new Set([
2520
2540
  "\\mathring"
2521
2541
  ]);
2522
2542
 
2523
- const needWebkitShift = new Set([
2543
+ const needsWebkitVerticalShift = new Set([
2524
2544
  "\\acute",
2525
2545
  "\\bar",
2526
2546
  "\\breve",
@@ -2530,7 +2550,7 @@ const needWebkitShift = new Set([
2530
2550
  "\\grave",
2531
2551
  "\\hat",
2532
2552
  "\\mathring",
2533
- "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"
2553
+ "\\`", "\\'", "\\^", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"
2534
2554
  ]);
2535
2555
 
2536
2556
  const combiningChar = {
@@ -2544,7 +2564,8 @@ const combiningChar = {
2544
2564
  '\\"': "\u0308",
2545
2565
  "\\r": "\u030A",
2546
2566
  "\\H": "\u030B",
2547
- "\\v": "\u030C"
2567
+ "\\v": "\u030C",
2568
+ "\\c": "\u0327"
2548
2569
  };
2549
2570
 
2550
2571
  // Accents
@@ -2589,8 +2610,8 @@ defineFunction({
2589
2610
  type: "accent",
2590
2611
  mode: context.parser.mode,
2591
2612
  label: context.funcName,
2592
- isStretchy: isStretchy,
2593
- base: base
2613
+ isStretchy,
2614
+ base
2594
2615
  };
2595
2616
  },
2596
2617
  mathmlBuilder: mathmlBuilder$a
@@ -2617,21 +2638,25 @@ defineFunction({
2617
2638
  }
2618
2639
 
2619
2640
  if (mode === "text" && base.text && base.text.length === 1
2620
- && context.funcName in combiningChar && smalls.indexOf(base.text) > -1) {
2641
+ && context.funcName in combiningChar && smalls.indexOf(base.text) > -1) {
2621
2642
  // Return a combining accent character
2622
2643
  return {
2623
2644
  type: "textord",
2624
2645
  mode: "text",
2625
2646
  text: base.text + combiningChar[context.funcName]
2626
2647
  }
2648
+ } else if (context.funcName === "\\c" && mode === "text" && base.text
2649
+ && base.text.length === 1) {
2650
+ // combining cedilla
2651
+ return { type: "textord", mode: "text", text: base.text + "\u0327" }
2627
2652
  } else {
2628
2653
  // Build up the accent
2629
2654
  return {
2630
2655
  type: "accent",
2631
- mode: mode,
2656
+ mode,
2632
2657
  label: context.funcName,
2633
2658
  isStretchy: false,
2634
- base: base
2659
+ base
2635
2660
  }
2636
2661
  }
2637
2662
  },
@@ -2889,12 +2914,17 @@ defineFunction({
2889
2914
  "\\xlongequal",
2890
2915
  "\\xtwoheadrightarrow",
2891
2916
  "\\xtwoheadleftarrow",
2892
- // The next 5 functions are here only to support mhchem
2917
+ "\\xtofrom", // expfeil
2918
+ "\\xleftrightharpoons", // mathtools
2919
+ "\\xrightleftharpoons", // mathtools
2920
+ // The next 7 functions are here only to support mhchem
2893
2921
  "\\yields",
2894
2922
  "\\yieldsLeft",
2895
2923
  "\\mesomerism",
2896
2924
  "\\longrightharpoonup",
2897
2925
  "\\longleftharpoondown",
2926
+ "\\yieldsLeftRight",
2927
+ "\\chemequilibrium",
2898
2928
  // The next 3 functions are here only to support the {CD} environment.
2899
2929
  "\\\\cdrightarrow",
2900
2930
  "\\\\cdleftarrow",
@@ -2925,26 +2955,15 @@ defineFunction({
2925
2955
  });
2926
2956
 
2927
2957
  const arrowComponent = {
2928
- "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"],
2929
- "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"],
2930
- "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"],
2931
- "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"],
2932
- // The next three all get the same harpoon glyphs. Only the lengths and paddings differ.
2933
- "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"],
2934
2958
  "\\equilibriumRight": ["\\longrightharpoonup", "\\eqleftharpoondown"],
2935
2959
  "\\equilibriumLeft": ["\\eqrightharpoonup", "\\longleftharpoondown"]
2936
2960
  };
2937
2961
 
2938
- // Browsers are not good at stretching a glyph that contains a pair of stacked arrows such as ⇄.
2939
- // So we stack a pair of single arrows.
2962
+ // Math fonts do not have a single glyph for these two mhchem functions.
2963
+ // So we stack a pair of single harpoons.
2940
2964
  defineFunction({
2941
2965
  type: "stackedArrow",
2942
2966
  names: [
2943
- "\\xtofrom", // expfeil
2944
- "\\xleftrightharpoons", // mathtools
2945
- "\\xrightleftharpoons", // mathtools
2946
- "\\yieldsLeftRight", // mhchem
2947
- "\\equilibrium", // mhchem
2948
2967
  "\\equilibriumRight",
2949
2968
  "\\equilibriumLeft"
2950
2969
  ],
@@ -3451,7 +3470,6 @@ const bordermatrixParseTree = (matrix, delimiters) => {
3451
3470
  alwaysHandleSupSub: true,
3452
3471
  parentIsSupSub: true,
3453
3472
  symbol: false,
3454
- stack: true,
3455
3473
  suppressBaseShift: true,
3456
3474
  body: [container]
3457
3475
  };
@@ -3459,6 +3477,7 @@ const bordermatrixParseTree = (matrix, delimiters) => {
3459
3477
  const mover = {
3460
3478
  type: "supsub", // We're using the MathML equivalent
3461
3479
  mode: "math", // of TeX \overset.
3480
+ stack: true,
3462
3481
  base: base, // That keeps the {pmatrix} aligned with
3463
3482
  sup: topWrapper, // the math centerline.
3464
3483
  sub: null
@@ -5922,8 +5941,8 @@ defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap
5922
5941
  case "<-": return "\\yieldsLeft";
5923
5942
  case "<->": return "\\mesomerism";
5924
5943
  case "<-->": return "\\yieldsLeftRight";
5925
- case "<=>": return "\\equilibrium";
5926
- case "\u21CC": return "\\equilibrium";
5944
+ case "<=>": return "\\chemequilibrium";
5945
+ case "\u21CC": return "\\chemequilibrium";
5927
5946
  case "<=>>": return "\\equilibriumRight";
5928
5947
  case "<<=>": return "\\equilibriumLeft";
5929
5948
  default:
@@ -8186,7 +8205,8 @@ const mathmlBuilder$7 = (group, style) => {
8186
8205
  case "\\boxed":
8187
8206
  // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
8188
8207
  node.setAttribute("notation", "box");
8189
- node.classes.push("tml-box");
8208
+ node.style.padding = "padding: 3pt 0 3pt 0";
8209
+ node.style.border = "1px solid";
8190
8210
  node.setAttribute("scriptlevel", "0");
8191
8211
  node.setAttribute("displaystyle", "true");
8192
8212
  break
@@ -8992,88 +9012,6 @@ defineFunction({
8992
9012
  mathmlBuilder: mathmlBuilder$4
8993
9013
  });
8994
9014
 
8995
- defineFunction({
8996
- type: "href",
8997
- names: ["\\href"],
8998
- props: {
8999
- numArgs: 2,
9000
- argTypes: ["url", "original"],
9001
- allowedInText: true
9002
- },
9003
- handler: ({ parser, token }, args) => {
9004
- const body = args[1];
9005
- const href = assertNodeType(args[0], "url").url;
9006
-
9007
- if (
9008
- !parser.settings.isTrusted({
9009
- command: "\\href",
9010
- url: href
9011
- })
9012
- ) {
9013
- throw new ParseError(`Function "\\href" is not trusted`, token)
9014
- }
9015
-
9016
- return {
9017
- type: "href",
9018
- mode: parser.mode,
9019
- href,
9020
- body: ordargument(body)
9021
- };
9022
- },
9023
- mathmlBuilder: (group, style) => {
9024
- const math = new MathNode("math", [buildExpressionRow(group.body, style)]);
9025
- const anchorNode = new AnchorNode(group.href, [], [math]);
9026
- return anchorNode
9027
- }
9028
- });
9029
-
9030
- defineFunction({
9031
- type: "href",
9032
- names: ["\\url"],
9033
- props: {
9034
- numArgs: 1,
9035
- argTypes: ["url"],
9036
- allowedInText: true
9037
- },
9038
- handler: ({ parser, token }, args) => {
9039
- const href = assertNodeType(args[0], "url").url;
9040
-
9041
- if (
9042
- !parser.settings.isTrusted({
9043
- command: "\\url",
9044
- url: href
9045
- })
9046
- ) {
9047
- throw new ParseError(`Function "\\url" is not trusted`, token)
9048
- }
9049
-
9050
- const chars = [];
9051
- for (let i = 0; i < href.length; i++) {
9052
- let c = href[i];
9053
- if (c === "~") {
9054
- c = "\\textasciitilde";
9055
- }
9056
- chars.push({
9057
- type: "textord",
9058
- mode: "text",
9059
- text: c
9060
- });
9061
- }
9062
- const body = {
9063
- type: "text",
9064
- mode: parser.mode,
9065
- font: "\\texttt",
9066
- body: chars
9067
- };
9068
- return {
9069
- type: "href",
9070
- mode: parser.mode,
9071
- href,
9072
- body: ordargument(body)
9073
- };
9074
- }
9075
- });
9076
-
9077
9015
  defineFunction({
9078
9016
  type: "html",
9079
9017
  names: ["\\class", "\\id", "\\style", "\\data"],
@@ -9331,17 +9269,24 @@ defineFunction({
9331
9269
  },
9332
9270
  mathmlBuilder(group, style) {
9333
9271
  const dimension = calculateSize(group.dimension, style);
9334
- const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : "";
9272
+ const ch = dimension.number > 0 && dimension.unit === "em"
9273
+ ? spaceCharacter(dimension.number)
9274
+ : "";
9335
9275
  if (group.mode === "text" && ch.length > 0) {
9336
9276
  const character = new mathMLTree.TextNode(ch);
9337
9277
  return new mathMLTree.MathNode("mtext", [character]);
9338
9278
  } else {
9339
- const node = new mathMLTree.MathNode("mspace");
9340
- node.setAttribute("width", dimension.number + dimension.unit);
9341
- if (dimension.number < 0) {
9279
+ if (dimension.number >= 0) {
9280
+ const node = new mathMLTree.MathNode("mspace");
9281
+ node.setAttribute("width", dimension.number + dimension.unit);
9282
+ return node
9283
+ } else {
9284
+ // Don't use <mspace> or <mpadded> because
9285
+ // WebKit recognizes negative left margin only on a <mrow> element
9286
+ const node = new mathMLTree.MathNode("mrow");
9342
9287
  node.style.marginLeft = dimension.number + dimension.unit;
9288
+ return node
9343
9289
  }
9344
- return node;
9345
9290
  }
9346
9291
  }
9347
9292
  });
@@ -9674,7 +9619,9 @@ const binrelClass = (arg) => {
9674
9619
  // (by rendering separately and with {}s before and after, and measuring
9675
9620
  // the change in spacing). We'll do roughly the same by detecting the
9676
9621
  // atom type directly.
9677
- const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg;
9622
+ const atom = arg.type === "ordgroup" && arg.body.length && arg.body.length === 1
9623
+ ? arg.body[0]
9624
+ : arg;
9678
9625
  if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) {
9679
9626
  return "m" + atom.family;
9680
9627
  } else {
@@ -9712,14 +9659,25 @@ defineFunction({
9712
9659
  const baseArg = args[1];
9713
9660
  const shiftedArg = args[0];
9714
9661
 
9662
+ let mclass;
9663
+ if (funcName !== "\\stackrel") {
9664
+ // LaTeX applies \binrel spacing to \overset and \underset.
9665
+ mclass = binrelClass(baseArg);
9666
+ } else {
9667
+ mclass = "mrel"; // for \stackrel
9668
+ }
9669
+
9670
+ const baseType = mclass === "mrel" || mclass === "mbin"
9671
+ ? "op"
9672
+ : "ordgroup";
9673
+
9715
9674
  const baseOp = {
9716
- type: "op",
9675
+ type: baseType,
9717
9676
  mode: baseArg.mode,
9718
9677
  limits: true,
9719
9678
  alwaysHandleSupSub: true,
9720
9679
  parentIsSupSub: false,
9721
9680
  symbol: false,
9722
- stack: true,
9723
9681
  suppressBaseShift: funcName !== "\\stackrel",
9724
9682
  body: ordargument(baseArg)
9725
9683
  };
@@ -9727,6 +9685,7 @@ defineFunction({
9727
9685
  return {
9728
9686
  type: "supsub",
9729
9687
  mode: shiftedArg.mode,
9688
+ stack: true,
9730
9689
  base: baseOp,
9731
9690
  sup: funcName === "\\underset" ? null : shiftedArg,
9732
9691
  sub: funcName === "\\underset" ? shiftedArg : null
@@ -10628,6 +10587,71 @@ defineFunction({
10628
10587
  }
10629
10588
  });
10630
10589
 
10590
+ const numRegEx = /^[0-9]$/;
10591
+ const unicodeNumSubs = {
10592
+ '0': '₀',
10593
+ '1': '₁',
10594
+ '2': '₂',
10595
+ '3': '₃',
10596
+ '4': '₄',
10597
+ '5': '₅',
10598
+ '6': '₆',
10599
+ '7': '₇',
10600
+ '8': '₈',
10601
+ '9': '₉'
10602
+ };
10603
+ const unicodeNumSups = {
10604
+ '0': '⁰',
10605
+ '1': '¹',
10606
+ '2': '²',
10607
+ '3': '³',
10608
+ '4': '⁴',
10609
+ '5': '⁵',
10610
+ '6': '⁶',
10611
+ '7': '⁷',
10612
+ '8': '⁸',
10613
+ '9': '⁹'
10614
+ };
10615
+
10616
+ defineFunction({
10617
+ type: "sfrac",
10618
+ names: ["\\sfrac"],
10619
+ props: {
10620
+ numArgs: 2,
10621
+ allowedInText: true,
10622
+ allowedInMath: true
10623
+ },
10624
+ handler({ parser }, args) {
10625
+ let numerator = "";
10626
+ for (const node of args[0].body) {
10627
+ if (node.type !== "textord" || !numRegEx.test(node.text)) {
10628
+ throw new ParseError("Numerator must be an integer.", node)
10629
+ }
10630
+ numerator += node.text;
10631
+ }
10632
+ let denominator = "";
10633
+ for (const node of args[1].body) {
10634
+ if (node.type !== "textord" || !numRegEx.test(node.text)) {
10635
+ throw new ParseError("Denominator must be an integer.", node)
10636
+ }
10637
+ denominator += node.text;
10638
+ }
10639
+ return {
10640
+ type: "sfrac",
10641
+ mode: parser.mode,
10642
+ numerator,
10643
+ denominator
10644
+ };
10645
+ },
10646
+ mathmlBuilder(group, style) {
10647
+ const numerator = group.numerator.split('').map(c => unicodeNumSups[c]).join('');
10648
+ const denominator = group.denominator.split('').map(c => unicodeNumSubs[c]).join('');
10649
+ // Use a fraction slash.
10650
+ const text = new mathMLTree.TextNode(numerator + "\u2044" + denominator, group.mode, style);
10651
+ return new mathMLTree.MathNode("mn", [text], ["special-fraction"])
10652
+ }
10653
+ });
10654
+
10631
10655
  // The size mappings are taken from TeX with \normalsize=10pt.
10632
10656
  // We don't have to track script level. MathML does that.
10633
10657
  const sizeMap = {
@@ -10845,6 +10869,11 @@ defineFunction({
10845
10869
  // Helpers
10846
10870
  const symbolRegEx = /^m(over|under|underover)$/;
10847
10871
 
10872
+ // From the KaTeX font metrics, identify letters that encroach on a superscript.
10873
+ const smallPad = "DHKLUcegorsuvxyzΠΥΨαδηιμνοτυχϵ";
10874
+ const mediumPad = "BCEFGIMNOPQRSTXZlpqtwΓΘΞΣΦΩβεζθξρςφψϑϕϱ";
10875
+ const largePad = "AJdfΔΛ";
10876
+
10848
10877
  // Super scripts and subscripts, whose precise placement can depend on other
10849
10878
  // functions that precede them.
10850
10879
  defineFunctionBuilders({
@@ -10866,7 +10895,7 @@ defineFunctionBuilders({
10866
10895
  }
10867
10896
  }
10868
10897
 
10869
- if (group.base && !group.base.stack &&
10898
+ if (group.base && !group.stack &&
10870
10899
  (group.base.type === "op" || group.base.type === "operatorname")) {
10871
10900
  group.base.parentIsSupSub = true;
10872
10901
  appendApplyFunction = !group.base.symbol;
@@ -10874,7 +10903,7 @@ defineFunctionBuilders({
10874
10903
  needsLeadingSpace = group.base.needsLeadingSpace;
10875
10904
  }
10876
10905
 
10877
- const children = group.base && group.base.stack
10906
+ const children = group.stack && group.base.body.length === 1
10878
10907
  ? [buildGroup$1(group.base.body[0], style)]
10879
10908
  : [buildGroup$1(group.base, style)];
10880
10909
 
@@ -10894,11 +10923,16 @@ defineFunctionBuilders({
10894
10923
  if (group.sup) {
10895
10924
  const sup = buildGroup$1(group.sup, childStyle);
10896
10925
  if (style.level === 3) { sup.setAttribute("scriptlevel", "2"); }
10897
- const testNode = sup.type === "mrow" ? sup.children[0] : sup;
10898
- if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime"))
10899
- && group.base && group.base.text && "fF".indexOf(group.base.text) > -1) {
10900
- // Chromium does not address italic correction on prime. Prevent f′ from overlapping.
10901
- testNode.classes.push("prime-pad");
10926
+ if (group.base && group.base.text && group.base.text.length === 1) {
10927
+ // Make an italic correction on the superscript.
10928
+ const text = group.base.text;
10929
+ if (smallPad.indexOf(text) > -1) {
10930
+ sup.classes.push("tml-sml-pad");
10931
+ } else if (mediumPad.indexOf(text) > -1) {
10932
+ sup.classes.push("tml-med-pad");
10933
+ } else if (largePad.indexOf(text) > -1) {
10934
+ sup.classes.push("tml-lrg-pad");
10935
+ }
10902
10936
  }
10903
10937
  children.push(sup);
10904
10938
  }
@@ -10927,7 +10961,9 @@ defineFunctionBuilders({
10927
10961
  }
10928
10962
  } else if (!group.sup) {
10929
10963
  const base = group.base;
10930
- if (
10964
+ if (group.stack) {
10965
+ nodeType = "munder";
10966
+ } else if (
10931
10967
  base &&
10932
10968
  base.type === "op" &&
10933
10969
  base.limits &&
@@ -13972,7 +14008,7 @@ class Style {
13972
14008
  * https://mit-license.org/
13973
14009
  */
13974
14010
 
13975
- const version = "0.11.06";
14011
+ const version = "0.11.08";
13976
14012
 
13977
14013
  function postProcess(block) {
13978
14014
  const labelMap = {};
@@ -11,7 +11,7 @@
11
11
  * https://mit-license.org/
12
12
  */
13
13
 
14
- const version = "0.11.06";
14
+ const version = "0.11.08";
15
15
 
16
16
  function postProcess(block) {
17
17
  const labelMap = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "temml",
3
- "version": "0.11.06",
3
+ "version": "0.11.08",
4
4
  "description": "TeX to MathML conversion in JavaScript.",
5
5
  "main": "dist/temml.js",
6
6
  "engines": {
@@ -122,7 +122,6 @@ export const bordermatrixParseTree = (matrix, delimiters) => {
122
122
  alwaysHandleSupSub: true,
123
123
  parentIsSupSub: true,
124
124
  symbol: false,
125
- stack: true,
126
125
  suppressBaseShift: true,
127
126
  body: [container]
128
127
  }
@@ -130,6 +129,7 @@ export const bordermatrixParseTree = (matrix, delimiters) => {
130
129
  const mover = {
131
130
  type: "supsub", // We're using the MathML equivalent
132
131
  mode: "math", // of TeX \overset.
132
+ stack: true,
133
133
  base: base, // That keeps the {pmatrix} aligned with
134
134
  sup: topWrapper, // the math centerline.
135
135
  sub: null