temml 0.12.2 → 0.13.2

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.js CHANGED
@@ -216,6 +216,7 @@ var temml = (function () {
216
216
  : [Infinity, Infinity]
217
217
  );
218
218
  this.maxExpand = Math.max(0, deflt(options.maxExpand, 1000)); // number
219
+ this.wrapDelimiterPairs = true; // boolean
219
220
  }
220
221
 
221
222
  /**
@@ -997,8 +998,7 @@ var temml = (function () {
997
998
  defineSymbol(math, textord, "\u2200", "\\forall", true);
998
999
  defineSymbol(math, textord, "\u210f", "\\hbar", true);
999
1000
  defineSymbol(math, textord, "\u2203", "\\exists", true);
1000
- // is actually a unary operator, not binary. But this works.
1001
- defineSymbol(math, bin, "\u2207", "\\nabla", true);
1001
+ defineSymbol(math, open, "\u2207", "\\nabla", true);
1002
1002
  defineSymbol(math, textord, "\u266d", "\\flat", true);
1003
1003
  defineSymbol(math, textord, "\u2113", "\\ell", true);
1004
1004
  defineSymbol(math, textord, "\u266e", "\\natural", true);
@@ -1091,7 +1091,7 @@ var temml = (function () {
1091
1091
 
1092
1092
  // AMS Negated Binary Relations
1093
1093
  defineSymbol(math, rel, "\u226e", "\\nless", true);
1094
- // Symbol names preceeded by "@" each have a corresponding macro.
1094
+ // Symbol names preceded by "@" each have a corresponding macro.
1095
1095
  defineSymbol(math, rel, "\u2a87", "\\lneq", true);
1096
1096
  defineSymbol(math, rel, "\u2268", "\\lneqq", true);
1097
1097
  defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq");
@@ -2002,16 +2002,12 @@ var temml = (function () {
2002
2002
  * much of this module.
2003
2003
  */
2004
2004
 
