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