temml 0.10.19 → 0.10.20

Sign up to get free protection for your applications and to get access to all the features.
@@ -47,6 +47,39 @@ mo.tml-prime {
47
47
  font-feature-settings: 'salt';
48
48
  }
49
49
 
50
+ mrow.tml-cancel {
51
+ background: linear-gradient(to top left,
52
+ rgba(0,0,0,0) 0%,
53
+ rgba(0,0,0,0) calc(50% - 0.06em),
54
+ rgba(0,0,0,1) 50%,
55
+ rgba(0,0,0,0) calc(50% + 0.06em),
56
+ rgba(0,0,0,0) 100%);
57
+ }
58
+
59
+ mrow.tml-bcancel {
60
+ background: linear-gradient(to top right,
61
+ rgba(0,0,0,0) 0%,
62
+ rgba(0,0,0,0) calc(50% - 0.06em),
63
+ rgba(0,0,0,1) 50%,
64
+ rgba(0,0,0,0) calc(50% + 0.06em),
65
+ rgba(0,0,0,0) 100%);
66
+ }
67
+
68
+ mrow.tml-xcancel {
69
+ background: linear-gradient(to top left,
70
+ rgba(0,0,0,0) 0%,
71
+ rgba(0,0,0,0) calc(50% - 0.06em),
72
+ rgba(0,0,0,1) 50%,
73
+ rgba(0,0,0,0) calc(50% + 0.06em),
74
+ rgba(0,0,0,0) 100%),
75
+ linear-gradient(to top right,
76
+ rgba(0,0,0,0) 0%,
77
+ rgba(0,0,0,0) calc(50% - 0.06em),
78
+ rgba(0,0,0,1) 50%,
79
+ rgba(0,0,0,0) calc(50% + 0.06em),
80
+ rgba(0,0,0,0) 100%)
81
+ }
82
+
50
83
  /* Prevent f' from overlapping in Chromium */