2005
- const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃";
2006
- const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄";
2007
-
2008
2005
  function setLineBreaks(expression, wrapMode, isDisplayMode) {
2009
2006
  const mtrs = [];
2010
2007
  let mrows = [];
2011
2008
  let block = [];
2012
2009
  let numTopLevelEquals = 0;
2013
2010
  let i = 0;
2014
- let level = 0;
2015
2011
  while (i < expression.length) {
2016
2012
  while (expression[i] instanceof DocumentFragment) {
2017
2013
  expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
@@ -2034,13 +2030,10 @@ var temml = (function () {
2034
2030
  }
2035
2031
  block.push(node);
2036
2032
  if (node.type && node.type === "mo" && node.children.length === 1 &&
2033
+ !(node.attributes.form && node.attributes.form === "prefix") && // unary operators
2037
2034
  !Object.prototype.hasOwnProperty.call(node.attributes, "movablelimits")) {
2038
2035
  const ch = node.children[0].text;
2039
- if (openDelims.indexOf(ch) > -1) {
2040
- level += 1;
2041
- } else if (closeDelims.indexOf(ch) > -1) {
2042
- level -= 1;
2043
- } else if (level === 0 && wrapMode === "=" && ch === "=") {
2036
+ if (wrapMode === "=" && ch === "=") {
2044
2037
  numTopLevelEquals += 1;
2045
2038
  if (numTopLevelEquals > 1) {
2046
2039
  block.pop();
@@ -2049,7 +2042,7 @@ var temml = (function () {
2049
2042
  mrows.push(element);
2050
2043
  block = [node];
2051
2044
  }
2052
- } else if (level === 0 && wrapMode === "tex" && ch !== "∇") {
2045
+ } else if (wrapMode === "tex") {
2053
2046
  // Check if the following node is a \nobreak text node, e.g. "~""
2054
2047
  const next = i < expression.length - 1 ? expression[i + 1] : null;
2055
2048
  let glueIsFreeOfNobreak = true;
@@ -3071,7 +3064,7 @@ var temml = (function () {
3071
3064
  * returns null.
3072
3065
  */
3073
3066
  function checkSymbolNodeType(node) {
3074
- if (node && (node.type === "atom" ||
3067
+ if (node && (node.type === "atom" || node.type === "delimiter" ||
3075
3068
  Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) {
3076
3069
  return node;
3077
3070
  }
@@ -3877,7 +3870,6 @@ var temml = (function () {
3877
3870
  "\\iint": "\\dotsi",
3878
3871
  "\\iiint": "\\dotsi",
3879
3872
  "\\iiiint": "\\dotsi",
3880
- "\\idotsint": "\\dotsi",
3881
3873
  // Symbols whose definition starts with \DOTSX:
3882
3874
  "\\DOTSX": "\\dotsx"
3883
3875
  };
@@ -3959,7 +3951,7 @@ var temml = (function () {
3959
3951
  defineMacro("\\dotsb", "\\cdots");
3960
3952
  defineMacro("\\dotsm", "\\cdots");
3961
3953
  defineMacro("\\dotsi", "\\!\\cdots");
3962
- defineMacro("\\idotsint", "\\dotsi");
3954
+ defineMacro("\\idotsint", "\\int\\!\\cdots\\!\\int");
3963
3955
  // amsmath doesn't actually define \dotsx, but \dots followed by a macro
3964
3956
  // starting with \DOTSX implies \dotso, and then \extra@ detects this case
3965
3957
  // and forces the added `\,`.
@@ -4254,6 +4246,7 @@ var temml = (function () {
4254
4246
  // cmll package
4255
4247
  defineMacro("\\invamp", '\\mathbin{\\char"214b}');
4256
4248
  defineMacro("\\parr", '\\mathbin{\\char"214b}');
4249
+ defineMacro("\\upand", '\\mathbin{\\char"214b}'); // STIX package
4257
4250
  defineMacro("\\with", '\\mathbin{\\char"26}');
4258
4251
  defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}');
4259
4252
  defineMacro("\\multimapboth", '\\mathrel{\\char"29df}');
@@ -5311,6 +5304,7 @@ var temml = (function () {
5311
5304
  // That way, the arrow will be an overlay on the content.
5312
5305
  const phantom = new MathNode("mphantom", [buildGroup$1(group.body, style)]);
5313
5306
  const arrow = new MathNode("mrow", [phantom], ["tml-cancelto"]);
5307
+ arrow.style.color = style.color;
5314
5308
  if (group.isCharacterBox && smalls.indexOf(group.body.body[0].text) > -1) {
5315
5309
  arrow.style.left = "0.1em";
5316
5310
  arrow.style.width = "90%";
@@ -5342,6 +5336,7 @@ var temml = (function () {
5342
5336
  dummyNode = new MathNode("mphantom", [zeroWidthNode]); // Hide it.
5343
5337
  }
5344
5338
  const toNode = buildGroup$1(group.to, style);
5339
+ toNode.style.color = style.color;
5345
5340
  const zeroWidthToNode = new MathNode("mpadded", [toNode]);
5346
5341
  if (!group.isCharacterBox || /[f∫∑]/.test(group.body.body[0].text)) {
5347
5342
  const w = new MathNode("mspace", []);
@@ -5400,7 +5395,7 @@ var temml = (function () {
5400
5395
 
5401
5396
  // Colors from Tables 4.1 and 4.2 of the xcolor package.
5402
5397
  // Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx.
5403
- // Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable
5398
+ // Table 4.2 (Capitalized) values were sampled, because Chroma contains a unreliable
5404
5399
  // conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274.
5405
5400
  const xcolors = JSON.parse(`{
5406
5401
  "Apricot": "#ffb484",
@@ -5959,7 +5954,41 @@ var temml = (function () {
5959
5954
  "\\Bigg": { mclass: "mord", size: 4 }
5960
5955
  };
5961
5956
 
5962
- const delimiters = [
5957
+ const leftToRight = {
5958
+ "(": ")",
5959
+ "\\lparen": "\\rparen",
5960
+ "[": "]",
5961
+ "\\lbrack": "\\rbrack",
5962
+ "\\{": "\\}",
5963
+ "\\lbrace": "\\rbrace",
5964
+ "⦇": "⦈",
5965
+ "\\llparenthesis": "\\rrparenthesis",
5966
+ "\\lfloor": "\\rfloor",
5967
+ "\u230a": "\u230b",
5968
+ "\\lceil": "\\rceil",
5969
+ "\u2308": "\u2309",
5970
+ "\\langle": "\\rangle",
5971
+ "\u27e8": "\u27e9",
5972
+ "\\lAngle": "\\rAngle",
5973
+ "\u27ea": "\u27eb",
5974
+ "\\llangle": "\\rrangle",
5975
+ "⦉": "⦊",
5976
+ "\\lvert": "\\rvert",
5977
+ "\\lVert": "\\rVert",
5978
+ "\\lgroup": "\\rgroup",
5979
+ "\u27ee": "\u27ef",
5980
+ "\\lmoustache": "\\rmoustache",
5981
+ "\u23b0": "\u23b1",
5982
+ "\\llbracket": "\\rrbracket",
5983
+ "\u27e6": "\u27e7",
5984
+ "\\lBrace": "\\rBrace",
5985
+ "\u2983": "\u2984"
5986
+ };
5987
+
5988
+ const leftDelimiterNames = new Set(Object.keys(leftToRight));
5989
+ new Set(Object.values(leftToRight));
5990
+
5991
+ const delimiters = new Set([
5963
5992
  "(",
5964
5993
  "\\lparen",
5965
5994
  ")",
@@ -6015,7 +6044,7 @@ var temml = (function () {
6015
6044
  "\\llbracket",
6016
6045
  "\\rrbracket",
6017
6046
  "\u27e6",
6018
- "\u27e6",
6047
+ "\u27e7",
6019
6048
  "\\lBrace",
6020
6049
  "\\rBrace",
6021
6050
  "\u2983",
@@ -6034,12 +6063,12 @@ var temml = (function () {
6034
6063
  "\\updownarrow",
6035
6064
  "\\Updownarrow",
6036
6065
  "."
6037
- ];
6066
+ ]);
6038
6067
 
6039
6068
  // Export isDelimiter for benefit of parser.
6040
- const dels = ["}", "\\left", "\\middle", "\\right"];
6069
+ const dels = new Set(["}", "\\left", "\\middle", "\\right"]);
6041
6070
  const isDelimiter = str => str.length > 0 &&
6042
- (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
6071
+ (delimiters.has(str) || delimiterSizes[str] || dels.has(str));
6043
6072
 
6044
6073
  // Metrics of the different sizes. Found by looking at TeX's output of
6045
6074
  // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
@@ -6052,11 +6081,11 @@ var temml = (function () {
6052
6081
  delim = delim.body[0]; // Unwrap the braces
6053
6082
  }
6054
6083
  const symDelim = checkSymbolNodeType(delim);
6055
- if (symDelim && delimiters.includes(symDelim.text)) {
6084
+ if (symDelim && delimiters.has(symDelim.text)) {
6056
6085
  // If a character is not in the MathML operator dictionary, it will not stretch.
6057
6086
  // Replace such characters w/characters that will stretch.
6058
- if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; }
6059
- if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; }
6087
+ if (symDelim.text === "<" || symDelim.text === "\\lt") { symDelim.text = "⟨"; }
6088
+ if (symDelim.text === ">" || symDelim.text === "\\gt") { symDelim.text = "⟩"; }
6060
6089
  return symDelim;
6061
6090
  } else if (symDelim) {
6062
6091
  throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
@@ -6066,7 +6095,16 @@ var temml = (function () {
6066
6095
  }
6067
6096
 
6068
6097
  // / \
6069
- const needExplicitStretch = ["\u002F", "\u005C", "\\backslash", "\\vert", "|"];
6098
+ const needExplicitStretch = new Set(["\u002F", "\u005C", "\\backslash", "\u2216", "\\vert", "|"]);
6099
+
6100
+ const makeFenceMo = (delim, mode, form, isStretchy) => {
6101
+ const text = delim === "." ? "" : delim;
6102
+ const node = new MathNode("mo", [makeText(text, mode)]);
6103
+ node.setAttribute("fence", "true");
6104
+ node.setAttribute("form", form);
6105
+ node.setAttribute("stretchy", isStretchy ? "true" : "false");
6106
+ return node;
6107
+ };
6070
6108
 
6071
6109
  defineFunction({
6072
6110
  type: "delimsizing",
@@ -6117,9 +6155,9 @@ var temml = (function () {
6117
6155
  },
6118
6156
  mathmlBuilder: (group) => {
6119
6157
  const children = [];
6158
+ const delim = group.delim === "." ? "" : group.delim;
6120
6159
 
6121
- if (group.delim === ".") { group.delim = ""; }
6122
- children.push(makeText(group.delim, group.mode));
6160
+ children.push(makeText(delim, group.mode));
6123
6161
 
6124
6162
  const node = new MathNode("mo", children);
6125
6163
 
@@ -6132,7 +6170,7 @@ var temml = (function () {
6132
6170
  // defaults.
6133
6171
  node.setAttribute("fence", "false");
6134
6172
  }
6135
- if (needExplicitStretch.includes(group.delim) || group.delim.indexOf("arrow") > -1) {
6173
+ if (needExplicitStretch.has(delim) || delim.indexOf("arrow") > -1) {
6136
6174
  // We have to explicitly set stretchy to true.
6137
6175
  node.setAttribute("stretchy", "true");
6138
6176
  }
@@ -6145,7 +6183,7 @@ var temml = (function () {
6145
6183
 
6146
6184
  function assertParsed(group) {
6147
6185
  if (!group.body) {
6148
- throw new Error("Bug: The leftright ParseNode wasn't fully parsed.");
6186
+ throw new Error("Bug: The delim ParseNode wasn't fully parsed.");
6149
6187
  }
6150
6188
  }
6151
6189
 
@@ -6176,17 +6214,10 @@ var temml = (function () {
6176
6214
  const delim = checkDelimiter(args[0], context);
6177
6215
 
6178
6216
  const parser = context.parser;
6179
- // Parse out the implicit body
6180
6217
  ++parser.leftrightDepth;
6181
- // parseExpression stops before '\\right' or `\\middle`
6182
- let body = parser.parseExpression(false, null, true);
6218
+ let body = parser.parseExpression(false, "\\right", true);
6183
6219
  let nextToken = parser.fetch();
6184
6220
  while (nextToken.text === "\\middle") {
6185
- // `\middle`, from the ε-TeX package, ends one group and starts another group.
6186
- // We had to parse this expression with `breakOnMiddle` enabled in order
6187
- // to get TeX-compliant parsing of \over.
6188
- // But we do not want, at this point, to end on \middle, so continue
6189
- // to parse until we fetch a `\right`.
6190
6221
  parser.consume();
6191
6222
  const middle = parser.fetch().text;
6192
6223
  if (!symbols.math[middle]) {
@@ -6195,11 +6226,10 @@ var temml = (function () {
6195
6226
  checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" });
6196
6227
  body.push({ type: "middle", mode: "math", delim: middle });
6197
6228
  parser.consume();
6198
- body = body.concat(parser.parseExpression(false, null, true));
6229
+ body = body.concat(parser.parseExpression(false, "\\right", true));
6199
6230
  nextToken = parser.fetch();
6200
6231
  }
6201
6232
  --parser.leftrightDepth;
6202
- // Check the next token
6203
6233
  parser.expect("\\right", false);
6204
6234
  const right = assertNodeType(parser.parseFunction(), "leftright-right");
6205
6235
  return {
@@ -6207,35 +6237,90 @@ var temml = (function () {
6207
6237
  mode: parser.mode,
6208
6238
  body,
6209
6239
  left: delim.text,
6210
- right: right.delim
6240
+ right: right.delim,
6241
+ isStretchy: true
6211
6242
  };
6212
6243
  },
6213
6244
  mathmlBuilder: (group, style) => {
6214
6245
  assertParsed(group);
6215
6246
  const inner = buildExpression(group.body, style);
6216
6247
 
6217
- if (group.left === ".") { group.left = ""; }
6218
- const leftNode = new MathNode("mo", [makeText(group.left, group.mode)]);
6219
- leftNode.setAttribute("fence", "true");
6220
- leftNode.setAttribute("form", "prefix");
6221
- if (group.left === "/" || group.left === "\u005C" || group.left.indexOf("arrow") > -1) {
6222
- leftNode.setAttribute("stretchy", "true");
6223
- }
6248
+ const leftNode = makeFenceMo(group.left, group.mode, "prefix", true);
6224
6249
  inner.unshift(leftNode);
6225
6250
 
6226
- if (group.right === ".") { group.right = ""; }
6227
- const rightNode = new MathNode("mo", [makeText(group.right, group.mode)]);
6228
- rightNode.setAttribute("fence", "true");
6229
- rightNode.setAttribute("form", "postfix");
6230
- if (group.right === "\u2216" || group.right.indexOf("arrow") > -1) {
6231
- rightNode.setAttribute("stretchy", "true");
6251
+ const rightNode = makeFenceMo(group.right, group.mode, "postfix", true);
6252
+ if (group.body.length > 0) {
6253
+ const lastElement = group.body[group.body.length - 1];
6254
+ if (lastElement.type === "color" && !lastElement.isTextColor) {
6255
+ rightNode.setAttribute("mathcolor", lastElement.color);
6256
+ }
6232
6257
  }
6258
+ inner.push(rightNode);
6259
+
6260
+ return makeRow(inner);
6261
+ }
6262
+ });
6263
+
6264
+ defineFunction({
6265
+ type: "delimiter",
6266
+ names: Array.from(leftDelimiterNames),
6267
+ props: {
6268
+ numArgs: 0,
6269
+ allowedInText: true,
6270
+ allowedInMath: true,
6271
+ allowedInArgument: true
6272
+ },
6273
+ handler: ({ parser, funcName, token }) => {
6274
+ if (parser.mode === "text") {
6275
+ return {
6276
+ type: "textord",
6277
+ mode: "text",
6278
+ text: funcName,
6279
+ loc: token.loc
6280
+ }
6281
+ } else if (!parser.settings.wrapDelimiterPairs) {
6282
+ // Treat this token as an ordinary symbol.
6283
+ return {
6284
+ type: "atom",
6285
+ mode: "math",
6286
+ family: "open",
6287
+ loc: token.loc,
6288
+ text: funcName
6289
+ };
6290
+ }
6291
+ // Otherwise, try to wrap a pair of delimiters with an <mrow>.
6292
+ const rightDelim = leftToRight[funcName];
6293
+ // Parse the inner expression, looking for the corresponding right delimiter.
6294
+ const body = parser.parseExpression(false, rightDelim, false);
6295
+ const nextToken = parser.fetch().text;
6296
+
6297
+ if (nextToken !== rightDelim) {
6298
+ // We were unable to find a matching right delimiter.
6299
+ // Throw control back to renderToMathMLTree.
6300
+ // It will reparse the entire expression with wrapDelimiterPairs set to false.
6301
+ throw new ParseError("Unmatched delimiter");
6302
+ }
6303
+ parser.consume();
6304
+
6305
+ return {
6306
+ type: "delimiter",
6307
+ mode: parser.mode,
6308
+ body,
6309
+ left: funcName,
6310
+ right: rightDelim
6311
+ };
6312
+ },
6313
+ mathmlBuilder: (group, style) => {
6314
+ assertParsed(group);
6315
+ const inner = buildExpression(group.body, style);
6316
+
6317
+ const leftNode = makeFenceMo(group.left, group.mode, "prefix", false);
6318
+ inner.unshift(leftNode);
6319
+
6320
+ const rightNode = makeFenceMo(group.right, group.mode, "postfix", false);
6233
6321
  if (group.body.length > 0) {
6234
6322
  const lastElement = group.body[group.body.length - 1];
6235
6323
  if (lastElement.type === "color" && !lastElement.isTextColor) {
6236
- // \color is a switch. If the last element is of type "color" then
6237
- // the user set the \color switch and left it on.
6238
- // A \right delimiter turns the switch off, but the delimiter itself gets the color.
6239
6324
  rightNode.setAttribute("mathcolor", lastElement.color);
6240
6325
  }
6241
6326
  }
@@ -6264,7 +6349,7 @@ var temml = (function () {
6264
6349
  delim: delim.text
6265
6350
  };
6266
6351
  },
6267
- mathmlBuilder: (group, style) => {
6352
+ mathmlBuilder: (group) => {
6268
6353
  const textNode = makeText(group.delim, group.mode);
6269
6354
  const middleNode = new MathNode("mo", [textNode]);
6270
6355
  middleNode.setAttribute("fence", "true");
@@ -6310,7 +6395,7 @@ var temml = (function () {
6310
6395
  break
6311
6396
  case "\\xcancel":
6312
6397
  node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
6313
- node.classes.push("tml-xcancel");
6398
+ node.children.push(new MathNode("mrow", [], ["tml-cancel", "tml-xcancel"]));
6314
6399
  break
6315
6400
  // cancelto is handled in cancelto.js
6316
6401
  case "\\longdiv":
@@ -6747,22 +6832,37 @@ var temml = (function () {
6747
6832
  const stylArray = ["display", "text", "script", "scriptscript"];
6748
6833
  const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 };
6749
6834
 
6835
+ const adjustStyle = (functionSize, originalStyle) => {
6836
+ // Figure out what style this fraction should be in based on the
6837
+ // function used
6838
+ let style = originalStyle;
6839
+ if (functionSize === "display") { //\tfrac or \cfrac
6840
+ // Get display style as a default.
6841
+ // If incoming style is sub/sup, use style.text() to get correct size.
6842
+ const newSize = style.level >= StyleLevel.SCRIPT ? StyleLevel.TEXT : StyleLevel.DISPLAY;
6843
+ style = style.withLevel(newSize);
6844
+ } else if (functionSize === "text" &&
6845
+ style.level === StyleLevel.DISPLAY) {
6846
+ // We're in a \tfrac but incoming style is displaystyle, so:
6847
+ style = style.withLevel(StyleLevel.TEXT);
6848
+ } else if (functionSize === "auto") {
6849
+ style = style.incrementLevel();
6850
+ } else if (functionSize === "script") {
6851
+ style = style.withLevel(StyleLevel.SCRIPT);
6852
+ } else if (functionSize === "scriptscript") {
6853
+ style = style.withLevel(StyleLevel.SCRIPTSCRIPT);
6854
+ }
6855
+ return style;
6856
+ };
6857
+
6750
6858
  const mathmlBuilder$5 = (group, style) => {
6751
- // Track the scriptLevel of the numerator and denominator.
6752
- // We may need that info for \mathchoice or for adjusting em dimensions.
6753
- const childOptions = group.scriptLevel === "auto"
6754
- ? style.incrementLevel()
6755
- : group.scriptLevel === "display"
6756
- ? style.withLevel(StyleLevel.TEXT)
6757
- : group.scriptLevel === "text"
6758
- ? style.withLevel(StyleLevel.SCRIPT)
6759
- : style.withLevel(StyleLevel.SCRIPTSCRIPT);
6859
+ style = adjustStyle(group.scriptLevel, style);
6760
6860
 
6761
6861
  // Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
6762
6862
  // So we check for levels that Chromium shrinks too small.
6763
6863
  // If necessary, set an explicit fraction depth.
6764
- const numer = buildGroup$1(group.numer, childOptions);
6765
- const denom = buildGroup$1(group.denom, childOptions);
6864
+ const numer = buildGroup$1(group.numer, style);
6865
+ const denom = buildGroup$1(group.denom, style);
6766
6866
  if (style.level === 3) {
6767
6867
  numer.style.mathDepth = "2";
6768
6868
  numer.setAttribute("scriptlevel", "2");
@@ -6815,6 +6915,7 @@ var temml = (function () {
6815
6915
  defineFunction({
6816
6916
  type: "genfrac",
6817
6917
  names: [
6918
+ "\\cfrac",
6818
6919
  "\\dfrac",
6819
6920
  "\\frac",
6820
6921
  "\\tfrac",
@@ -6838,6 +6939,7 @@ var temml = (function () {
6838
6939
  let scriptLevel = "auto";
6839
6940
 
6840
6941
  switch (funcName) {
6942
+ case "\\cfrac":
6841
6943
  case "\\dfrac":
6842
6944
  case "\\frac":
6843
6945
  case "\\tfrac":
@@ -6864,15 +6966,10 @@ var temml = (function () {
6864
6966
  throw new Error("Unrecognized genfrac command");
6865
6967
  }
6866
6968
 
6867
- switch (funcName) {
6868
- case "\\dfrac":
6869
- case "\\dbinom":
6870
- scriptLevel = "display";
6871
- break;
6872
- case "\\tfrac":
6873
- case "\\tbinom":
6874
- scriptLevel = "text";
6875
- break;
6969
+ if (funcName === "\\cfrac" || funcName.startsWith("\\d")) {
6970
+ scriptLevel = "display";
6971
+ } else if (funcName.startsWith("\\t")) {
6972
+ scriptLevel = "text";
6876
6973
  }
6877
6974
 
6878
6975
  return {
@@ -6891,31 +6988,6 @@ var temml = (function () {
6891
6988
  mathmlBuilder: mathmlBuilder$5
6892
6989
  });
6893
6990
 
6894
- defineFunction({
6895
- type: "genfrac",
6896
- names: ["\\cfrac"],
6897
- props: {
6898
- numArgs: 2
6899
- },
6900
- handler: ({ parser, funcName }, args) => {
6901
- const numer = args[0];
6902
- const denom = args[1];
6903
-
6904
- return {
6905
- type: "genfrac",
6906
- mode: parser.mode,
6907
- continued: true,
6908
- numer,
6909
- denom,
6910
- hasBarLine: true,
6911
- leftDelim: null,
6912
- rightDelim: null,
6913
- scriptLevel: "display",
6914
- barSize: null
6915
- };
6916
- }
6917
- });
6918
-
6919
6991
  // Infix generalized fractions -- these are not rendered directly, but replaced
6920
6992
  // immediately by one of the variants above.
6921
6993
  defineFunction({
@@ -7744,8 +7816,16 @@ var temml = (function () {
7744
7816
  const atom = arg.type === "ordgroup" && arg.body.length && arg.body.length === 1
7745
7817
  ? arg.body[0]
7746
7818
  : arg;
7747
- if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) {
7748
- return "m" + atom.family;
7819
+ if (atom.type === "atom") {
7820
+ // BIN args are sometimes changed to OPEN, so check the original family.
7821
+ const family = arg.body.length > 0 && arg.body[0].text && symbols.math[arg.body[0].text]
7822
+ ? symbols.math[arg.body[0].text].group
7823
+ : atom.family;
7824
+ if (family === "bin" || family === "rel") {
7825
+ return "m" + family;
7826
+ } else {
7827
+ return "mord";
7828
+ }
7749
7829
  } else {
7750
7830
  return "mord";
7751
7831
  }
@@ -8316,6 +8396,14 @@ var temml = (function () {
8316
8396
  if ((node.type === "mrow" || node.type === "mpadded") && node.children.length === 1 &&
8317
8397
  node.children[0] instanceof MathNode) {
8318
8398
  node = node.children[0];
8399
+ } else if (node.type === "mrow" && node.children.length === 2 &&
8400
+ node.children[0] instanceof MathNode &&
8401
+ node.children[1] instanceof MathNode &&
8402
+ node.children[1].type === "mspace" && !node.children[1].attributes.width &&
8403
+ node.children[1].children.length === 0) {
8404
+ // This is a workaround for a Firefox bug that applies spacing to
8405
+ // an <mi> with mathvariant="normal".
8406
+ node = node.children[0];
8319
8407
  }
8320
8408
  switch (node.type) {
8321
8409
  case "mi":
@@ -9586,8 +9674,8 @@ var temml = (function () {
9586
9674
  node.setAttribute("mathvariant", "normal");
9587
9675
  if (text.text.length === 1) {
9588
9676
  // A Firefox bug will apply spacing here, but there should be none. Fix it.
9589
- node = new MathNode("mpadded", [node]);
9590
- node.setAttribute("lspace", "0");
9677
+ const mspace = new MathNode("mspace", []);
9678
+ node = new MathNode("mrow", [node, mspace]);
9591
9679
  }
9592
9680
  }
9593
9681
  return node
@@ -11124,7 +11212,7 @@ var temml = (function () {
11124
11212
  * Parses an "expression", which is a list of atoms.
11125
11213
  *
11126
11214
  * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
11127
- * happens when functions have higher precedence han infix
11215
+ * happens when functions have higher precedence than infix
11128
11216
  * nodes in implicit parses.
11129
11217
  *
11130
11218
  * `breakOnTokenText`: The text of the token that the expression should end
@@ -11732,7 +11820,7 @@ var temml = (function () {
11732
11820
  ) {
11733
11821
  const firstToken = this.fetch();
11734
11822
  const text = firstToken.text;
11735
-
11823
+ if (name === "argument to '\\left'") { return this.parseSymbol() }
11736
11824
  let result;
11737
11825
  // Try to parse an open brace or \begingroup
11738
11826
  if (text === "{" || text === "\\begingroup" || text === "\\toggle") {
@@ -11765,6 +11853,12 @@ var temml = (function () {
11765
11853
  result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol();
11766
11854
  if (result == null && text[0] === "\\" &&
11767
11855
  !Object.prototype.hasOwnProperty.call(implicitCommands, text )) {
11856
+ if (this.settings.throwOnError) {
11857
+ throw new ParseError("Unsupported function name: " + text, firstToken);
11858
+ }
11859
+ // For people getting dyanamically rendered math, it's better to
11860
+ // show the unsupported command in red rather than panicking for every
11861
+ // partially written expression.
11768
11862
  result = this.formatUnsupportedCmd(text);
11769
11863
  this.consume();
11770
11864
  }
@@ -11873,7 +11967,8 @@ var temml = (function () {
11873
11967
  let symbol;
11874
11968
  if (symbols[this.mode][text]) {
11875
11969
  let group = symbols[this.mode][text].group;
11876
- if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) {
11970
+ if (group === "bin" &&
11971
+ (binLeftCancellers.includes(this.prevAtomType) || this.prevAtomType === "")) {
11877
11972
  // Change from a binary operator to a unary (prefix) operator
11878
11973
  group = "open";
11879
11974
  }
@@ -11969,11 +12064,27 @@ var temml = (function () {
11969
12064
  if (!(typeof toParse === "string" || toParse instanceof String)) {
11970
12065
  throw new TypeError("Temml can only parse string typed expression")
11971
12066
  }
11972
- const parser = new Parser(toParse, settings);
11973
- // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
11974
- delete parser.gullet.macros.current["\\df@tag"];
12067
+ let tree;
12068
+ let parser;
12069
+ try {
12070
+ parser = new Parser(toParse, settings);
12071
+ // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
12072
+ delete parser.gullet.macros.current["\\df@tag"];
11975
12073
 
11976
- let tree = parser.parse();
12074
+ tree = parser.parse();
12075
+ } catch (error) {
12076
+ if (error.toString() === "ParseError: Unmatched delimiter") {
12077
+ // Abandon the attempt to wrap delimiter pairs in an <mrow>.
12078
+ // Try again, and put each delimiter into an <mo> element.
12079
+ settings.wrapDelimiterPairs = false;
12080
+ parser = new Parser(toParse, settings);
12081
+ // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
12082
+ delete parser.gullet.macros.current["\\df@tag"];
12083
+ tree = parser.parse();
12084
+ } else {
12085
+ throw error;
12086
+ }
12087
+ }
11977
12088
 
11978
12089
  // LaTeX ignores a \tag placed outside an AMS environment.
11979
12090
  if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) {
@@ -12150,7 +12261,7 @@ var temml = (function () {
12150
12261
  * https://mit-license.org/
12151
12262
  */
12152
12263
 
12153
- const version = "0.12.02";
12264
+ const version = "0.13.02";
12154
12265
 
12155
12266
  function postProcess(block) {
12156
12267
  const labelMap = {};