temml 0.13.1 → 0.13.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/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
  }
@@ -4253,6 +4246,7 @@ var temml = (function () {
4253
4246
  // cmll package
4254
4247
  defineMacro("\\invamp", '\\mathbin{\\char"214b}');
4255
4248
  defineMacro("\\parr", '\\mathbin{\\char"214b}');
4249
+ defineMacro("\\upand", '\\mathbin{\\char"214b}'); // STIX package
4256
4250
  defineMacro("\\with", '\\mathbin{\\char"26}');
4257
4251
  defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}');
4258
4252
  defineMacro("\\multimapboth", '\\mathrel{\\char"29df}');
@@ -4613,9 +4607,9 @@ var temml = (function () {
4613
4607
  }
4614
4608
  if (mustSquashRow) {
4615
4609
  // All the cell contents are \hphantom. Squash the cell.
4610
+ // TODO: Remove the next line when Firefox no longer needs it.
4611
+ mtr.classes.push("ff-squash"); // necessary in Firefox only.
4616
4612
  for (let j = 0; j < mtr.children.length; j++) {
4617
- mtr.children[j].style.display = "block"; // necessary in Firefox only
4618
- mtr.children[j].style.height = "0"; // necessary in Firefox only
4619
4613
  mtr.children[j].style.paddingTop = "0";
4620
4614
  mtr.children[j].style.paddingBottom = "0";
4621
4615
  }
@@ -5256,13 +5250,11 @@ var temml = (function () {
5256
5250
  },
5257
5251
  handler: ({ parser, funcName }, args, optArgs) => {
5258
5252
  // Find out if the author has defined custom delimiters
5259
- let delimiters = ["(", ")"];
5253
+ let delimiters = ["(", ")"]; // default
5260
5254
  if (funcName === "\\bordermatrix" && optArgs[0] && optArgs[0].body) {
5261
5255
  const body = optArgs[0].body;
5262
- if (body.length === 2 && body[0].type === "atom" && body[1].type === "atom") {
5263
- if (body[0].family === "open" && body[1].family === "close") {
5264
- delimiters = [body[0].text, body[1].text];
5265
- }
5256
+ if (body.length === 1 && body[0].type === "delimiter") {
5257
+ delimiters = [body[0].left, body[0].right];
5266
5258
  }
5267
5259
  }
5268
5260
  // consume the opening brace
@@ -5310,6 +5302,7 @@ var temml = (function () {
5310
5302
  // That way, the arrow will be an overlay on the content.
5311
5303
  const phantom = new MathNode("mphantom", [buildGroup$1(group.body, style)]);
5312
5304
  const arrow = new MathNode("mrow", [phantom], ["tml-cancelto"]);
5305
+ arrow.style.color = style.color;
5313
5306
  if (group.isCharacterBox && smalls.indexOf(group.body.body[0].text) > -1) {
5314
5307
  arrow.style.left = "0.1em";
5315
5308
  arrow.style.width = "90%";
@@ -5341,6 +5334,7 @@ var temml = (function () {
5341
5334
  dummyNode = new MathNode("mphantom", [zeroWidthNode]); // Hide it.
5342
5335
  }
5343
5336
  const toNode = buildGroup$1(group.to, style);
5337
+ toNode.style.color = style.color;
5344
5338
  const zeroWidthToNode = new MathNode("mpadded", [toNode]);
5345
5339
  if (!group.isCharacterBox || /[f∫∑]/.test(group.body.body[0].text)) {
5346
5340
  const w = new MathNode("mspace", []);
@@ -5399,7 +5393,7 @@ var temml = (function () {
5399
5393
 
5400
5394
  // Colors from Tables 4.1 and 4.2 of the xcolor package.
5401
5395
  // Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx.
5402
- // Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable
5396
+ // Table 4.2 (Capitalized) values were sampled, because Chroma contains a unreliable
5403
5397
  // conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274.
5404
5398
  const xcolors = JSON.parse(`{
5405
5399
  "Apricot": "#ffb484",
@@ -5958,7 +5952,41 @@ var temml = (function () {
5958
5952
  "\\Bigg": { mclass: "mord", size: 4 }
5959
5953
  };
5960
5954
 
5961
- const delimiters = [
5955
+ const leftToRight = {
5956
+ "(": ")",
5957
+ "\\lparen": "\\rparen",
5958
+ "[": "]",
5959
+ "\\lbrack": "\\rbrack",
5960
+ "\\{": "\\}",
5961
+ "\\lbrace": "\\rbrace",
5962
+ "⦇": "⦈",
5963
+ "\\llparenthesis": "\\rrparenthesis",
5964
+ "\\lfloor": "\\rfloor",
5965
+ "\u230a": "\u230b",
5966
+ "\\lceil": "\\rceil",
5967
+ "\u2308": "\u2309",
5968
+ "\\langle": "\\rangle",
5969
+ "\u27e8": "\u27e9",
5970
+ "\\lAngle": "\\rAngle",
5971
+ "\u27ea": "\u27eb",
5972
+ "\\llangle": "\\rrangle",
5973
+ "⦉": "⦊",
5974
+ "\\lvert": "\\rvert",
5975
+ "\\lVert": "\\rVert",
5976
+ "\\lgroup": "\\rgroup",
5977
+ "\u27ee": "\u27ef",
5978
+ "\\lmoustache": "\\rmoustache",
5979
+ "\u23b0": "\u23b1",
5980
+ "\\llbracket": "\\rrbracket",
5981
+ "\u27e6": "\u27e7",
5982
+ "\\lBrace": "\\rBrace",
5983
+ "\u2983": "\u2984"
5984
+ };
5985
+
5986
+ const leftDelimiterNames = new Set(Object.keys(leftToRight));
5987
+ new Set(Object.values(leftToRight));
5988
+
5989
+ const delimiters = new Set([
5962
5990
  "(",
5963
5991
  "\\lparen",
5964
5992
  ")",
@@ -6014,7 +6042,7 @@ var temml = (function () {
6014
6042
  "\\llbracket",
6015
6043
  "\\rrbracket",
6016
6044
  "\u27e6",
6017
- "\u27e6",
6045
+ "\u27e7",
6018
6046
  "\\lBrace",
6019
6047
  "\\rBrace",
6020
6048
  "\u2983",
@@ -6033,12 +6061,12 @@ var temml = (function () {
6033
6061
  "\\updownarrow",
6034
6062
  "\\Updownarrow",
6035
6063
  "."
6036
- ];
6064
+ ]);
6037
6065
 
6038
6066
  // Export isDelimiter for benefit of parser.
6039
- const dels = ["}", "\\left", "\\middle", "\\right"];
6067
+ const dels = new Set(["}", "\\left", "\\middle", "\\right"]);
6040
6068
  const isDelimiter = str => str.length > 0 &&
6041
- (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
6069
+ (delimiters.has(str) || delimiterSizes[str] || dels.has(str));
6042
6070
 
6043
6071
  // Metrics of the different sizes. Found by looking at TeX's output of
6044
6072
  // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
@@ -6051,11 +6079,11 @@ var temml = (function () {
6051
6079
  delim = delim.body[0]; // Unwrap the braces
6052
6080
  }
6053
6081
  const symDelim = checkSymbolNodeType(delim);
6054
- if (symDelim && delimiters.includes(symDelim.text)) {
6082
+ if (symDelim && delimiters.has(symDelim.text)) {
6055
6083
  // If a character is not in the MathML operator dictionary, it will not stretch.
6056
6084
  // Replace such characters w/characters that will stretch.
6057
- if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; }
6058
- if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; }
6085
+ if (symDelim.text === "<" || symDelim.text === "\\lt") { symDelim.text = "⟨"; }
6086
+ if (symDelim.text === ">" || symDelim.text === "\\gt") { symDelim.text = "⟩"; }
6059
6087
  return symDelim;
6060
6088
  } else if (symDelim) {
6061
6089
  throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
@@ -6065,7 +6093,16 @@ var temml = (function () {
6065
6093
  }
6066
6094
 
6067
6095
  // / \
6068
- const needExplicitStretch = ["\u002F", "\u005C", "\\backslash", "\\vert", "|"];
6096
+ const needExplicitStretch = new Set(["\u002F", "\u005C", "\\backslash", "\u2216", "\\vert", "|"]);
6097
+
6098
+ const makeFenceMo = (delim, mode, form, isStretchy) => {
6099
+ const text = delim === "." ? "" : delim;
6100
+ const node = new MathNode("mo", [makeText(text, mode)]);
6101
+ node.setAttribute("fence", "true");
6102
+ node.setAttribute("form", form);
6103
+ node.setAttribute("stretchy", isStretchy ? "true" : "false");
6104
+ return node;
6105
+ };
6069
6106
 
6070
6107
  defineFunction({
6071
6108
  type: "delimsizing",
@@ -6116,9 +6153,9 @@ var temml = (function () {
6116
6153
  },
6117
6154
  mathmlBuilder: (group) => {
6118
6155
  const children = [];
6156
+ const delim = group.delim === "." ? "" : group.delim;
6119
6157
 
6120
- if (group.delim === ".") { group.delim = ""; }
6121
- children.push(makeText(group.delim, group.mode));
6158
+ children.push(makeText(delim, group.mode));
6122
6159
 
6123
6160
  const node = new MathNode("mo", children);
6124
6161
 
@@ -6131,7 +6168,7 @@ var temml = (function () {
6131
6168
  // defaults.
6132
6169
  node.setAttribute("fence", "false");
6133
6170
  }
6134
- if (needExplicitStretch.includes(group.delim) || group.delim.indexOf("arrow") > -1) {
6171
+ if (needExplicitStretch.has(delim) || delim.indexOf("arrow") > -1) {
6135
6172
  // We have to explicitly set stretchy to true.
6136
6173
  node.setAttribute("stretchy", "true");
6137
6174
  }
@@ -6144,7 +6181,7 @@ var temml = (function () {
6144
6181
 
6145
6182
  function assertParsed(group) {
6146
6183
  if (!group.body) {
6147
- throw new Error("Bug: The leftright ParseNode wasn't fully parsed.");
6184
+ throw new Error("Bug: The delim ParseNode wasn't fully parsed.");
6148
6185
  }
6149
6186
  }
6150
6187
 
@@ -6175,17 +6212,10 @@ var temml = (function () {
6175
6212
  const delim = checkDelimiter(args[0], context);
6176
6213
 
6177
6214
  const parser = context.parser;
6178
- // Parse out the implicit body
6179
6215
  ++parser.leftrightDepth;
6180
- // parseExpression stops before '\\right' or `\\middle`
6181
- let body = parser.parseExpression(false, null, true);
6216
+ let body = parser.parseExpression(false, "\\right", true);
6182
6217
  let nextToken = parser.fetch();
6183
6218
  while (nextToken.text === "\\middle") {
6184
- // `\middle`, from the ε-TeX package, ends one group and starts another group.
6185
- // We had to parse this expression with `breakOnMiddle` enabled in order
6186
- // to get TeX-compliant parsing of \over.
6187
- // But we do not want, at this point, to end on \middle, so continue
6188
- // to parse until we fetch a `\right`.
6189
6219
  parser.consume();
6190
6220
  const middle = parser.fetch().text;
6191
6221
  if (!symbols.math[middle]) {
@@ -6194,11 +6224,10 @@ var temml = (function () {
6194
6224
  checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" });
6195
6225
  body.push({ type: "middle", mode: "math", delim: middle });
6196
6226
  parser.consume();
6197
- body = body.concat(parser.parseExpression(false, null, true));
6227
+ body = body.concat(parser.parseExpression(false, "\\right", true));
6198
6228
  nextToken = parser.fetch();
6199
6229
  }
6200
6230
  --parser.leftrightDepth;
6201
- // Check the next token
6202
6231
  parser.expect("\\right", false);
6203
6232
  const right = assertNodeType(parser.parseFunction(), "leftright-right");
6204
6233
  return {
@@ -6206,35 +6235,90 @@ var temml = (function () {
6206
6235
  mode: parser.mode,
6207
6236
  body,
6208
6237
  left: delim.text,
6209
- right: right.delim
6238
+ right: right.delim,
6239
+ isStretchy: true
6210
6240
  };
6211
6241
  },
6212
6242
  mathmlBuilder: (group, style) => {
6213
6243
  assertParsed(group);
6214
6244
  const inner = buildExpression(group.body, style);
6215
6245
 
6216
- if (group.left === ".") { group.left = ""; }
6217
- const leftNode = new MathNode("mo", [makeText(group.left, group.mode)]);
6218
- leftNode.setAttribute("fence", "true");
6219
- leftNode.setAttribute("form", "prefix");
6220
- if (group.left === "/" || group.left === "\u005C" || group.left.indexOf("arrow") > -1) {
6221
- leftNode.setAttribute("stretchy", "true");
6222
- }
6246
+ const leftNode = makeFenceMo(group.left, group.mode, "prefix", true);
6223
6247
  inner.unshift(leftNode);
6224
6248
 
6225
- if (group.right === ".") { group.right = ""; }
6226
- const rightNode = new MathNode("mo", [makeText(group.right, group.mode)]);
6227
- rightNode.setAttribute("fence", "true");
6228
- rightNode.setAttribute("form", "postfix");
6229
- if (group.right === "\u2216" || group.right.indexOf("arrow") > -1) {
6230
- rightNode.setAttribute("stretchy", "true");
6249
+ const rightNode = makeFenceMo(group.right, group.mode, "postfix", true);
6250
+ if (group.body.length > 0) {
6251
+ const lastElement = group.body[group.body.length - 1];
6252
+ if (lastElement.type === "color" && !lastElement.isTextColor) {
6253
+ rightNode.setAttribute("mathcolor", lastElement.color);
6254
+ }
6231
6255
  }
6256
+ inner.push(rightNode);
6257
+
6258
+ return makeRow(inner);
6259
+ }
6260
+ });
6261
+
6262
+ defineFunction({
6263
+ type: "delimiter",
6264
+ names: Array.from(leftDelimiterNames),
6265
+ props: {
6266
+ numArgs: 0,
6267
+ allowedInText: true,
6268
+ allowedInMath: true,
6269
+ allowedInArgument: true
6270
+ },
6271
+ handler: ({ parser, funcName, token }) => {
6272
+ if (parser.mode === "text") {
6273
+ return {
6274
+ type: "textord",
6275
+ mode: "text",
6276
+ text: funcName,
6277
+ loc: token.loc
6278
+ }
6279
+ } else if (!parser.settings.wrapDelimiterPairs) {
6280
+ // Treat this token as an ordinary symbol.
6281
+ return {
6282
+ type: "atom",
6283
+ mode: "math",
6284
+ family: "open",
6285
+ loc: token.loc,
6286
+ text: funcName
6287
+ };
6288
+ }
6289
+ // Otherwise, try to wrap a pair of delimiters with an <mrow>.
6290
+ const rightDelim = leftToRight[funcName];
6291
+ // Parse the inner expression, looking for the corresponding right delimiter.
6292
+ const body = parser.parseExpression(false, rightDelim, false);
6293
+ const nextToken = parser.fetch().text;
6294
+
6295
+ if (nextToken !== rightDelim) {
6296
+ // We were unable to find a matching right delimiter.
6297
+ // Throw control back to renderToMathMLTree.
6298
+ // It will reparse the entire expression with wrapDelimiterPairs set to false.
6299
+ throw new ParseError("Unmatched delimiter");
6300
+ }
6301
+ parser.consume();
6302
+
6303
+ return {
6304
+ type: "delimiter",
6305
+ mode: parser.mode,
6306
+ body,
6307
+ left: funcName,
6308
+ right: rightDelim
6309
+ };
6310
+ },
6311
+ mathmlBuilder: (group, style) => {
6312
+ assertParsed(group);
6313
+ const inner = buildExpression(group.body, style);
6314
+
6315
+ const leftNode = makeFenceMo(group.left, group.mode, "prefix", false);
6316
+ inner.unshift(leftNode);
6317
+
6318
+ const rightNode = makeFenceMo(group.right, group.mode, "postfix", false);
6232
6319
  if (group.body.length > 0) {
6233
6320
  const lastElement = group.body[group.body.length - 1];
6234
6321
  if (lastElement.type === "color" && !lastElement.isTextColor) {
6235
- // \color is a switch. If the last element is of type "color" then
6236
- // the user set the \color switch and left it on.
6237
- // A \right delimiter turns the switch off, but the delimiter itself gets the color.
6238
6322
  rightNode.setAttribute("mathcolor", lastElement.color);
6239
6323
  }
6240
6324
  }
@@ -6263,20 +6347,17 @@ var temml = (function () {
6263
6347
  delim: delim.text
6264
6348
  };
6265
6349
  },
6266
- mathmlBuilder: (group, style) => {
6350
+ mathmlBuilder: (group) => {
6267
6351
  const textNode = makeText(group.delim, group.mode);
6268
6352
  const middleNode = new MathNode("mo", [textNode]);
6269
- middleNode.setAttribute("fence", "true");
6270
- if (group.delim.indexOf("arrow") > -1) {
6271
- middleNode.setAttribute("stretchy", "true");
6272
- }
6273
- // The next line is not semantically correct, but
6274
- // Chromium fails to stretch if it is not there.
6275
- middleNode.setAttribute("form", "prefix");
6276
- // MathML gives 5/18em spacing to each <mo> element.
6277
- // \middle should get delimiter spacing instead.
6278
- middleNode.setAttribute("lspace", "0.05em");
6279
- middleNode.setAttribute("rspace", "0.05em");
6353
+ middleNode.setAttribute("stretchy", "true");
6354
+ middleNode.setAttribute("form", "infix");
6355
+ if (textNode.text !== "/") {
6356
+ // MathML gives 5/18em spacing to each <mo> element.
6357
+ // \middle should get delimiter spacing instead.
6358
+ middleNode.setAttribute("lspace", "0.05em");
6359
+ middleNode.setAttribute("rspace", "0.05em");
6360
+ }
6280
6361
  return middleNode;
6281
6362
  }
6282
6363
  });
@@ -6309,7 +6390,7 @@ var temml = (function () {
6309
6390
  break
6310
6391
  case "\\xcancel":
6311
6392
  node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
6312
- node.classes.push("tml-xcancel");
6393
+ node.children.push(new MathNode("mrow", [], ["tml-cancel", "tml-xcancel"]));
6313
6394
  break
6314
6395
  // cancelto is handled in cancelto.js
6315
6396
  case "\\longdiv":
@@ -6443,7 +6524,7 @@ var temml = (function () {
6443
6524
 
6444
6525
  defineFunction({
6445
6526
  type: "enclose",
6446
- names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline",
6527
+ names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\overline",
6447
6528
  "\\boxed", "\\longdiv", "\\phase"],
6448
6529
  props: {
6449
6530
  numArgs: 1
@@ -6460,6 +6541,25 @@ var temml = (function () {
6460
6541
  mathmlBuilder: mathmlBuilder$7
6461
6542
  });
6462
6543
 
6544
+ defineFunction({
6545
+ type: "enclose",
6546
+ names: ["\\sout"],
6547
+ props: {
6548
+ numArgs: 1,
6549
+ allowedInText: true
6550
+ },
6551
+ handler({ parser, funcName }, args) {
6552
+ const body = args[0];
6553
+ return {
6554
+ type: "enclose",
6555
+ mode: parser.mode,
6556
+ label: funcName,
6557
+ body
6558
+ };
6559
+ },
6560
+ mathmlBuilder: mathmlBuilder$7
6561
+ });
6562
+
6463
6563
  defineFunction({
6464
6564
  type: "enclose",
6465
6565
  names: ["\\underline"],
@@ -6592,8 +6692,237 @@ var temml = (function () {
6592
6692
  }
6593
6693
  });
6594
6694
 
6695
+ // Chromium does not support the MathML `mathvariant` attribute.
6696
+ // Instead, we replace ASCII characters with Unicode characters that
6697
+ // are defined in the font as bold, italic, double-struck, etc.
6698
+ // This module identifies those Unicode code points.
6699
+
6700
+ // First, a few helpers.
6701
+ const script = Object.freeze({
6702
+ B: 0x20EA, // Offset from ASCII B to Unicode script B
6703
+ E: 0x20EB,
6704
+ F: 0x20EB,
6705
+ H: 0x20C3,
6706
+ I: 0x20C7,
6707
+ L: 0x20C6,
6708
+ M: 0x20E6,
6709
+ R: 0x20C9,
6710
+ e: 0x20CA,
6711
+ g: 0x20A3,
6712
+ o: 0x20C5
6713
+ });
6714
+
6715
+ const frak = Object.freeze({
6716
+ C: 0x20EA,
6717
+ H: 0x20C4,
6718
+ I: 0x20C8,
6719
+ R: 0x20CA,
6720
+ Z: 0x20CE
6721
+ });
6722
+
6723
+ const bbb = Object.freeze({
6724
+ C: 0x20BF, // blackboard bold
6725
+ H: 0x20C5,
6726
+ N: 0x20C7,
6727
+ P: 0x20C9,
6728
+ Q: 0x20C9,
6729
+ R: 0x20CB,
6730
+ Z: 0x20CA
6731
+ });
6732
+
6733
+ const bold = Object.freeze({
6734
+ "\u03f5": 0x1D2E7, // lunate epsilon
6735
+ "\u03d1": 0x1D30C, // vartheta
6736
+ "\u03f0": 0x1D2EE, // varkappa
6737
+ "\u03c6": 0x1D319, // varphi
6738
+ "\u03f1": 0x1D2EF, // varrho
6739
+ "\u03d6": 0x1D30B // varpi
6740
+ });
6741
+
6742
+ const boldItalic = Object.freeze({
6743
+ "\u03f5": 0x1D35B, // lunate epsilon
6744
+ "\u03d1": 0x1D380, // vartheta
6745
+ "\u03f0": 0x1D362, // varkappa
6746
+ "\u03c6": 0x1D38D, // varphi
6747
+ "\u03f1": 0x1D363, // varrho
6748
+ "\u03d6": 0x1D37F // varpi
6749
+ });
6750
+
6751
+ const boldsf = Object.freeze({
6752
+ "\u03f5": 0x1D395, // lunate epsilon
6753
+ "\u03d1": 0x1D3BA, // vartheta
6754
+ "\u03f0": 0x1D39C, // varkappa
6755
+ "\u03c6": 0x1D3C7, // varphi
6756
+ "\u03f1": 0x1D39D, // varrho
6757
+ "\u03d6": 0x1D3B9 // varpi
6758
+ });
6759
+
6760
+ const bisf = Object.freeze({
6761
+ "\u03f5": 0x1D3CF, // lunate epsilon
6762
+ "\u03d1": 0x1D3F4, // vartheta
6763
+ "\u03f0": 0x1D3D6, // varkappa
6764
+ "\u03c6": 0x1D401, // varphi
6765
+ "\u03f1": 0x1D3D7, // varrho
6766
+ "\u03d6": 0x1D3F3 // varpi
6767
+ });
6768
+
6769
+ // Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf
6770
+ const offset = Object.freeze({
6771
+ upperCaseLatin: { // A-Z
6772
+ "normal": ch => { return 0 },
6773
+ "bold": ch => { return 0x1D3BF },
6774
+ "italic": ch => { return 0x1D3F3 },
6775
+ "bold-italic": ch => { return 0x1D427 },
6776
+ "script": ch => { return script[ch] || 0x1D45B },
6777
+ "script-bold": ch => { return 0x1D48F },
6778
+ "fraktur": ch => { return frak[ch] || 0x1D4C3 },
6779
+ "fraktur-bold": ch => { return 0x1D52B },
6780
+ "double-struck": ch => { return bbb[ch] || 0x1D4F7 },
6781
+ "sans-serif": ch => { return 0x1D55F },
6782
+ "sans-serif-bold": ch => { return 0x1D593 },
6783
+ "sans-serif-italic": ch => { return 0x1D5C7 },
6784
+ "sans-serif-bold-italic": ch => { return 0x1D63C },
6785
+ "monospace": ch => { return 0x1D62F }
6786
+ },
6787
+ lowerCaseLatin: { // a-z
6788
+ "normal": ch => { return 0 },
6789
+ "bold": ch => { return 0x1D3B9 },
6790
+ "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED },
6791
+ "bold-italic": ch => { return 0x1D421 },
6792
+ "script": ch => { return script[ch] || 0x1D455 },
6793
+ "script-bold": ch => { return 0x1D489 },
6794
+ "fraktur": ch => { return 0x1D4BD },
6795
+ "fraktur-bold": ch => { return 0x1D525 },
6796
+ "double-struck": ch => { return 0x1D4F1 },
6797
+ "sans-serif": ch => { return 0x1D559 },
6798
+ "sans-serif-bold": ch => { return 0x1D58D },
6799
+ "sans-serif-italic": ch => { return 0x1D5C1 },
6800
+ "sans-serif-bold-italic": ch => { return 0x1D5F5 },
6801
+ "monospace": ch => { return 0x1D629 }
6802
+ },
6803
+ upperCaseGreek: { // A-Ω
6804
+ "normal": ch => { return 0 },
6805
+ "bold": ch => { return 0x1D317 },
6806
+ "italic": ch => { return 0x1D351 },
6807
+ // \boldsymbol actually returns upright bold for upperCaseGreek
6808
+ "bold-italic": ch => { return 0x1D317 },
6809
+ "script": ch => { return 0 },
6810
+ "script-bold": ch => { return 0 },
6811
+ "fraktur": ch => { return 0 },
6812
+ "fraktur-bold": ch => { return 0 },
6813
+ "double-struck": ch => { return 0 },
6814
+ // Unicode has no code points for regular-weight san-serif Greek. Use bold.
6815
+ "sans-serif": ch => { return 0x1D3C5 },
6816
+ "sans-serif-bold": ch => { return 0x1D3C5 },
6817
+ "sans-serif-italic": ch => { return 0 },
6818
+ "sans-serif-bold-italic": ch => { return 0x1D3FF },
6819
+ "monospace": ch => { return 0 }
6820
+ },
6821
+ lowerCaseGreek: { // α-ω
6822
+ "normal": ch => { return 0 },
6823
+ "bold": ch => { return 0x1D311 },
6824
+ "italic": ch => { return 0x1D34B },
6825
+ "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 },
6826
+ "script": ch => { return 0 },
6827
+ "script-bold": ch => { return 0 },
6828
+ "fraktur": ch => { return 0 },
6829
+ "fraktur-bold": ch => { return 0 },
6830
+ "double-struck": ch => { return 0 },
6831
+ // Unicode has no code points for regular-weight san-serif Greek. Use bold.
6832
+ "sans-serif": ch => { return 0x1D3BF },
6833
+ "sans-serif-bold": ch => { return 0x1D3BF },
6834
+ "sans-serif-italic": ch => { return 0 },
6835
+ "sans-serif-bold-italic": ch => { return 0x1D3F9 },
6836
+ "monospace": ch => { return 0 }
6837
+ },
6838
+ varGreek: { // \varGamma, etc
6839
+ "normal": ch => { return 0 },
6840
+ "bold": ch => { return bold[ch] || -51 },
6841
+ "italic": ch => { return 0 },
6842
+ "bold-italic": ch => { return boldItalic[ch] || 0x3A },
6843
+ "script": ch => { return 0 },
6844
+ "script-bold": ch => { return 0 },
6845
+ "fraktur": ch => { return 0 },
6846
+ "fraktur-bold": ch => { return 0 },
6847
+ "double-struck": ch => { return 0 },
6848
+ "sans-serif": ch => { return boldsf[ch] || 0x74 },
6849
+ "sans-serif-bold": ch => { return boldsf[ch] || 0x74 },
6850
+ "sans-serif-italic": ch => { return 0 },
6851
+ "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE },
6852
+ "monospace": ch => { return 0 }
6853
+ },
6854
+ numeral: { // 0-9
6855
+ "normal": ch => { return 0 },
6856
+ "bold": ch => { return 0x1D79E },
6857
+ "italic": ch => { return 0 },
6858
+ "bold-italic": ch => { return 0 },
6859
+ "script": ch => { return 0 },
6860
+ "script-bold": ch => { return 0 },
6861
+ "fraktur": ch => { return 0 },
6862
+ "fraktur-bold": ch => { return 0 },
6863
+ "double-struck": ch => { return 0x1D7A8 },
6864
+ "sans-serif": ch => { return 0x1D7B2 },
6865
+ "sans-serif-bold": ch => { return 0x1D7BC },
6866
+ "sans-serif-italic": ch => { return 0 },
6867
+ "sans-serif-bold-italic": ch => { return 0 },
6868
+ "monospace": ch => { return 0x1D7C6 }
6869
+ }
6870
+ });
6871
+
6872
+ const variantChar = (ch, variant) => {
6873
+ const codePoint = ch.codePointAt(0);
6874
+ const block = 0x40 < codePoint && codePoint < 0x5b
6875
+ ? "upperCaseLatin"
6876
+ : 0x60 < codePoint && codePoint < 0x7b
6877
+ ? "lowerCaseLatin"
6878
+ : (0x390 < codePoint && codePoint < 0x3AA)
6879
+ ? "upperCaseGreek"
6880
+ : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5"
6881
+ ? "lowerCaseGreek"
6882
+ : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch]
6883
+ ? "varGreek"
6884
+ : (0x2F < codePoint && codePoint < 0x3A)
6885
+ ? "numeral"
6886
+ : "other";
6887
+ return block === "other"
6888
+ ? ch
6889
+ : String.fromCodePoint(codePoint + offset[block][variant](ch))
6890
+ };
6891
+
6892
+ const smallCaps = Object.freeze({
6893
+ a: "ᴀ",
6894
+ b: "ʙ",
6895
+ c: "ᴄ",
6896
+ d: "ᴅ",
6897
+ e: "ᴇ",
6898
+ f: "ꜰ",
6899
+ g: "ɢ",
6900
+ h: "ʜ",
6901
+ i: "ɪ",
6902
+ j: "ᴊ",
6903
+ k: "ᴋ",
6904
+ l: "ʟ",
6905
+ m: "ᴍ",
6906
+ n: "ɴ",
6907
+ o: "ᴏ",
6908
+ p: "ᴘ",
6909
+ q: "ǫ",
6910
+ r: "ʀ",
6911
+ s: "s",
6912
+ t: "ᴛ",
6913
+ u: "ᴜ",
6914
+ v: "ᴠ",
6915
+ w: "ᴡ",
6916
+ x: "x",
6917
+ y: "ʏ",
6918
+ z: "ᴢ"
6919
+ });
6920
+
6921
+ const varNameFonts = ["mathrm", "mathit"];
6922
+
6595
6923
  const isLongVariableName = (group, font) => {
6596
- if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) {
6924
+ if (!varNameFonts.includes(font) || !group.body || group.body.type !== "ordgroup" ||
6925
+ group.body.body.length === 1) {
6597
6926
  return false
6598
6927
  }
6599
6928
  if (group.body.body[0].type !== "mathord") { return false }
@@ -6619,8 +6948,7 @@ var temml = (function () {
6619
6948
  }
6620
6949
  // Check if it is possible to consolidate elements into a single <mi> element.
6621
6950
  if (isLongVariableName(group, font)) {
6622
- // This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js
6623
- // wraps <mi> elements with <mpadded>s to work around a Firefox bug.
6951
+ // This is a \mathrm{…} or \mathit{…} group. It gets special treatment.
6624
6952
  const mi = mathGroup.children[0].children[0].children
6625
6953
  ? mathGroup.children[0].children[0]
6626
6954
  : mathGroup.children[0];
@@ -6630,7 +6958,14 @@ var temml = (function () {
6630
6958
  ? mathGroup.children[i].children[0].children[0].text
6631
6959
  : mathGroup.children[i].children[0].text;
6632
6960
  }
6633
- // Wrap in a <mpadded> to prevent the same Firefox bug.
6961
+ if (font === "mathit") {
6962
+ // Long <mi> elements are normally rendered in upright font.
6963
+ // To get italic, we need to convert each character to the corresponding italic character.
6964
+ mi.children[0].text = mi.children[0].text.split("")
6965
+ .map(c => variantChar(c, "italic")).join("");
6966
+ return mi
6967
+ }
6968
+ // Otherwise, font is "mathrm". Wrap in a <mpadded> to prevent a Firefox spacing bug.
6634
6969
  const mpadded = new MathNode("mpadded", [mi]);
6635
6970
  mpadded.setAttribute("lspace", "0");
6636
6971
  return mpadded
@@ -6746,22 +7081,37 @@ var temml = (function () {
6746
7081
  const stylArray = ["display", "text", "script", "scriptscript"];
6747
7082
  const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 };
6748
7083
 
7084
+ const adjustStyle = (functionSize, originalStyle) => {
7085
+ // Figure out what style this fraction should be in based on the
7086
+ // function used
7087
+ let style = originalStyle;
7088
+ if (functionSize === "display") { //\tfrac or \cfrac
7089
+ // Get display style as a default.
7090
+ // If incoming style is sub/sup, use style.text() to get correct size.
7091
+ const newSize = style.level >= StyleLevel.SCRIPT ? StyleLevel.TEXT : StyleLevel.DISPLAY;
7092
+ style = style.withLevel(newSize);
7093
+ } else if (functionSize === "text" &&
7094
+ style.level === StyleLevel.DISPLAY) {
7095
+ // We're in a \tfrac but incoming style is displaystyle, so:
7096
+ style = style.withLevel(StyleLevel.TEXT);
7097
+ } else if (functionSize === "auto") {
7098
+ style = style.incrementLevel();
7099
+ } else if (functionSize === "script") {
7100
+ style = style.withLevel(StyleLevel.SCRIPT);
7101
+ } else if (functionSize === "scriptscript") {
7102
+ style = style.withLevel(StyleLevel.SCRIPTSCRIPT);
7103
+ }
7104
+ return style;
7105
+ };
7106
+
6749
7107
  const mathmlBuilder$5 = (group, style) => {
6750
- // Track the scriptLevel of the numerator and denominator.
6751
- // We may need that info for \mathchoice or for adjusting em dimensions.
6752
- const childOptions = group.scriptLevel === "auto"
6753
- ? style.incrementLevel()
6754
- : group.scriptLevel === "display"
6755
- ? style.withLevel(StyleLevel.TEXT)
6756
- : group.scriptLevel === "text"
6757
- ? style.withLevel(StyleLevel.SCRIPT)
6758
- : style.withLevel(StyleLevel.SCRIPTSCRIPT);
7108
+ style = adjustStyle(group.scriptLevel, style);
6759
7109
 
6760
7110
  // Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
6761
7111
  // So we check for levels that Chromium shrinks too small.
6762
7112
  // If necessary, set an explicit fraction depth.
6763
- const numer = buildGroup$1(group.numer, childOptions);
6764
- const denom = buildGroup$1(group.denom, childOptions);
7113
+ const numer = buildGroup$1(group.numer, style);
7114
+ const denom = buildGroup$1(group.denom, style);
6765
7115
  if (style.level === 3) {
6766
7116
  numer.style.mathDepth = "2";
6767
7117
  numer.setAttribute("scriptlevel", "2");
@@ -6814,6 +7164,7 @@ var temml = (function () {
6814
7164
  defineFunction({
6815
7165
  type: "genfrac",
6816
7166
  names: [
7167
+ "\\cfrac",
6817
7168
  "\\dfrac",
6818
7169
  "\\frac",
6819
7170
  "\\tfrac",
@@ -6837,6 +7188,7 @@ var temml = (function () {
6837
7188
  let scriptLevel = "auto";
6838
7189
 
6839
7190
  switch (funcName) {
7191
+ case "\\cfrac":
6840
7192
  case "\\dfrac":
6841
7193
  case "\\frac":
6842
7194
  case "\\tfrac":
@@ -6863,56 +7215,26 @@ var temml = (function () {
6863
7215
  throw new Error("Unrecognized genfrac command");
6864
7216
  }
6865
7217
 
6866
- switch (funcName) {
6867
- case "\\dfrac":
6868
- case "\\dbinom":
6869
- scriptLevel = "display";
6870
- break;
6871
- case "\\tfrac":
6872
- case "\\tbinom":
6873
- scriptLevel = "text";
6874
- break;
6875
- }
6876
-
6877
- return {
6878
- type: "genfrac",
6879
- mode: parser.mode,
6880
- continued: false,
6881
- numer,
6882
- denom,
6883
- hasBarLine,
6884
- leftDelim,
6885
- rightDelim,
6886
- scriptLevel,
6887
- barSize: null
6888
- };
6889
- },
6890
- mathmlBuilder: mathmlBuilder$5
6891
- });
6892
-
6893
- defineFunction({
6894
- type: "genfrac",
6895
- names: ["\\cfrac"],
6896
- props: {
6897
- numArgs: 2
6898
- },
6899
- handler: ({ parser, funcName }, args) => {
6900
- const numer = args[0];
6901
- const denom = args[1];
7218
+ if (funcName === "\\cfrac" || funcName.startsWith("\\d")) {
7219
+ scriptLevel = "display";
7220
+ } else if (funcName.startsWith("\\t")) {
7221
+ scriptLevel = "text";
7222
+ }
6902
7223
 
6903
7224
  return {
6904
7225
  type: "genfrac",
6905
7226
  mode: parser.mode,
6906
- continued: true,
7227
+ continued: false,
6907
7228
  numer,
6908
7229
  denom,
6909
- hasBarLine: true,
6910
- leftDelim: null,
6911
- rightDelim: null,
6912
- scriptLevel: "display",
7230
+ hasBarLine,
7231
+ leftDelim,
7232
+ rightDelim,
7233
+ scriptLevel,
6913
7234
  barSize: null
6914
7235
  };
6915
- }
7236
+ },
7237
+ mathmlBuilder: mathmlBuilder$5
6916
7238
  });
6917
7239
 
6918
7240
  // Infix generalized fractions -- these are not rendered directly, but replaced
@@ -7743,8 +8065,16 @@ var temml = (function () {
7743
8065
  const atom = arg.type === "ordgroup" && arg.body.length && arg.body.length === 1
7744
8066
  ? arg.body[0]
7745
8067
  : arg;
7746
- if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) {
7747
- return "m" + atom.family;
8068
+ if (atom.type === "atom") {
8069
+ // BIN args are sometimes changed to OPEN, so check the original family.
8070
+ const family = arg.body.length > 0 && arg.body[0].text && symbols.math[arg.body[0].text]
8071
+ ? symbols.math[arg.body[0].text].group
8072
+ : atom.family;
8073
+ if (family === "bin" || family === "rel") {
8074
+ return "m" + family;
8075
+ } else {
8076
+ return "mord";
8077
+ }
7748
8078
  } else {
7749
8079
  return "mord";
7750
8080
  }
@@ -8315,6 +8645,14 @@ var temml = (function () {
8315
8645
  if ((node.type === "mrow" || node.type === "mpadded") && node.children.length === 1 &&
8316
8646
  node.children[0] instanceof MathNode) {
8317
8647
  node = node.children[0];
8648
+ } else if (node.type === "mrow" && node.children.length === 2 &&
8649
+ node.children[0] instanceof MathNode &&
8650
+ node.children[1] instanceof MathNode &&
8651
+ node.children[1].type === "mspace" && !node.children[1].attributes.width &&
8652
+ node.children[1].children.length === 0) {
8653
+ // This is a workaround for a Firefox bug that applies spacing to
8654
+ // an <mi> with mathvariant="normal".
8655
+ node = node.children[0];
8318
8656
  }
8319
8657
  switch (node.type) {
8320
8658
  case "mi":
@@ -8505,7 +8843,7 @@ var temml = (function () {
8505
8843
  const inner = buildExpression(ordargument(group.body), style);
8506
8844
  const phantom = new MathNode("mphantom", inner);
8507
8845
  const node = new MathNode("mpadded", [phantom]);
8508
- node.setAttribute("width", "0px");
8846
+ node.setAttribute("width", "0.1px");
8509
8847
  return node;
8510
8848
  }
8511
8849
  });
@@ -9322,232 +9660,6 @@ var temml = (function () {
9322
9660
  return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null
9323
9661
  };
9324
9662
 
9325
- // Chromium does not support the MathML `mathvariant` attribute.
9326
- // Instead, we replace ASCII characters with Unicode characters that
9327
- // are defined in the font as bold, italic, double-struck, etc.
9328
- // This module identifies those Unicode code points.
9329
-
9330
- // First, a few helpers.
9331
- const script = Object.freeze({
9332
- B: 0x20EA, // Offset from ASCII B to Unicode script B
9333
- E: 0x20EB,
9334
- F: 0x20EB,
9335
- H: 0x20C3,
9336
- I: 0x20C7,
9337
- L: 0x20C6,
9338
- M: 0x20E6,
9339
- R: 0x20C9,
9340
- e: 0x20CA,
9341
- g: 0x20A3,
9342
- o: 0x20C5
9343
- });
9344
-
9345
- const frak = Object.freeze({
9346
- C: 0x20EA,
9347
- H: 0x20C4,
9348
- I: 0x20C8,
9349
- R: 0x20CA,
9350
- Z: 0x20CE
9351
- });
9352
-
9353
- const bbb = Object.freeze({
9354
- C: 0x20BF, // blackboard bold
9355
- H: 0x20C5,
9356
- N: 0x20C7,
9357
- P: 0x20C9,
9358
- Q: 0x20C9,
9359
- R: 0x20CB,
9360
- Z: 0x20CA
9361
- });
9362
-
9363
- const bold = Object.freeze({
9364
- "\u03f5": 0x1D2E7, // lunate epsilon
9365
- "\u03d1": 0x1D30C, // vartheta
9366
- "\u03f0": 0x1D2EE, // varkappa
9367
- "\u03c6": 0x1D319, // varphi
9368
- "\u03f1": 0x1D2EF, // varrho
9369
- "\u03d6": 0x1D30B // varpi
9370
- });
9371
-
9372
- const boldItalic = Object.freeze({
9373
- "\u03f5": 0x1D35B, // lunate epsilon
9374
- "\u03d1": 0x1D380, // vartheta
9375
- "\u03f0": 0x1D362, // varkappa
9376
- "\u03c6": 0x1D38D, // varphi
9377
- "\u03f1": 0x1D363, // varrho
9378
- "\u03d6": 0x1D37F // varpi
9379
- });
9380
-
9381
- const boldsf = Object.freeze({
9382
- "\u03f5": 0x1D395, // lunate epsilon
9383
- "\u03d1": 0x1D3BA, // vartheta
9384
- "\u03f0": 0x1D39C, // varkappa
9385
- "\u03c6": 0x1D3C7, // varphi
9386
- "\u03f1": 0x1D39D, // varrho
9387
- "\u03d6": 0x1D3B9 // varpi
9388
- });
9389
-
9390
- const bisf = Object.freeze({
9391
- "\u03f5": 0x1D3CF, // lunate epsilon
9392
- "\u03d1": 0x1D3F4, // vartheta
9393
- "\u03f0": 0x1D3D6, // varkappa
9394
- "\u03c6": 0x1D401, // varphi
9395
- "\u03f1": 0x1D3D7, // varrho
9396
- "\u03d6": 0x1D3F3 // varpi
9397
- });
9398
-
9399
- // Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf
9400
- const offset = Object.freeze({
9401
- upperCaseLatin: { // A-Z
9402
- "normal": ch => { return 0 },
9403
- "bold": ch => { return 0x1D3BF },
9404
- "italic": ch => { return 0x1D3F3 },
9405
- "bold-italic": ch => { return 0x1D427 },
9406
- "script": ch => { return script[ch] || 0x1D45B },
9407
- "script-bold": ch => { return 0x1D48F },
9408
- "fraktur": ch => { return frak[ch] || 0x1D4C3 },
9409
- "fraktur-bold": ch => { return 0x1D52B },
9410
- "double-struck": ch => { return bbb[ch] || 0x1D4F7 },
9411
- "sans-serif": ch => { return 0x1D55F },
9412
- "sans-serif-bold": ch => { return 0x1D593 },
9413
- "sans-serif-italic": ch => { return 0x1D5C7 },
9414
- "sans-serif-bold-italic": ch => { return 0x1D63C },
9415
- "monospace": ch => { return 0x1D62F }
9416
- },
9417
- lowerCaseLatin: { // a-z
9418
- "normal": ch => { return 0 },
9419
- "bold": ch => { return 0x1D3B9 },
9420
- "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED },
9421
- "bold-italic": ch => { return 0x1D421 },
9422
- "script": ch => { return script[ch] || 0x1D455 },
9423
- "script-bold": ch => { return 0x1D489 },
9424
- "fraktur": ch => { return 0x1D4BD },
9425
- "fraktur-bold": ch => { return 0x1D525 },
9426
- "double-struck": ch => { return 0x1D4F1 },
9427
- "sans-serif": ch => { return 0x1D559 },
9428
- "sans-serif-bold": ch => { return 0x1D58D },
9429
- "sans-serif-italic": ch => { return 0x1D5C1 },
9430
- "sans-serif-bold-italic": ch => { return 0x1D5F5 },
9431
- "monospace": ch => { return 0x1D629 }
9432
- },
9433
- upperCaseGreek: { // A-Ω
9434
- "normal": ch => { return 0 },
9435
- "bold": ch => { return 0x1D317 },
9436
- "italic": ch => { return 0x1D351 },
9437
- // \boldsymbol actually returns upright bold for upperCaseGreek
9438
- "bold-italic": ch => { return 0x1D317 },
9439
- "script": ch => { return 0 },
9440
- "script-bold": ch => { return 0 },
9441
- "fraktur": ch => { return 0 },
9442
- "fraktur-bold": ch => { return 0 },
9443
- "double-struck": ch => { return 0 },
9444
- // Unicode has no code points for regular-weight san-serif Greek. Use bold.
9445
- "sans-serif": ch => { return 0x1D3C5 },
9446
- "sans-serif-bold": ch => { return 0x1D3C5 },
9447
- "sans-serif-italic": ch => { return 0 },
9448
- "sans-serif-bold-italic": ch => { return 0x1D3FF },
9449
- "monospace": ch => { return 0 }
9450
- },
9451
- lowerCaseGreek: { // α-ω
9452
- "normal": ch => { return 0 },
9453
- "bold": ch => { return 0x1D311 },
9454
- "italic": ch => { return 0x1D34B },
9455
- "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 },
9456
- "script": ch => { return 0 },
9457
- "script-bold": ch => { return 0 },
9458
- "fraktur": ch => { return 0 },
9459
- "fraktur-bold": ch => { return 0 },
9460
- "double-struck": ch => { return 0 },
9461
- // Unicode has no code points for regular-weight san-serif Greek. Use bold.
9462
- "sans-serif": ch => { return 0x1D3BF },
9463
- "sans-serif-bold": ch => { return 0x1D3BF },
9464
- "sans-serif-italic": ch => { return 0 },
9465
- "sans-serif-bold-italic": ch => { return 0x1D3F9 },
9466
- "monospace": ch => { return 0 }
9467
- },
9468
- varGreek: { // \varGamma, etc
9469
- "normal": ch => { return 0 },
9470
- "bold": ch => { return bold[ch] || -51 },
9471
- "italic": ch => { return 0 },
9472
- "bold-italic": ch => { return boldItalic[ch] || 0x3A },
9473
- "script": ch => { return 0 },
9474
- "script-bold": ch => { return 0 },
9475
- "fraktur": ch => { return 0 },
9476
- "fraktur-bold": ch => { return 0 },
9477
- "double-struck": ch => { return 0 },
9478
- "sans-serif": ch => { return boldsf[ch] || 0x74 },
9479
- "sans-serif-bold": ch => { return boldsf[ch] || 0x74 },
9480
- "sans-serif-italic": ch => { return 0 },
9481
- "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE },
9482
- "monospace": ch => { return 0 }
9483
- },
9484
- numeral: { // 0-9
9485
- "normal": ch => { return 0 },
9486
- "bold": ch => { return 0x1D79E },
9487
- "italic": ch => { return 0 },
9488
- "bold-italic": ch => { return 0 },
9489
- "script": ch => { return 0 },
9490
- "script-bold": ch => { return 0 },
9491
- "fraktur": ch => { return 0 },
9492
- "fraktur-bold": ch => { return 0 },
9493
- "double-struck": ch => { return 0x1D7A8 },
9494
- "sans-serif": ch => { return 0x1D7B2 },
9495
- "sans-serif-bold": ch => { return 0x1D7BC },
9496
- "sans-serif-italic": ch => { return 0 },
9497
- "sans-serif-bold-italic": ch => { return 0 },
9498
- "monospace": ch => { return 0x1D7C6 }
9499
- }
9500
- });
9501
-
9502
- const variantChar = (ch, variant) => {
9503
- const codePoint = ch.codePointAt(0);
9504
- const block = 0x40 < codePoint && codePoint < 0x5b
9505
- ? "upperCaseLatin"
9506
- : 0x60 < codePoint && codePoint < 0x7b
9507
- ? "lowerCaseLatin"
9508
- : (0x390 < codePoint && codePoint < 0x3AA)
9509
- ? "upperCaseGreek"
9510
- : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5"
9511
- ? "lowerCaseGreek"
9512
- : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch]
9513
- ? "varGreek"
9514
- : (0x2F < codePoint && codePoint < 0x3A)
9515
- ? "numeral"
9516
- : "other";
9517
- return block === "other"
9518
- ? ch
9519
- : String.fromCodePoint(codePoint + offset[block][variant](ch))
9520
- };
9521
-
9522
- const smallCaps = Object.freeze({
9523
- a: "ᴀ",
9524
- b: "ʙ",
9525
- c: "ᴄ",
9526
- d: "ᴅ",
9527
- e: "ᴇ",
9528
- f: "ꜰ",
9529
- g: "ɢ",
9530
- h: "ʜ",
9531
- i: "ɪ",
9532
- j: "ᴊ",
9533
- k: "ᴋ",
9534
- l: "ʟ",
9535
- m: "ᴍ",
9536
- n: "ɴ",
9537
- o: "ᴏ",
9538
- p: "ᴘ",
9539
- q: "ǫ",
9540
- r: "ʀ",
9541
- s: "s",
9542
- t: "ᴛ",
9543
- u: "ᴜ",
9544
- v: "ᴠ",
9545
- w: "ᴡ",
9546
- x: "x",
9547
- y: "ʏ",
9548
- z: "ᴢ"
9549
- });
9550
-
9551
9663
  // "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
9552
9664
  // src/symbols.js.
9553
9665
 
@@ -9585,8 +9697,8 @@ var temml = (function () {
9585
9697
  node.setAttribute("mathvariant", "normal");
9586
9698
  if (text.text.length === 1) {
9587
9699
  // A Firefox bug will apply spacing here, but there should be none. Fix it.
9588
- node = new MathNode("mpadded", [node]);
9589
- node.setAttribute("lspace", "0");
9700
+ const mspace = new MathNode("mspace", []);
9701
+ node = new MathNode("mrow", [node, mspace]);
9590
9702
  }
9591
9703
  }
9592
9704
  return node
@@ -10167,7 +10279,7 @@ var temml = (function () {
10167
10279
  this.pushToken(new Token("EOF", end.loc));
10168
10280
 
10169
10281
  this.pushTokens(tokens);
10170
- return start.range(end, "");
10282
+ return new Token("", SourceLocation.range(start, end));
10171
10283
  }
10172
10284
 
10173
10285
  /**
@@ -11123,7 +11235,7 @@ var temml = (function () {
11123
11235
  * Parses an "expression", which is a list of atoms.
11124
11236
  *
11125
11237
  * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
11126
- * happens when functions have higher precedence han infix
11238
+ * happens when functions have higher precedence than infix
11127
11239
  * nodes in implicit parses.
11128
11240
  *
11129
11241
  * `breakOnTokenText`: The text of the token that the expression should end
@@ -11731,7 +11843,7 @@ var temml = (function () {
11731
11843
  ) {
11732
11844
  const firstToken = this.fetch();
11733
11845
  const text = firstToken.text;
11734
-
11846
+ if (name === "argument to '\\left'") { return this.parseSymbol() }
11735
11847
  let result;
11736
11848
  // Try to parse an open brace or \begingroup
11737
11849
  if (text === "{" || text === "\\begingroup" || text === "\\toggle") {
@@ -11878,7 +11990,8 @@ var temml = (function () {
11878
11990
  let symbol;
11879
11991
  if (symbols[this.mode][text]) {
11880
11992
  let group = symbols[this.mode][text].group;
11881
- if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) {
11993
+ if (group === "bin" &&
11994
+ (binLeftCancellers.includes(this.prevAtomType) || this.prevAtomType === "")) {
11882
11995
  // Change from a binary operator to a unary (prefix) operator
11883
11996
  group = "open";
11884
11997
  }
@@ -11974,11 +12087,27 @@ var temml = (function () {
11974
12087
  if (!(typeof toParse === "string" || toParse instanceof String)) {
11975
12088
  throw new TypeError("Temml can only parse string typed expression")
11976
12089
  }
11977
- const parser = new Parser(toParse, settings);
11978
- // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
11979
- delete parser.gullet.macros.current["\\df@tag"];
12090
+ let tree;
12091
+ let parser;
12092
+ try {
12093
+ parser = new Parser(toParse, settings);
12094
+ // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
12095
+ delete parser.gullet.macros.current["\\df@tag"];
11980
12096
 
11981
- let tree = parser.parse();
12097
+ tree = parser.parse();
12098
+ } catch (error) {
12099
+ if (error.toString() === "ParseError: Unmatched delimiter") {
12100
+ // Abandon the attempt to wrap delimiter pairs in an <mrow>.
12101
+ // Try again, and put each delimiter into an <mo> element.
12102
+ settings.wrapDelimiterPairs = false;
12103
+ parser = new Parser(toParse, settings);
12104
+ // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
12105
+ delete parser.gullet.macros.current["\\df@tag"];
12106
+ tree = parser.parse();
12107
+ } else {
12108
+ throw error;
12109
+ }
12110
+ }
11982
12111
 
11983
12112
  // LaTeX ignores a \tag placed outside an AMS environment.
11984
12113
  if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) {
@@ -12155,7 +12284,7 @@ var temml = (function () {
12155
12284
  * https://mit-license.org/
12156
12285
  */
12157
12286
 
12158
- const version = "0.13.01";
12287
+ const version = "0.13.3";
12159
12288
 
12160
12289
  function postProcess(block) {
12161
12290
  const labelMap = {};