51
84
  mo.prime-pad {
52
85
  padding-left: 0.08em;
@@ -57,6 +57,39 @@ mo.tml-prime {
57
57
  font-family: Temml;
58
58
  }
59
59
 
60
+ mrow.tml-cancel {
61
+ background: linear-gradient(to top left,
62
+ rgba(0,0,0,0) 0%,
63
+ rgba(0,0,0,0) calc(50% - 0.06em),
64
+ rgba(0,0,0,1) 50%,
65
+ rgba(0,0,0,0) calc(50% + 0.06em),
66
+ rgba(0,0,0,0) 100%);
67
+ }
68
+
69
+ mrow.tml-bcancel {
70
+ background: linear-gradient(to top right,
71
+ rgba(0,0,0,0) 0%,
72
+ rgba(0,0,0,0) calc(50% - 0.06em),
73
+ rgba(0,0,0,1) 50%,
74
+ rgba(0,0,0,0) calc(50% + 0.06em),
75
+ rgba(0,0,0,0) 100%);
76
+ }
77
+
78
+ mrow.tml-xcancel {
79
+ background: linear-gradient(to top left,
80
+ rgba(0,0,0,0) 0%,
81
+ rgba(0,0,0,0) calc(50% - 0.06em),
82
+ rgba(0,0,0,1) 50%,
83
+ rgba(0,0,0,0) calc(50% + 0.06em),
84
+ rgba(0,0,0,0) 100%),
85
+ linear-gradient(to top right,
86
+ rgba(0,0,0,0) 0%,
87
+ rgba(0,0,0,0) calc(50% - 0.06em),
88
+ rgba(0,0,0,1) 50%,
89
+ rgba(0,0,0,0) calc(50% + 0.06em),
90
+ rgba(0,0,0,0) 100%)
91
+ }
92
+
60
93
  /* Prevent f' from overlapping in Chromium */
61
94
  mo.prime-pad {
62
95
  padding-left: 0.08em;
@@ -54,6 +54,39 @@ mo.tml-prime {
54
54
  font-feature-settings: 'ssty';
55
55
  }
56
56
 
57
+ mrow.tml-cancel {
58
+ background: linear-gradient(to top left,
59
+ rgba(0,0,0,0) 0%,
60
+ rgba(0,0,0,0) calc(50% - 0.06em),
61
+ rgba(0,0,0,1) 50%,
62
+ rgba(0,0,0,0) calc(50% + 0.06em),
63
+ rgba(0,0,0,0) 100%);
64
+ }
65
+
66
+ mrow.tml-bcancel {
67
+ background: linear-gradient(to top right,
68
+ rgba(0,0,0,0) 0%,
69
+ rgba(0,0,0,0) calc(50% - 0.06em),
70
+ rgba(0,0,0,1) 50%,
71
+ rgba(0,0,0,0) calc(50% + 0.06em),
72
+ rgba(0,0,0,0) 100%);
73
+ }
74
+
75
+ mrow.tml-xcancel {
76
+ background: linear-gradient(to top left,
77
+ rgba(0,0,0,0) 0%,
78
+ rgba(0,0,0,0) calc(50% - 0.06em),
79
+ rgba(0,0,0,1) 50%,
80
+ rgba(0,0,0,0) calc(50% + 0.06em),
81
+ rgba(0,0,0,0) 100%),
82
+ linear-gradient(to top right,
83
+ rgba(0,0,0,0) 0%,
84
+ rgba(0,0,0,0) calc(50% - 0.06em),
85
+ rgba(0,0,0,1) 50%,
86
+ rgba(0,0,0,0) calc(50% + 0.06em),
87
+ rgba(0,0,0,0) 100%)
88
+ }
89
+
57
90
  /* Prevent f' from overlapping in Chromium */
58
91
  mo.prime-pad {
59
92
  padding-left: 0.08em;
@@ -40,6 +40,39 @@ mo.tml-prime {
40
40
  font-family: Temml;
41
41
  }
42
42
 
43
+ mrow.tml-cancel {
44
+ background: linear-gradient(to top left,
45
+ rgba(0,0,0,0) 0%,
46
+ rgba(0,0,0,0) calc(50% - 0.06em),
47
+ rgba(0,0,0,1) 50%,
48
+ rgba(0,0,0,0) calc(50% + 0.06em),
49
+ rgba(0,0,0,0) 100%);
50
+ }
51
+
52
+ mrow.tml-bcancel {
53
+ background: linear-gradient(to top right,
54
+ rgba(0,0,0,0) 0%,
55
+ rgba(0,0,0,0) calc(50% - 0.06em),
56
+ rgba(0,0,0,1) 50%,
57
+ rgba(0,0,0,0) calc(50% + 0.06em),
58
+ rgba(0,0,0,0) 100%);
59
+ }
60
+
61
+ mrow.tml-xcancel {
62
+ background: linear-gradient(to top left,
63
+ rgba(0,0,0,0) 0%,
64
+ rgba(0,0,0,0) calc(50% - 0.06em),
65
+ rgba(0,0,0,1) 50%,
66
+ rgba(0,0,0,0) calc(50% + 0.06em),
67
+ rgba(0,0,0,0) 100%),
68
+ linear-gradient(to top right,
69
+ rgba(0,0,0,0) 0%,
70
+ rgba(0,0,0,0) calc(50% - 0.06em),
71
+ rgba(0,0,0,1) 50%,
72
+ rgba(0,0,0,0) calc(50% + 0.06em),
73
+ rgba(0,0,0,0) 100%)
74
+ }
75
+
43
76
  /* Prevent f' from overlapping in Chromium */
44
77
  mo.prime-pad {
45
78
  padding-left: 0.08em;
@@ -48,6 +48,39 @@ mo.tml-prime {
48
48
  font-feature-settings: 'ss04';
49
49
  }
50
50
 
51
+ mrow.tml-cancel {
52
+ background: linear-gradient(to top left,
53
+ rgba(0,0,0,0) 0%,
54
+ rgba(0,0,0,0) calc(50% - 0.06em),
55
+ rgba(0,0,0,1) 50%,
56
+ rgba(0,0,0,0) calc(50% + 0.06em),
57
+ rgba(0,0,0,0) 100%);
58
+ }
59
+
60
+ mrow.tml-bcancel {
61
+ background: linear-gradient(to top right,
62
+ rgba(0,0,0,0) 0%,
63
+ rgba(0,0,0,0) calc(50% - 0.06em),
64
+ rgba(0,0,0,1) 50%,
65
+ rgba(0,0,0,0) calc(50% + 0.06em),
66
+ rgba(0,0,0,0) 100%);
67
+ }
68
+
69
+ mrow.tml-xcancel {
70
+ background: linear-gradient(to top left,
71
+ rgba(0,0,0,0) 0%,
72
+ rgba(0,0,0,0) calc(50% - 0.06em),
73
+ rgba(0,0,0,1) 50%,
74
+ rgba(0,0,0,0) calc(50% + 0.06em),
75
+ rgba(0,0,0,0) 100%),
76
+ linear-gradient(to top right,
77
+ rgba(0,0,0,0) 0%,
78
+ rgba(0,0,0,0) calc(50% - 0.06em),
79
+ rgba(0,0,0,1) 50%,
80
+ rgba(0,0,0,0) calc(50% + 0.06em),
81
+ rgba(0,0,0,0) 100%)
82
+ }
83
+
51
84
  /* Prevent f' from overlapping in Chromium */
52
85
  mo.prime-pad {
53
86
  padding-left: 0.08em;
package/dist/temml.cjs CHANGED
@@ -2072,20 +2072,22 @@ const consolidateNumbers = expression => {
2072
2072
  * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
2073
2073
  * unless the array has length 1. Always returns a single node.
2074
2074
  */
2075
- const makeRow = function(body) {
2075
+ const makeRow = function(body, semisimple = false) {
2076
2076
  if (body.length === 1 && !(body[0] instanceof DocumentFragment)) {
2077
2077
  return body[0];
2078
- } else {
2078
+ } else if (!semisimple) {
2079
2079
  // Suppress spacing on <mo> nodes at both ends of the row.
2080
2080
  if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) {
2081
2081
  body[0].attributes.lspace = "0em";
2082
+ body[0].attributes.rspace = "0em";
2082
2083
  }
2083
2084
  const end = body.length - 1;
2084
2085
  if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) {
2086
+ body[end].attributes.lspace = "0em";
2085
2087
  body[end].attributes.rspace = "0em";
2086
2088
  }
2087
- return new mathMLTree.MathNode("mrow", body);
2088
2089
  }
2090
+ return new mathMLTree.MathNode("mrow", body);
2089
2091
  };
2090
2092
 
2091
2093
  const isRel = item => {
@@ -2099,10 +2101,10 @@ const isRel = item => {
2099
2101
  * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}.
2100
2102
  * (2) Suppress spacing between two adjacent relations.
2101
2103
  */
2102
- const buildExpression = function(expression, style, isOrdgroup) {
2103
- if (expression.length === 1) {
2104
+ const buildExpression = function(expression, style, semisimple = false) {
2105
+ if (!semisimple && expression.length === 1) {
2104
2106
  const group = buildGroup$1(expression[0], style);
2105
- if (isOrdgroup && group instanceof MathNode && group.type === "mo") {
2107
+ if (group instanceof MathNode && group.type === "mo") {
2106
2108
  // When TeX writers want to suppress spacing on an operator,
2107
2109
  // they often put the operator by itself inside braces.
2108
2110
  group.setAttribute("lspace", "0em");
@@ -2132,8 +2134,8 @@ const buildExpression = function(expression, style, isOrdgroup) {
2132
2134
  * Equivalent to buildExpression, but wraps the elements in an <mrow>
2133
2135
  * if there's more than one. Returns a single node instead of an array.
2134
2136
  */
2135
- const buildExpressionRow = function(expression, style, isOrdgroup) {
2136
- return makeRow(buildExpression(expression, style, isOrdgroup));
2137
+ const buildExpressionRow = function(expression, style, semisimple = false) {
2138
+ return makeRow(buildExpression(expression, style, semisimple), semisimple);
2137
2139
  };
2138
2140
 
2139
2141
  /**
@@ -2818,7 +2820,8 @@ function cdArrow(arrowChar, labels, parser) {
2818
2820
  const arrowGroup = {
2819
2821
  type: "ordgroup",
2820
2822
  mode: "math",
2821
- body: [leftLabel, sizedArrow, rightLabel]
2823
+ body: [leftLabel, sizedArrow, rightLabel],
2824
+ semisimple: true
2822
2825
  };
2823
2826
  return parser.callFunction("\\\\cdparent", [arrowGroup], []);
2824
2827
  }
@@ -3940,20 +3943,12 @@ const mathmlBuilder$8 = (group, style) => {
3940
3943
  node.style.borderBottom = "0.065em solid";
3941
3944
  break
3942
3945
  case "\\cancel":
3943
- node.style.background = `linear-gradient(to top left,
3944
- rgba(0,0,0,0) 0%,
3945
- rgba(0,0,0,0) calc(50% - 0.06em),
3946
- rgba(0,0,0,1) 50%,
3947
- rgba(0,0,0,0) calc(50% + 0.06em),
3948
- rgba(0,0,0,0) 100%);`;
3946
+ // We can't use an inline background-gradient. It does not work client-side.
3947
+ // So set a class and put the rule in the external CSS file.
3948
+ node.classes.push("tml-cancel");
3949
3949
  break
3950
3950
  case "\\bcancel":
3951
- node.style.background = `linear-gradient(to top right,
3952
- rgba(0,0,0,0) 0%,
3953
- rgba(0,0,0,0) calc(50% - 0.06em),
3954
- rgba(0,0,0,1) 50%,
3955
- rgba(0,0,0,0) calc(50% + 0.06em),
3956
- rgba(0,0,0,0) 100%);`;
3951
+ node.classes.push("tml-bcancel");
3957
3952
  break
3958
3953
  /*
3959
3954
  case "\\longdiv":
@@ -4000,18 +3995,7 @@ rgba(0,0,0,0) 100%);`;
4000
3995
  break
4001
3996
  }
4002
3997
  case "\\xcancel":
4003
- node.style.background = `linear-gradient(to top left,
4004
- rgba(0,0,0,0) 0%,
4005
- rgba(0,0,0,0) calc(50% - 0.06em),
4006
- rgba(0,0,0,1) 50%,
4007
- rgba(0,0,0,0) calc(50% + 0.06em),
4008
- rgba(0,0,0,0) 100%),
4009
- linear-gradient(to top right,
4010
- rgba(0,0,0,0) 0%,
4011
- rgba(0,0,0,0) calc(50% - 0.06em),
4012
- rgba(0,0,0,1) 50%,
4013
- rgba(0,0,0,0) calc(50% + 0.06em),
4014
- rgba(0,0,0,0) 100%);`;
3998
+ node.classes.push("tml-xcancel");
4015
3999
  break
4016
4000
  }
4017
4001
  if (group.backgroundColor) {
@@ -4209,7 +4193,7 @@ const getTag = (group, style, rowNum) => {
4209
4193
  if (tagContents) {
4210
4194
  // The author has written a \tag or a \notag in this row.
4211
4195
  if (tagContents.body) {
4212
- tag = buildExpressionRow(tagContents.body, style);
4196
+ tag = buildExpressionRow(tagContents.body, style, true);
4213
4197
  tag.classes = ["tml-tag"];
4214
4198
  } else {
4215
4199
  // \notag. Return an empty span.
@@ -4256,7 +4240,9 @@ function parseArray(
4256
4240
  parser.gullet.macros.set("\\cr", "\\\\\\relax");
4257
4241
  }
4258
4242
  if (addEqnNum) {
4259
- parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}");
4243
+ parser.gullet.macros.set("\\tag", "\\@ifstar\\envtag@literal\\envtag@paren");
4244
+ parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}");
4245
+ parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}");
4260
4246
  parser.gullet.macros.set("\\notag", "\\env@notag");
4261
4247
  parser.gullet.macros.set("\\nonumber", "\\env@notag");
4262
4248
  }
@@ -4297,7 +4283,8 @@ function parseArray(
4297
4283
  cell = {
4298
4284
  type: "ordgroup",
4299
4285
  mode: parser.mode,
4300
- body: cell
4286
+ body: cell,
4287
+ semisimple: true
4301
4288
  };
4302
4289
  row.push(cell);
4303
4290
  const next = parser.fetch().text;
@@ -5130,7 +5117,7 @@ const mathmlBuilder$6 = (group, style) => {
5130
5117
  const mathGroup = buildGroup$1(group.body, newStyle);
5131
5118
 
5132
5119
  if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{}
5133
- if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) {
5120
+ if (font === "boldsymbol" && ["mo", "mpadded", "mrow"].includes(mathGroup.type)) {
5134
5121
  mathGroup.style.fontWeight = "bold";
5135
5122
  return mathGroup
5136
5123
  }
@@ -6487,10 +6474,10 @@ defineFunction({
6487
6474
  },
6488
6475
  mathmlBuilder(group, style) {
6489
6476
  if (group.isCharacterBox) {
6490
- const inner = buildExpression(group.body, style);
6477
+ const inner = buildExpression(group.body, style, true);
6491
6478
  return inner[0]
6492
6479
  } else {
6493
- return buildExpressionRow(group.body, style, true)
6480
+ return buildExpressionRow(group.body, style)
6494
6481
  }
6495
6482
  }
6496
6483
  });
@@ -6510,6 +6497,13 @@ const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
6510
6497
  // NOTE: Unlike most `builders`s, this one handles not only "op", but also
6511
6498
  // "supsub" since some of them (like \int) can affect super/subscripting.
6512
6499
 
6500
+ const setSpacing = node => {
6501
+ // The user wrote a \mathop{…} function. Change spacing from default to OP spacing.
6502
+ // The most likely spacing for an OP is a thin space per TeXbook p170.
6503
+ node.attributes.lspace = "0.1667em";
6504
+ node.attributes.rspace = "0.1667em";
6505
+ };
6506
+
6513
6507
  const mathmlBuilder$2 = (group, style) => {
6514
6508
  let node;
6515
6509
 
@@ -6521,9 +6515,11 @@ const mathmlBuilder$2 = (group, style) => {
6521
6515
  } else {
6522
6516
  node.setAttribute("movablelimits", "false");
6523
6517
  }
6518
+ if (group.fromMathOp) { setSpacing(node); }
6524
6519
  } else if (group.body) {
6525
6520
  // This is an operator with children. Add them.
6526
6521
  node = new MathNode("mo", buildExpression(group.body, style));
6522
+ if (group.fromMathOp) { setSpacing(node); }
6527
6523
  } else {
6528
6524
  // This is a text operator. Add all of the characters from the operator's name.
6529
6525
  node = new MathNode("mi", [new TextNode(group.name.slice(1))]);
@@ -6643,6 +6639,7 @@ defineFunction({
6643
6639
  limits: true,
6644
6640
  parentIsSupSub: false,
6645
6641
  symbol: isSymbol,
6642
+ fromMathOp: true,
6646
6643
  stack: false,
6647
6644
  name: isSymbol ? arr[0].text : null,
6648
6645
  body: isSymbol ? null : ordargument(body)
@@ -6976,7 +6973,7 @@ defineMacro("\\operatorname",
6976
6973
  defineFunctionBuilders({
6977
6974
  type: "ordgroup",
6978
6975
  mathmlBuilder(group, style) {
6979
- return buildExpressionRow(group.body, style, true);
6976
+ return buildExpressionRow(group.body, style, group.semisimple);
6980
6977
  }
6981
6978
  });
6982
6979
 
@@ -12005,6 +12002,8 @@ var unicodeSymbols = {
12005
12002
 
12006
12003
  /* eslint no-constant-condition:0 */
12007
12004
 
12005
+ const binLeftCancellers = ["bin", "op", "open", "punct", "rel"];
12006
+
12008
12007
  /**
12009
12008
  * This file contains the parser used to parse out a TeX expression from the
12010
12009
  * input. Since TeX isn't context-free, standard parsers don't work particularly
@@ -12774,8 +12773,7 @@ class Parser {
12774
12773
  body: expression,
12775
12774
  // A group formed by \begingroup...\endgroup is a semi-simple group
12776
12775
  // which doesn't affect spacing in math mode, i.e., is transparent.
12777
- // https://tex.stackexchange.com/questions/1930/when-should-one-
12778
- // use-begingroup-instead-of-bgroup
12776
+ // https://tex.stackexchange.com/questions/1930/
12779
12777
  semisimple: text === "\\begingroup" || undefined
12780
12778
  };
12781
12779
  } else {
@@ -12889,7 +12887,11 @@ class Parser {
12889
12887
  // Recognize base symbol
12890
12888
  let symbol;
12891
12889
  if (symbols[this.mode][text]) {
12892
- const group = symbols[this.mode][text].group;
12890
+ let group = symbols[this.mode][text].group;
12891
+ if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) {
12892
+ // Change from a binary operator to a unary (prefix) operator
12893
+ group = "open";
12894
+ }
12893
12895
  const loc = SourceLocation.range(nucleus);
12894
12896
  let s;
12895
12897
  if (Object.prototype.hasOwnProperty.call(ATOMS, group )) {
@@ -13159,7 +13161,7 @@ class Style {
13159
13161
  * https://mit-license.org/
13160
13162
  */
13161
13163
 
13162
- const version = "0.10.19";
13164
+ const version = "0.10.20";
13163
13165
 
13164
13166
  function postProcess(block) {
13165
13167
  const labelMap = {};
package/dist/temml.js CHANGED
@@ -2073,20 +2073,22 @@ var temml = (function () {
2073
2073
  * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
2074
2074
  * unless the array has length 1. Always returns a single node.
2075
2075
  */
2076
- const makeRow = function(body) {
2076
+ const makeRow = function(body, semisimple = false) {
2077
2077
  if (body.length === 1 && !(body[0] instanceof DocumentFragment)) {
2078
2078
  return body[0];
2079
- } else {
2079
+ } else if (!semisimple) {
2080
2080
  // Suppress spacing on <mo> nodes at both ends of the row.
2081
2081
  if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) {
2082
2082
  body[0].attributes.lspace = "0em";
2083
+ body[0].attributes.rspace = "0em";
2083
2084
  }
2084
2085
  const end = body.length - 1;
2085
2086
  if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) {
2087
+ body[end].attributes.lspace = "0em";
2086
2088
  body[end].attributes.rspace = "0em";
2087
2089
  }
2088
- return new mathMLTree.MathNode("mrow", body);
2089
2090
  }
2091
+ return new mathMLTree.MathNode("mrow", body);
2090
2092
  };
2091
2093
 
2092
2094
  const isRel = item => {
@@ -2100,10 +2102,10 @@ var temml = (function () {
2100
2102
  * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}.
2101
2103
  * (2) Suppress spacing between two adjacent relations.
2102
2104
  */
2103
- const buildExpression = function(expression, style, isOrdgroup) {
2104
- if (expression.length === 1) {
2105
+ const buildExpression = function(expression, style, semisimple = false) {
2106
+ if (!semisimple && expression.length === 1) {
2105
2107
  const group = buildGroup$1(expression[0], style);
2106
- if (isOrdgroup && group instanceof MathNode && group.type === "mo") {
2108
+ if (group instanceof MathNode && group.type === "mo") {
2107
2109
  // When TeX writers want to suppress spacing on an operator,
2108
2110
  // they often put the operator by itself inside braces.
2109
2111
  group.setAttribute("lspace", "0em");
@@ -2133,8 +2135,8 @@ var temml = (function () {
2133
2135
  * Equivalent to buildExpression, but wraps the elements in an <mrow>
2134
2136
  * if there's more than one. Returns a single node instead of an array.
2135
2137
  */
2136
- const buildExpressionRow = function(expression, style, isOrdgroup) {
2137
- return makeRow(buildExpression(expression, style, isOrdgroup));
2138
+ const buildExpressionRow = function(expression, style, semisimple = false) {
2139
+ return makeRow(buildExpression(expression, style, semisimple), semisimple);
2138
2140
  };
2139
2141
 
2140
2142
  /**
@@ -2819,7 +2821,8 @@ var temml = (function () {
2819
2821
  const arrowGroup = {
2820
2822
  type: "ordgroup",
2821
2823
  mode: "math",
2822
- body: [leftLabel, sizedArrow, rightLabel]
2824
+ body: [leftLabel, sizedArrow, rightLabel],
2825
+ semisimple: true
2823
2826
  };
2824
2827
  return parser.callFunction("\\\\cdparent", [arrowGroup], []);
2825
2828
  }
@@ -3941,20 +3944,12 @@ var temml = (function () {
3941
3944
  node.style.borderBottom = "0.065em solid";
3942
3945
  break
3943
3946
  case "\\cancel":
3944
- node.style.background = `linear-gradient(to top left,
3945
- rgba(0,0,0,0) 0%,
3946
- rgba(0,0,0,0) calc(50% - 0.06em),
3947
- rgba(0,0,0,1) 50%,
3948
- rgba(0,0,0,0) calc(50% + 0.06em),
3949
- rgba(0,0,0,0) 100%);`;
3947
+ // We can't use an inline background-gradient. It does not work client-side.
3948
+ // So set a class and put the rule in the external CSS file.
3949
+ node.classes.push("tml-cancel");
3950
3950
  break
3951
3951
  case "\\bcancel":
3952
- node.style.background = `linear-gradient(to top right,
3953
- rgba(0,0,0,0) 0%,
3954
- rgba(0,0,0,0) calc(50% - 0.06em),
3955
- rgba(0,0,0,1) 50%,
3956
- rgba(0,0,0,0) calc(50% + 0.06em),
3957
- rgba(0,0,0,0) 100%);`;
3952
+ node.classes.push("tml-bcancel");
3958
3953
  break
3959
3954
  /*
3960
3955
  case "\\longdiv":
@@ -4001,18 +3996,7 @@ rgba(0,0,0,0) 100%);`;
4001
3996
  break
4002
3997
  }
4003
3998
  case "\\xcancel":
4004
- node.style.background = `linear-gradient(to top left,
4005
- rgba(0,0,0,0) 0%,
4006
- rgba(0,0,0,0) calc(50% - 0.06em),
4007
- rgba(0,0,0,1) 50%,
4008
- rgba(0,0,0,0) calc(50% + 0.06em),
4009
- rgba(0,0,0,0) 100%),
4010
- linear-gradient(to top right,
4011
- rgba(0,0,0,0) 0%,
4012
- rgba(0,0,0,0) calc(50% - 0.06em),
4013
- rgba(0,0,0,1) 50%,
4014
- rgba(0,0,0,0) calc(50% + 0.06em),
4015
- rgba(0,0,0,0) 100%);`;
3999
+ node.classes.push("tml-xcancel");
4016
4000
  break
4017
4001
  }
4018
4002
  if (group.backgroundColor) {
@@ -4210,7 +4194,7 @@ rgba(0,0,0,0) 100%);`;
4210
4194
  if (tagContents) {
4211
4195
  // The author has written a \tag or a \notag in this row.
4212
4196
  if (tagContents.body) {
4213
- tag = buildExpressionRow(tagContents.body, style);
4197
+ tag = buildExpressionRow(tagContents.body, style, true);
4214
4198
  tag.classes = ["tml-tag"];
4215
4199
  } else {
4216
4200
  // \notag. Return an empty span.
@@ -4257,7 +4241,9 @@ rgba(0,0,0,0) 100%);`;
4257
4241
  parser.gullet.macros.set("\\cr", "\\\\\\relax");
4258
4242
  }
4259
4243
  if (addEqnNum) {
4260
- parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}");
4244
+ parser.gullet.macros.set("\\tag", "\\@ifstar\\envtag@literal\\envtag@paren");
4245
+ parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}");
4246
+ parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}");
4261
4247
  parser.gullet.macros.set("\\notag", "\\env@notag");
4262
4248
  parser.gullet.macros.set("\\nonumber", "\\env@notag");
4263
4249
  }
@@ -4298,7 +4284,8 @@ rgba(0,0,0,0) 100%);`;
4298
4284
  cell = {
4299
4285
  type: "ordgroup",
4300
4286
  mode: parser.mode,
4301
- body: cell
4287
+ body: cell,
4288
+ semisimple: true
4302
4289
  };
4303
4290
  row.push(cell);
4304
4291
  const next = parser.fetch().text;
@@ -5131,7 +5118,7 @@ rgba(0,0,0,0) 100%);`;
5131
5118
  const mathGroup = buildGroup$1(group.body, newStyle);
5132
5119
 
5133
5120
  if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{}
5134
- if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) {
5121
+ if (font === "boldsymbol" && ["mo", "mpadded", "mrow"].includes(mathGroup.type)) {
5135
5122
  mathGroup.style.fontWeight = "bold";
5136
5123
  return mathGroup
5137
5124
  }
@@ -6488,10 +6475,10 @@ rgba(0,0,0,0) 100%);`;
6488
6475
  },
6489
6476
  mathmlBuilder(group, style) {
6490
6477
  if (group.isCharacterBox) {
6491
- const inner = buildExpression(group.body, style);
6478
+ const inner = buildExpression(group.body, style, true);
6492
6479
  return inner[0]
6493
6480
  } else {
6494
- return buildExpressionRow(group.body, style, true)
6481
+ return buildExpressionRow(group.body, style)
6495
6482
  }
6496
6483
  }
6497
6484
  });
@@ -6511,6 +6498,13 @@ rgba(0,0,0,0) 100%);`;
6511
6498
  // NOTE: Unlike most `builders`s, this one handles not only "op", but also
6512
6499
  // "supsub" since some of them (like \int) can affect super/subscripting.
6513
6500
 
6501
+ const setSpacing = node => {
6502
+ // The user wrote a \mathop{…} function. Change spacing from default to OP spacing.
6503
+ // The most likely spacing for an OP is a thin space per TeXbook p170.
6504
+ node.attributes.lspace = "0.1667em";
6505
+ node.attributes.rspace = "0.1667em";
6506
+ };
6507
+
6514
6508
  const mathmlBuilder$2 = (group, style) => {
6515
6509
  let node;
6516
6510
 
@@ -6522,9 +6516,11 @@ rgba(0,0,0,0) 100%);`;
6522
6516
  } else {
6523
6517
  node.setAttribute("movablelimits", "false");
6524
6518
  }
6519
+ if (group.fromMathOp) { setSpacing(node); }
6525
6520
  } else if (group.body) {
6526
6521
  // This is an operator with children. Add them.
6527
6522
  node = new MathNode("mo", buildExpression(group.body, style));
6523
+ if (group.fromMathOp) { setSpacing(node); }
6528
6524
  } else {
6529
6525
  // This is a text operator. Add all of the characters from the operator's name.
6530
6526
  node = new MathNode("mi", [new TextNode(group.name.slice(1))]);
@@ -6644,6 +6640,7 @@ rgba(0,0,0,0) 100%);`;
6644
6640
  limits: true,
6645
6641
  parentIsSupSub: false,
6646
6642
  symbol: isSymbol,
6643
+ fromMathOp: true,
6647
6644
  stack: false,
6648
6645
  name: isSymbol ? arr[0].text : null,
6649
6646
  body: isSymbol ? null : ordargument(body)
@@ -6977,7 +6974,7 @@ rgba(0,0,0,0) 100%);`;
6977
6974
  defineFunctionBuilders({
6978
6975
  type: "ordgroup",
6979
6976
  mathmlBuilder(group, style) {
6980
- return buildExpressionRow(group.body, style, true);
6977
+ return buildExpressionRow(group.body, style, group.semisimple);
6981
6978
  }
6982
6979
  });
6983
6980
 
@@ -10106,6 +10103,8 @@ rgba(0,0,0,0) 100%);`;
10106
10103
 
10107
10104
  /* eslint no-constant-condition:0 */
10108
10105
 
10106
+ const binLeftCancellers = ["bin", "op", "open", "punct", "rel"];
10107
+
10109
10108
  /**
10110
10109
  * This file contains the parser used to parse out a TeX expression from the
10111
10110
  * input. Since TeX isn't context-free, standard parsers don't work particularly
@@ -10875,8 +10874,7 @@ rgba(0,0,0,0) 100%);`;
10875
10874
  body: expression,
10876
10875
  // A group formed by \begingroup...\endgroup is a semi-simple group
10877
10876
  // which doesn't affect spacing in math mode, i.e., is transparent.
10878
- // https://tex.stackexchange.com/questions/1930/when-should-one-
10879
- // use-begingroup-instead-of-bgroup
10877
+ // https://tex.stackexchange.com/questions/1930/
10880
10878
  semisimple: text === "\\begingroup" || undefined
10881
10879
  };
10882
10880
  } else {
@@ -10990,7 +10988,11 @@ rgba(0,0,0,0) 100%);`;
10990
10988
  // Recognize base symbol
10991
10989
  let symbol;
10992
10990
  if (symbols[this.mode][text]) {
10993
- const group = symbols[this.mode][text].group;
10991
+ let group = symbols[this.mode][text].group;
10992
+ if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) {
10993
+ // Change from a binary operator to a unary (prefix) operator
10994
+ group = "open";
10995
+ }
10994
10996
  const loc = SourceLocation.range(nucleus);
10995
10997
  let s;
10996
10998
  if (Object.prototype.hasOwnProperty.call(ATOMS, group )) {
@@ -11260,7 +11262,7 @@ rgba(0,0,0,0) 100%);`;
11260
11262
  * https://mit-license.org/
11261
11263
  */
11262
11264
 
11263
- const version = "0.10.19";
11265
+ const version = "0.10.20";
11264
11266
 
11265
11267
  function postProcess(block) {
11266
11268
  const labelMap = {};