temml 0.10.0 → 0.10.3

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/README.md CHANGED
@@ -7,11 +7,10 @@
7
7
  | KaTeX | 280 KB |
8
8
  | TeXZilla | 168 KB |
9
9
 
10
- As a futher advantage, Temml can use local system fonts. The minimum Temml installation serves a font file that is only 12kb.
10
+ As a futher advantage, Temml can use local system fonts. The minimum Temml installation serves a font file that is only 12kb. Sadly, Chromium has some rendering bugs when using system fonts. It
11
+ work better with the Latin Modern font, a 380 KB file.
11
12
 
12
- Chromium will support MathML in release 109 [early in 2023](https://chromiumdash.appspot.com/schedule), At that point, all the major browsers will support MathML and Temml will become the most lightweight way to render math in a browser.
13
-
14
- Temml’s coverage of LaTeX functions is as good as MathJax, slightly better than KaTeX 0.13.0 and substantially better than TeXZilla. See a [detailed coverage comparison](https://temml.org/docs/en/comparison.html).
13
+ Temml’s coverage of LaTeX functions is as good as MathJax, slightly better than KaTeX 0.16.0 and substantially better than TeXZilla. See a [detailed coverage comparison](https://temml.org/docs/en/comparison.html).
15
14
 
16
15
  Temml's test suite includes many rendered examples, including the Temml [supported functions page](https://temml.org/docs/en/supported.html) and tests from [Mozilla](https://temml.org/tests/mozilla-tests.html), [Wikipedia](https://temml.org/tests/wiki-tests.html), [mhchem](https://temml.org/tests/mhchem-tests.html), and [LaTeXML](https://temml.org/tests/LaTeXML-tests.html).
17
16
 
@@ -104,7 +104,7 @@ describe("A delimiter splitter", function() {
104
104
  ]);
105
105
  });
106
106
 
107
- it("splits mutliple times", function() {
107
+ it("splits multiple times", function() {
108
108
  expect("hello ( world ) boo ( more ) stuff").toSplitInto("(", ")", [
109
109
  { type: "text", data: "hello " },
110
110
  { type: "math", data: " world ", rawData: "( world )", display: false },
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable */
2
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
2
+ /* -*- Mode: JavaScript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
3
3
  /* vim: set ts=2 et sw=2 tw=80: */
4
4
 
5
5
  /*************************************************************
@@ -1696,7 +1696,7 @@ temml.__defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\
1696
1696
  };
1697
1697
 
1698
1698
  //
1699
- // Helpers for code anaylsis
1699
+ // Helpers for code analysis
1700
1700
  // Will show type error at calling position
1701
1701
  //
1702
1702
  /** @param {number} a */
@@ -35,7 +35,7 @@ mtext {
35
35
  }
36
36
 
37
37
  math {
38
- font-family: Asana Math;
38
+ font-family: Asana Math, math;
39
39
  }
40
40
 
41
41
  *.mathcal,
@@ -43,6 +43,22 @@ mo.tml-prime {
43
43
  font-feature-settings: 'salt';
44
44
  }
45
45
 
46
+ /* flex-wrap for line-breaking in Chromium */
47
+ math {
48
+ display: inline-flex;
49
+ flex-wrap: wrap;
50
+ align-items: baseline;
51
+ }
52
+ math > mrow {
53
+ padding: 0.5ex 0ex;
54
+ }
55
+
56
+ /* Avoid flex-wrap in Firefox */
57
+ @supports (-moz-appearance:meterbar) and (display:flex) {
58
+ math { display: inline; }
59
+ math > mrow { padding: 0 }
60
+ }
61
+
46
62
  /* AMS environment auto-numbering via CSS counter. */
47
63
  .tml-eqn::before {
48
64
  counter-increment: tmlEqnNo;
@@ -40,12 +40,8 @@ math * {
40
40
  border-color: currentColor;
41
41
  }
42
42
 
43
- .latin-modern math {
44
- font-family: "Latin Modern Math", "Times New Roman", math;
45
- }
46
-
47
43
  math {
48
- font-family: Latin Modern Math;
44
+ font-family: "Latin Modern Math", "Times New Roman", math;
49
45
  }
50
46
 
51
47
  *.mathscr {
@@ -56,6 +52,22 @@ mo.tml-prime {
56
52
  font-family: Temml;
57
53
  }
58
54
 
55
+ /* flex-wrap for line-breaking in Chromium */
56
+ math {
57
+ display: inline-flex;
58
+ flex-wrap: wrap;
59
+ align-items: baseline;
60
+ }
61
+ math > mrow {
62
+ padding: 0.5ex 0ex;
63
+ }
64
+
65
+ /* Avoid flex-wrap in Firefox */
66
+ @supports (-moz-appearance:meterbar) and (display:flex) {
67
+ math { display: inline; }
68
+ math > mrow { padding: 0 }
69
+ }
70
+
59
71
  /* AMS environment auto-numbering via CSS counter. */
60
72
  .tml-eqn::before {
61
73
  counter-increment: tmlEqnNo;
@@ -38,12 +38,8 @@ math * {
38
38
  border-color: currentColor;
39
39
  }
40
40
 
41
- .libertinus math {
42
- font-family: "Libertinus Math", "Times New Roman", math;
43
- }
44
-
45
41
  math {
46
- font-family: Libertinus Math;
42
+ font-family: Libertinus Math, math;
47
43
  }
48
44
 
49
45
  *.mathcal {
@@ -54,6 +50,22 @@ mo.tml-prime {
54
50
  font-feature-settings: 'ssty';
55
51
  }
56
52
 
53
+ /* flex-wrap for line-breaking in Chromium */
54
+ math {
55
+ display: inline-flex;
56
+ flex-wrap: wrap;
57
+ align-items: baseline;
58
+ }
59
+ math > mrow {
60
+ padding: 0.5ex 0ex;
61
+ }
62
+
63
+ /* Avoid flex-wrap in Firefox */
64
+ @supports (-moz-appearance:meterbar) and (display:flex) {
65
+ math { display: inline; }
66
+ math > mrow { padding: 0 }
67
+ }
68
+
57
69
  /* AMS environment auto-numbering via CSS counter. */
58
70
  .tml-eqn::before {
59
71
  counter-increment: tmlEqnNo;
@@ -36,6 +36,22 @@ mo.tml-prime {
36
36
  font-family: Temml;
37
37
  }
38
38
 
39
+ /* flex-wrap for line-breaking in Chromium */
40
+ math {
41
+ display: inline-flex;
42
+ flex-wrap: wrap;
43
+ align-items: baseline;
44
+ }
45
+ math > mrow {
46
+ padding: 0.5ex 0ex;
47
+ }
48
+
49
+ /* Avoid flex-wrap in Firefox */
50
+ @supports (-moz-appearance:meterbar) and (display:flex) {
51
+ math { display: inline; }
52
+ math > mrow { padding: 0 }
53
+ }
54
+
39
55
  /* AMS environment auto-numbering via CSS counter. */
40
56
  .tml-eqn::before {
41
57
  counter-increment: tmlEqnNo;
@@ -44,6 +44,22 @@ mo.tml-prime {
44
44
  font-feature-settings: 'ss04';
45
45
  }
46
46
 
47
+ /* flex-wrap for line-breaking in Chromium */
48
+ math {
49
+ display: inline-flex;
50
+ flex-wrap: wrap;
51
+ align-items: baseline;
52
+ }
53
+ math > mrow {
54
+ padding: 0.5ex 0ex;
55
+ }
56
+
57
+ /* Avoid flex-wrap in Firefox */
58
+ @supports (-moz-appearance:meterbar) and (display:flex) {
59
+ math { display: inline; }
60
+ math > mrow { padding: 0 }
61
+ }
62
+
47
63
  /* AMS environment auto-numbering via CSS counter. */
48
64
  .tml-eqn::before {
49
65
  counter-increment: tmlEqnNo;
package/dist/temml.cjs CHANGED
@@ -190,7 +190,7 @@ class Settings {
190
190
  this.leqno = utils.deflt(options.leqno, false); // boolean
191
191
  this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string
192
192
  this.macros = options.macros || {};
193
- this.wrap = utils.deflt(options.wrap, "none"); // "none" | "tex" | "="
193
+ this.wrap = utils.deflt(options.wrap, "tex"); // "tex" | "="
194
194
  this.xml = utils.deflt(options.xml, false); // boolean
195
195
  this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean
196
196
  this.strict = utils.deflt(options.strict, false); // boolean
@@ -668,7 +668,7 @@ class TextNode {
668
668
 
669
669
  /**
670
670
  * Converts the text node into a string
671
- * (representing the text iteself).
671
+ * (representing the text itself).
672
672
  */
673
673
  toText() {
674
674
  return this.text;
@@ -845,7 +845,6 @@ defineSymbol(math, rel, "\u226a", "\\ll", true);
845
845
  defineSymbol(math, rel, "\u226b", "\\gg", true);
846
846
  defineSymbol(math, rel, "\u224d", "\\asymp", true);
847
847
  defineSymbol(math, rel, "\u2225", "\\parallel");
848
- defineSymbol(math, rel, "\u22c8", "\\bowtie", true);
849
848
  defineSymbol(math, rel, "\u2323", "\\smile", true);
850
849
  defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true);
851
850
  defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true);
@@ -1162,7 +1161,6 @@ defineSymbol(math, rel, "\u22d9", "\\gggtr");
1162
1161
  defineSymbol(math, bin, "\u22b2", "\\lhd");
1163
1162
  defineSymbol(math, bin, "\u22b3", "\\rhd");
1164
1163
  defineSymbol(math, rel, "\u2242", "\\eqsim", true);
1165
- defineSymbol(math, rel, "\u22c8", "\\Join");
1166
1164
  defineSymbol(math, rel, "\u2251", "\\Doteq", true);
1167
1165
  defineSymbol(math, rel, "\u297d", "\\strictif", true);
1168
1166
  defineSymbol(math, rel, "\u297c", "\\strictfi", true);
@@ -1188,6 +1186,11 @@ defineSymbol(math, bin, "\u22ba", "\\intercal", true);
1188
1186
  defineSymbol(math, bin, "\u22d2", "\\doublecap");
1189
1187
  defineSymbol(math, bin, "\u22d3", "\\doublecup");
1190
1188
  defineSymbol(math, bin, "\u22a0", "\\boxtimes", true);
1189
+ defineSymbol(math, bin, "\u22c8", "\\bowtie", true);
1190
+ defineSymbol(math, bin, "\u22c8", "\\Join");
1191
+ defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true);
1192
+ defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true);
1193
+ defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true);
1191
1194
 
1192
1195
  // AMS Arrows
1193
1196
  // Note: unicode-math maps \u21e2 to their own function \rightdasharrow.
@@ -1746,10 +1749,12 @@ for (let i = 0; i < 10; i++) {
1746
1749
  * Then the top level of a <math> element can be occupied by <mrow> elements, and the browser
1747
1750
  * will break after a <mrow> if the expression extends beyond the container limit.
1748
1751
  *
1749
- * We want the expression to render with soft line breaks after each top-level binary or
1752
+ * The default is for soft line breaks after each top-level binary or
1750
1753
  * relational operator, per TeXbook p. 173. So we gather the expression into <mrow>s so that
1751
1754
  * each <mrow> ends in a binary or relational operator.
1752
1755
  *
1756
+ * An option is for soft line breaks before an "=" sign. That changes the <mrow>s.
1757
+ *
1753
1758
  * Soft line breaks will not work in Chromium and Safari, only Firefox.
1754
1759
  *
1755
1760
  * Hopefully browsers will someday do their own linebreaking and we will be able to delete
@@ -1892,7 +1897,7 @@ function setLineBreaks(expression, wrapMode, isDisplayMode, color) {
1892
1897
  }
1893
1898
 
1894
1899
  /**
1895
- * This file converts a parse tree into a cooresponding MathML tree. The main
1900
+ * This file converts a parse tree into a corresponding MathML tree. The main
1896
1901
  * entry point is the `buildMathML` function, which takes a parse tree from the
1897
1902
  * parser.
1898
1903
  */
@@ -2095,18 +2100,6 @@ function buildMathML(tree, texExpression, style, settings) {
2095
2100
  wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]);
2096
2101
  }
2097
2102
 
2098
- if (wrap !== "none" && wrapper.children.length > 1) {
2099
- const maths = [];
2100
- for (let i = 0; i < wrapper.children.length; i++) {
2101
- const math = new mathMLTree.MathNode("math", [wrapper.children[i]]);
2102
- if (settings.xml) {
2103
- math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML");
2104
- }
2105
- maths.push(math);
2106
- }
2107
- return mathMLTree.newDocumentFragment(maths)
2108
- }
2109
-
2110
2103
  const math = new mathMLTree.MathNode("math", [wrapper]);
2111
2104
 
2112
2105
  if (settings.xml) {
@@ -2114,6 +2107,9 @@ function buildMathML(tree, texExpression, style, settings) {
2114
2107
  }
2115
2108
  if (settings.displayMode) {
2116
2109
  math.setAttribute("display", "block");
2110
+ math.style.display = math.children.length === 1 && math.children[0].type === "mtable"
2111
+ ? "inline"
2112
+ : "inline-block";
2117
2113
  }
2118
2114
  return math;
2119
2115
  }
@@ -3523,6 +3519,11 @@ const delimiters = [
3523
3519
  "."
3524
3520
  ];
3525
3521
 
3522
+ // Export isDelimiter for benefit of parser.
3523
+ const dels = ["}", "\\left", "\\middle", "\\right"];
3524
+ const isDelimiter = str => str.length > 0 &&
3525
+ (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
3526
+
3526
3527
  // Metrics of the different sizes. Found by looking at TeX's output of
3527
3528
  // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
3528
3529
  // Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
@@ -6205,10 +6206,6 @@ const noSuccessor = ["\\smallint"];
6205
6206
  // Math operators (e.g. \sin) need a space between these types and themselves:
6206
6207
  const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
6207
6208
 
6208
- const dels$1 = ["}", "\\left", "\\middle", "\\right"];
6209
- const isDelimiter$1 = str => str.length > 0 &&
6210
- (delimiters.includes(str) || delimiterSizes[str] || dels$1.includes(str));
6211
-
6212
6209
  // NOTE: Unlike most `builders`s, this one handles not only "op", but also
6213
6210
  // "supsub" since some of them (like \int) can affect super/subscripting.
6214
6211
 
@@ -6429,7 +6426,7 @@ defineFunction({
6429
6426
  parentIsSupSub: false,
6430
6427
  symbol: false,
6431
6428
  stack: false,
6432
- isFollowedByDelimiter: isDelimiter$1(next),
6429
+ isFollowedByDelimiter: isDelimiter(next),
6433
6430
  needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
6434
6431
  name: funcName
6435
6432
  };
@@ -6454,7 +6451,7 @@ defineFunction({
6454
6451
  parentIsSupSub: false,
6455
6452
  symbol: false,
6456
6453
  stack: false,
6457
- isFollowedByDelimiter: isDelimiter$1(next),
6454
+ isFollowedByDelimiter: isDelimiter(next),
6458
6455
  needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
6459
6456
  name: funcName
6460
6457
  };
@@ -6540,11 +6537,7 @@ function defineMacro(name, body) {
6540
6537
  _macros[name] = body;
6541
6538
  }
6542
6539
 
6543
- const dels = ["}", "\\left", "\\middle", "\\right"];
6544
- const isDelimiter = str => str.length > 0 &&
6545
- (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
6546
-
6547
- // NOTE: Unlike most builders, this one handles not only
6540
+ // NOTE: Unlike most builders, this one handles not only
6548
6541
  // "operatorname", but also "supsub" since \operatorname* can
6549
6542
  // affect super/subscripting.
6550
6543
 
@@ -6554,8 +6547,12 @@ const mathmlBuilder$1 = (group, style) => {
6554
6547
  // Is expression a string or has it something like a fraction?
6555
6548
  let isAllString = true; // default
6556
6549
  for (let i = 0; i < expression.length; i++) {
6557
- const node = expression[i];
6550
+ let node = expression[i];
6558
6551
  if (node instanceof mathMLTree.MathNode) {
6552
+ if (node.type === "mrow" && node.children.length === 1 &&
6553
+ node.children[0] instanceof mathMLTree.MathNode) {
6554
+ node = node.children[0];
6555
+ }
6559
6556
  switch (node.type) {
6560
6557
  case "mi":
6561
6558
  case "mn":
@@ -6613,7 +6610,9 @@ const mathmlBuilder$1 = (group, style) => {
6613
6610
  let wrapper;
6614
6611
  if (isAllString) {
6615
6612
  wrapper = new mathMLTree.MathNode("mi", expression);
6616
- wrapper.setAttribute("mathvariant", "normal");
6613
+ if (expression[0].text.length === 1) {
6614
+ wrapper.setAttribute("mathvariant", "normal");
6615
+ }
6617
6616
  } else {
6618
6617
  wrapper = new mathMLTree.MathNode("mrow", expression);
6619
6618
  }
@@ -7151,6 +7150,7 @@ defineFunctionBuilders({
7151
7150
  let isOver;
7152
7151
  let isSup;
7153
7152
  let appendApplyFunction = false;
7153
+ let appendSpace = false;
7154
7154
  let needsLeadingSpace = false;
7155
7155
 
7156
7156
  if (group.base && group.base.type === "horizBrace") {
@@ -7165,6 +7165,7 @@ defineFunctionBuilders({
7165
7165
  (group.base.type === "op" || group.base.type === "operatorname")) {
7166
7166
  group.base.parentIsSupSub = true;
7167
7167
  appendApplyFunction = !group.base.symbol;
7168
+ appendSpace = appendApplyFunction && !group.isFollowedByDelimiter;
7168
7169
  needsLeadingSpace = group.base.needsLeadingSpace;
7169
7170
  }
7170
7171
 
@@ -7252,6 +7253,11 @@ defineFunctionBuilders({
7252
7253
  } else {
7253
7254
  node = mathMLTree.newDocumentFragment([node, operator]);
7254
7255
  }
7256
+ if (appendSpace) {
7257
+ const space = new mathMLTree.MathNode("mspace");
7258
+ space.setAttribute("width", "0.1667em"); // thin space.
7259
+ node.children.push(space);
7260
+ }
7255
7261
  } else if (symbolRegEx.test(nodeType)) {
7256
7262
  // Wrap in a <mrow>. Otherwise Firefox stretchy parens will not stretch to include limits.
7257
7263
  node = new mathMLTree.MathNode("mrow", [node]);
@@ -8884,7 +8890,7 @@ defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{
8884
8890
  defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}");
8885
8891
 
8886
8892
  /* eslint-disable */
8887
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
8893
+ /* -*- Mode: JavaScript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
8888
8894
  /* vim: set ts=2 et sw=2 tw=80: */
8889
8895
 
8890
8896
  /*************************************************************
@@ -10581,7 +10587,7 @@ defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap
10581
10587
  };
10582
10588
 
10583
10589
  //
10584
- // Helpers for code anaylsis
10590
+ // Helpers for code analysis
10585
10591
  // Will show type error at calling position
10586
10592
  //
10587
10593
  /** @param {number} a */
@@ -11006,15 +11012,15 @@ class MacroExpander {
11006
11012
  * Expand the next token only once if possible.
11007
11013
  *
11008
11014
  * If the token is expanded, the resulting tokens will be pushed onto
11009
- * the stack in reverse order and will be returned as an array,
11010
- * also in reverse order.
11015
+ * the stack in reverse order, and the number of such tokens will be
11016
+ * returned. This number might be zero or positive.
11011
11017
  *
11012
- * If not, the next token will be returned without removing it
11013
- * from the stack. This case can be detected by a `Token` return value
11014
- * instead of an `Array` return value.
11018
+ * If not, the return value is `false`, and the next token remains at the
11019
+ * top of the stack.
11015
11020
  *
11016
11021
  * In either case, the next token will be on the top of the stack,
11017
- * or the stack will be empty.
11022
+ * or the stack will be empty (in case of empty expansion
11023
+ * and no other tokens).
11018
11024
  *
11019
11025
  * Used to implement `expandAfterFuture` and `expandNextToken`.
11020
11026
  *
@@ -11030,7 +11036,7 @@ class MacroExpander {
11030
11036
  throw new ParseError("Undefined control sequence: " + name);
11031
11037
  }
11032
11038
  this.pushToken(topToken);
11033
- return topToken;
11039
+ return false;
11034
11040
  }
11035
11041
  this.expansionCount++;
11036
11042
  if (this.expansionCount > this.settings.maxExpand) {
@@ -11064,7 +11070,7 @@ class MacroExpander {
11064
11070
  }
11065
11071
  // Concatenate expansion onto top of stack.
11066
11072
  this.pushTokens(tokens);
11067
- return tokens;
11073
+ return tokens.length;
11068
11074
  }
11069
11075
 
11070
11076
  /**
@@ -11083,14 +11089,13 @@ class MacroExpander {
11083
11089
  */
11084
11090
  expandNextToken() {
11085
11091
  for (;;) {
11086
- const expanded = this.expandOnce();
11087
- // expandOnce returns Token if and only if it's fully expanded.
11088
- if (expanded instanceof Token) {
11092
+ if (this.expandOnce() === false) { // fully expanded
11093
+ const token = this.stack.pop();
11089
11094
  // The token after \noexpand is interpreted as if its meaning were ‘\relax’
11090
- if (expanded.treatAsRelax) {
11091
- expanded.text = "\\relax";
11095
+ if (token.treatAsRelax) {
11096
+ token.text = "\\relax";
11092
11097
  }
11093
- return this.stack.pop(); // === expanded
11098
+ return token
11094
11099
  }
11095
11100
  }
11096
11101
 
@@ -11116,15 +11121,15 @@ class MacroExpander {
11116
11121
  const oldStackLength = this.stack.length;
11117
11122
  this.pushTokens(tokens);
11118
11123
  while (this.stack.length > oldStackLength) {
11119
- const expanded = this.expandOnce(true); // expand only expandable tokens
11120
- // expandOnce returns Token if and only if it's fully expanded.
11121
- if (expanded instanceof Token) {
11122
- if (expanded.treatAsRelax) {
11124
+ // Expand only expandable tokens
11125
+ if (this.expandOnce(true) === false) { // fully expanded
11126
+ const token = this.stack.pop();
11127
+ if (token.treatAsRelax) {
11123
11128
  // the expansion of \noexpand is the token itself
11124
- expanded.noexpand = false;
11125
- expanded.treatAsRelax = false;
11129
+ token.noexpand = false;
11130
+ token.treatAsRelax = false;
11126
11131
  }
11127
- output.push(this.stack.pop());
11132
+ output.push(token);
11128
11133
  }
11129
11134
  }
11130
11135
  return output;
@@ -11952,7 +11957,7 @@ class Parser {
11952
11957
  * Parses an "expression", which is a list of atoms.
11953
11958
  *
11954
11959
  * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
11955
- * happens when functions have higher precendence han infix
11960
+ * happens when functions have higher precedence han infix
11956
11961
  * nodes in implicit parses.
11957
11962
  *
11958
11963
  * `breakOnTokenText`: The text of the token that the expression should end
@@ -12203,12 +12208,16 @@ class Parser {
12203
12208
  return base
12204
12209
  } else {
12205
12210
  // We got either a superscript or subscript, create a supsub
12211
+ const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname")
12212
+ ? undefined
12213
+ : isDelimiter(this.nextToken.text);
12206
12214
  return {
12207
12215
  type: "supsub",
12208
12216
  mode: this.mode,
12209
12217
  base: base,
12210
12218
  sup: superscript,
12211
- sub: subscript
12219
+ sub: subscript,
12220
+ isFollowedByDelimiter
12212
12221
  }
12213
12222
  }
12214
12223
  } else {
@@ -12369,7 +12378,7 @@ class Parser {
12369
12378
  while (true) {
12370
12379
  const ch = this.fetch().text;
12371
12380
  // \ufe0e is the Unicode variation selector to supress emoji. Ignore it.
12372
- if (ch === " " || ch === "\ufe0e") {
12381
+ if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") {
12373
12382
  this.consume();
12374
12383
  } else {
12375
12384
  break
@@ -12961,7 +12970,7 @@ class Style {
12961
12970
  * https://mit-license.org/
12962
12971
  */
12963
12972
 
12964
- const version = "0.10.0";
12973
+ const version = "0.10.3";
12965
12974
 
12966
12975
  function postProcess(block) {
12967
12976
  const labelMap = {};