temml 0.10.18 → 0.10.20

Sign up to get free protection for your applications and to get access to all the features.
package/dist/temml.mjs CHANGED
@@ -938,8 +938,8 @@ defineSymbol(math, textord, "\u2207", "\\nabla", true);
938
938
  defineSymbol(math, textord, "\u266d", "\\flat", true);
939
939
  defineSymbol(math, textord, "\u2113", "\\ell", true);
940
940
  defineSymbol(math, textord, "\u266e", "\\natural", true);
941
- defineSymbol(math, textord, "Å", "\\AA", true);
942
- defineSymbol(text, textord, "Å", "\\AA", true);
941
+ defineSymbol(math, textord, "Å", "\\Angstrom", true);
942
+ defineSymbol(text, textord, "Å", "\\Angstrom", true);
943
943
  defineSymbol(math, textord, "\u2663", "\\clubsuit", true);
944
944
  defineSymbol(math, textord, "\u2667", "\\varclubsuit", true);
945
945
  defineSymbol(math, textord, "\u2118", "\\wp", true);
@@ -2053,6 +2053,16 @@ const consolidateNumbers = expression => {
2053
2053
  expression[nums[i].start].text += expression[j].text;
2054
2054
  }
2055
2055
  expression.splice(nums[i].start + 1, nums[i].end - nums[i].start);
2056
+ // Check if the <mn> is followed by a numeric base in a supsub, e.g. the "3" in 123^4
2057
+ // If so, merge the first <mn> into the base.
2058
+ if (expression.length > nums[i].start + 1) {
2059
+ const nextTerm = expression[nums[i].start + 1];
2060
+ if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" &&
2061
+ numberRegEx$1.test(nextTerm.base.text)) {
2062
+ nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text;
2063
+ expression.splice(nums[i].start, 1);
2064
+ }
2065
+ }
2056
2066
  }
2057
2067
  };
2058
2068
 
@@ -2060,20 +2070,22 @@ const consolidateNumbers = expression => {
2060
2070
  * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
2061
2071
  * unless the array has length 1. Always returns a single node.
2062
2072
  */
2063
- const makeRow = function(body) {
2073
+ const makeRow = function(body, semisimple = false) {
2064
2074
  if (body.length === 1 && !(body[0] instanceof DocumentFragment)) {
2065
2075
  return body[0];
2066
- } else {
2076
+ } else if (!semisimple) {
2067
2077
  // Suppress spacing on <mo> nodes at both ends of the row.
2068
2078
  if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) {
2069
2079
  body[0].attributes.lspace = "0em";
2080
+ body[0].attributes.rspace = "0em";
2070
2081
  }
2071
2082
  const end = body.length - 1;
2072
2083
  if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) {
2084
+ body[end].attributes.lspace = "0em";
2073
2085
  body[end].attributes.rspace = "0em";
2074
2086
  }
2075
- return new mathMLTree.MathNode("mrow", body);
2076
2087
  }
2088
+ return new mathMLTree.MathNode("mrow", body);
2077
2089
  };
2078
2090
 
2079
2091
  const isRel = item => {
@@ -2087,10 +2099,10 @@ const isRel = item => {
2087
2099
  * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}.
2088
2100
  * (2) Suppress spacing between two adjacent relations.
2089
2101
  */
2090
- const buildExpression = function(expression, style, isOrdgroup) {
2091
- if (expression.length === 1) {
2102
+ const buildExpression = function(expression, style, semisimple = false) {
2103
+ if (!semisimple && expression.length === 1) {
2092
2104
  const group = buildGroup$1(expression[0], style);
2093
- if (isOrdgroup && group instanceof MathNode && group.type === "mo") {
2105
+ if (group instanceof MathNode && group.type === "mo") {
2094
2106
  // When TeX writers want to suppress spacing on an operator,
2095
2107
  // they often put the operator by itself inside braces.
2096
2108
  group.setAttribute("lspace", "0em");
@@ -2120,8 +2132,8 @@ const buildExpression = function(expression, style, isOrdgroup) {
2120
2132
  * Equivalent to buildExpression, but wraps the elements in an <mrow>
2121
2133
  * if there's more than one. Returns a single node instead of an array.
2122
2134
  */
2123
- const buildExpressionRow = function(expression, style, isOrdgroup) {
2124
- return makeRow(buildExpression(expression, style, isOrdgroup));
2135
+ const buildExpressionRow = function(expression, style, semisimple = false) {
2136
+ return makeRow(buildExpression(expression, style, semisimple), semisimple);
2125
2137
  };
2126
2138
 
2127
2139
  /**
@@ -2806,7 +2818,8 @@ function cdArrow(arrowChar, labels, parser) {
2806
2818
  const arrowGroup = {
2807
2819
  type: "ordgroup",
2808
2820
  mode: "math",
2809
- body: [leftLabel, sizedArrow, rightLabel]
2821
+ body: [leftLabel, sizedArrow, rightLabel],
2822
+ semisimple: true
2810
2823
  };
2811
2824
  return parser.callFunction("\\\\cdparent", [arrowGroup], []);
2812
2825
  }
@@ -3928,20 +3941,12 @@ const mathmlBuilder$8 = (group, style) => {
3928
3941
  node.style.borderBottom = "0.065em solid";
3929
3942
  break
3930
3943
  case "\\cancel":
3931
- node.style.background = `linear-gradient(to top left,
3932
- rgba(0,0,0,0) 0%,
3933
- rgba(0,0,0,0) calc(50% - 0.06em),
3934
- rgba(0,0,0,1) 50%,
3935
- rgba(0,0,0,0) calc(50% + 0.06em),
3936
- rgba(0,0,0,0) 100%);`;
3944
+ // We can't use an inline background-gradient. It does not work client-side.
3945
+ // So set a class and put the rule in the external CSS file.
3946
+ node.classes.push("tml-cancel");
3937
3947
  break
3938
3948
  case "\\bcancel":
3939
- node.style.background = `linear-gradient(to top right,
3940
- rgba(0,0,0,0) 0%,
3941
- rgba(0,0,0,0) calc(50% - 0.06em),
3942
- rgba(0,0,0,1) 50%,
3943
- rgba(0,0,0,0) calc(50% + 0.06em),
3944
- rgba(0,0,0,0) 100%);`;
3949
+ node.classes.push("tml-bcancel");
3945
3950
  break
3946
3951
  /*
3947
3952
  case "\\longdiv":
@@ -3988,18 +3993,7 @@ rgba(0,0,0,0) 100%);`;
3988
3993
  break
3989
3994
  }
3990
3995
  case "\\xcancel":
3991
- node.style.background = `linear-gradient(to top left,
3992
- rgba(0,0,0,0) 0%,
3993
- rgba(0,0,0,0) calc(50% - 0.06em),
3994
- rgba(0,0,0,1) 50%,
3995
- rgba(0,0,0,0) calc(50% + 0.06em),
3996
- rgba(0,0,0,0) 100%),
3997
- linear-gradient(to top right,
3998
- rgba(0,0,0,0) 0%,
3999
- rgba(0,0,0,0) calc(50% - 0.06em),
4000
- rgba(0,0,0,1) 50%,
4001
- rgba(0,0,0,0) calc(50% + 0.06em),
4002
- rgba(0,0,0,0) 100%);`;
3996
+ node.classes.push("tml-xcancel");
4003
3997
  break
4004
3998
  }
4005
3999
  if (group.backgroundColor) {
@@ -4197,7 +4191,7 @@ const getTag = (group, style, rowNum) => {
4197
4191
  if (tagContents) {
4198
4192
  // The author has written a \tag or a \notag in this row.
4199
4193
  if (tagContents.body) {
4200
- tag = buildExpressionRow(tagContents.body, style);
4194
+ tag = buildExpressionRow(tagContents.body, style, true);
4201
4195
  tag.classes = ["tml-tag"];
4202
4196
  } else {
4203
4197
  // \notag. Return an empty span.
@@ -4244,7 +4238,9 @@ function parseArray(
4244
4238
  parser.gullet.macros.set("\\cr", "\\\\\\relax");
4245
4239
  }
4246
4240
  if (addEqnNum) {
4247
- parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}");
4241
+ parser.gullet.macros.set("\\tag", "\\@ifstar\\envtag@literal\\envtag@paren");
4242
+ parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}");
4243
+ parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}");
4248
4244
  parser.gullet.macros.set("\\notag", "\\env@notag");
4249
4245
  parser.gullet.macros.set("\\nonumber", "\\env@notag");
4250
4246
  }
@@ -4285,7 +4281,8 @@ function parseArray(
4285
4281
  cell = {
4286
4282
  type: "ordgroup",
4287
4283
  mode: parser.mode,
4288
- body: cell
4284
+ body: cell,
4285
+ semisimple: true
4289
4286
  };
4290
4287
  row.push(cell);
4291
4288
  const next = parser.fetch().text;
@@ -5118,7 +5115,7 @@ const mathmlBuilder$6 = (group, style) => {
5118
5115
  const mathGroup = buildGroup$1(group.body, newStyle);
5119
5116
 
5120
5117
  if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{}
5121
- if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) {
5118
+ if (font === "boldsymbol" && ["mo", "mpadded", "mrow"].includes(mathGroup.type)) {
5122
5119
  mathGroup.style.fontWeight = "bold";
5123
5120
  return mathGroup
5124
5121
  }
@@ -6475,10 +6472,10 @@ defineFunction({
6475
6472
  },
6476
6473
  mathmlBuilder(group, style) {
6477
6474
  if (group.isCharacterBox) {
6478
- const inner = buildExpression(group.body, style);
6475
+ const inner = buildExpression(group.body, style, true);
6479
6476
  return inner[0]
6480
6477
  } else {
6481
- return buildExpressionRow(group.body, style, true)
6478
+ return buildExpressionRow(group.body, style)
6482
6479
  }
6483
6480
  }
6484
6481
  });
@@ -6498,6 +6495,13 @@ const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
6498
6495
  // NOTE: Unlike most `builders`s, this one handles not only "op", but also
6499
6496
  // "supsub" since some of them (like \int) can affect super/subscripting.
6500
6497
 
6498
+ const setSpacing = node => {
6499
+ // The user wrote a \mathop{…} function. Change spacing from default to OP spacing.
6500
+ // The most likely spacing for an OP is a thin space per TeXbook p170.
6501
+ node.attributes.lspace = "0.1667em";
6502
+ node.attributes.rspace = "0.1667em";
6503
+ };
6504
+
6501
6505
  const mathmlBuilder$2 = (group, style) => {
6502
6506
  let node;
6503
6507
 
@@ -6509,9 +6513,11 @@ const mathmlBuilder$2 = (group, style) => {
6509
6513
  } else {
6510
6514
  node.setAttribute("movablelimits", "false");
6511
6515
  }
6516
+ if (group.fromMathOp) { setSpacing(node); }
6512
6517
  } else if (group.body) {
6513
6518
  // This is an operator with children. Add them.
6514
6519
  node = new MathNode("mo", buildExpression(group.body, style));
6520
+ if (group.fromMathOp) { setSpacing(node); }
6515
6521
  } else {
6516
6522
  // This is a text operator. Add all of the characters from the operator's name.
6517
6523
  node = new MathNode("mi", [new TextNode(group.name.slice(1))]);
@@ -6631,6 +6637,7 @@ defineFunction({
6631
6637
  limits: true,
6632
6638
  parentIsSupSub: false,
6633
6639
  symbol: isSymbol,
6640
+ fromMathOp: true,
6634
6641
  stack: false,
6635
6642
  name: isSymbol ? arr[0].text : null,
6636
6643
  body: isSymbol ? null : ordargument(body)
@@ -6964,7 +6971,7 @@ defineMacro("\\operatorname",
6964
6971
  defineFunctionBuilders({
6965
6972
  type: "ordgroup",
6966
6973
  mathmlBuilder(group, style) {
6967
- return buildExpressionRow(group.body, style, true);
6974
+ return buildExpressionRow(group.body, style, group.semisimple);
6968
6975
  }
6969
6976
  });
6970
6977
 
@@ -8914,6 +8921,8 @@ defineMacro("\\quad", "\\hskip1em\\relax");
8914
8921
  // \def\qquad{\hskip2em\relax}
8915
8922
  defineMacro("\\qquad", "\\hskip2em\\relax");
8916
8923
 
8924
+ defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\relax");
8925
+
8917
8926
  // \tag@in@display form of \tag
8918
8927
  defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren");
8919
8928
  defineMacro("\\tag@paren", "\\tag@literal{({#1})}");
@@ -11991,6 +12000,8 @@ var unicodeSymbols = {
11991
12000
 
11992
12001
  /* eslint no-constant-condition:0 */
11993
12002
 
12003
+ const binLeftCancellers = ["bin", "op", "open", "punct", "rel"];
12004
+
11994
12005
  /**
11995
12006
  * This file contains the parser used to parse out a TeX expression from the
11996
12007
  * input. Since TeX isn't context-free, standard parsers don't work particularly
@@ -12760,8 +12771,7 @@ class Parser {
12760
12771
  body: expression,
12761
12772
  // A group formed by \begingroup...\endgroup is a semi-simple group
12762
12773
  // which doesn't affect spacing in math mode, i.e., is transparent.
12763
- // https://tex.stackexchange.com/questions/1930/when-should-one-
12764
- // use-begingroup-instead-of-bgroup
12774
+ // https://tex.stackexchange.com/questions/1930/
12765
12775
  semisimple: text === "\\begingroup" || undefined
12766
12776
  };
12767
12777
  } else {
@@ -12875,7 +12885,11 @@ class Parser {
12875
12885
  // Recognize base symbol
12876
12886
  let symbol;
12877
12887
  if (symbols[this.mode][text]) {
12878
- const group = symbols[this.mode][text].group;
12888
+ let group = symbols[this.mode][text].group;
12889
+ if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) {
12890
+ // Change from a binary operator to a unary (prefix) operator
12891
+ group = "open";
12892
+ }
12879
12893
  const loc = SourceLocation.range(nucleus);
12880
12894
  let s;
12881
12895
  if (Object.prototype.hasOwnProperty.call(ATOMS, group )) {
@@ -13145,7 +13159,7 @@ class Style {
13145
13159
  * https://mit-license.org/
13146
13160
  */
13147
13161
 
13148
- const version = "0.10.18";
13162
+ const version = "0.10.20";
13149
13163
 
13150
13164
  function postProcess(block) {
13151
13165
  const labelMap = {};
@@ -14,7 +14,7 @@
14
14
  * https://mit-license.org/
15
15
  */
16
16
 
17
- const version = "0.10.18";
17
+ const version = "0.10.20";
18
18
 
19
19
  function postProcess(block) {
20
20
  const labelMap = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "temml",
3
- "version": "0.10.18",
3
+ "version": "0.10.20",
4
4
  "description": "TeX to MathML conversion in JavaScript.",
5
5
  "main": "dist/temml.js",
6
6
  "engines": {
package/src/Parser.js CHANGED
@@ -15,6 +15,8 @@ import { isDelimiter } from "./functions/delimsizing"
15
15
  import unicodeAccents from /*preval*/ "./unicodeAccents";
16
16
  import unicodeSymbols from /*preval*/ "./unicodeSymbols";
17
17
 
18
+ const binLeftCancellers = ["bin", "op", "open", "punct", "rel"];
19
+
18
20
  /**
19
21
  * This file contains the parser used to parse out a TeX expression from the
20
22
  * input. Since TeX isn't context-free, standard parsers don't work particularly
@@ -784,8 +786,7 @@ export default class Parser {
784
786
  body: expression,
785
787
  // A group formed by \begingroup...\endgroup is a semi-simple group
786
788
  // which doesn't affect spacing in math mode, i.e., is transparent.
787
- // https://tex.stackexchange.com/questions/1930/when-should-one-
788
- // use-begingroup-instead-of-bgroup
789
+ // https://tex.stackexchange.com/questions/1930/
789
790
  semisimple: text === "\\begingroup" || undefined
790
791
  };
791
792
  } else {
@@ -899,7 +900,11 @@ export default class Parser {
899
900
  // Recognize base symbol
900
901
  let symbol;
901
902
  if (symbols[this.mode][text]) {
902
- const group = symbols[this.mode][text].group;
903
+ let group = symbols[this.mode][text].group;
904
+ if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) {
905
+ // Change from a binary operator to a unary (prefix) operator
906
+ group = "open"
907
+ }
903
908
  const loc = SourceLocation.range(nucleus);
904
909
  let s;
905
910
  if (Object.prototype.hasOwnProperty.call(ATOMS, group )) {
@@ -118,6 +118,16 @@ const consolidateNumbers = expression => {
118
118
  expression[nums[i].start].text += expression[j].text
119
119
  }
120
120
  expression.splice(nums[i].start + 1, nums[i].end - nums[i].start)
121
+ // Check if the <mn> is followed by a numeric base in a supsub, e.g. the "3" in 123^4
122
+ // If so, merge the first <mn> into the base.
123
+ if (expression.length > nums[i].start + 1) {
124
+ const nextTerm = expression[nums[i].start + 1];
125
+ if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" &&
126
+ numberRegEx.test(nextTerm.base.text)) {
127
+ nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text
128
+ expression.splice(nums[i].start, 1)
129
+ }
130
+ }
121
131
  }
122
132
  }
123
133
 
@@ -125,20 +135,22 @@ const consolidateNumbers = expression => {
125
135
  * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
126
136
  * unless the array has length 1. Always returns a single node.
127
137
  */
128
- export const makeRow = function(body) {
138
+ export const makeRow = function(body, semisimple = false) {
129
139
  if (body.length === 1 && !(body[0] instanceof DocumentFragment)) {
130
140
  return body[0];
131
- } else {
141
+ } else if (!semisimple) {
132
142
  // Suppress spacing on <mo> nodes at both ends of the row.
133
143
  if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) {
134
144
  body[0].attributes.lspace = "0em"
145
+ body[0].attributes.rspace = "0em"
135
146
  }
136
147
  const end = body.length - 1
137
148
  if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) {
149
+ body[end].attributes.lspace = "0em"
138
150
  body[end].attributes.rspace = "0em"
139
151
  }
140
- return new mathMLTree.MathNode("mrow", body);
141
152
  }
153
+ return new mathMLTree.MathNode("mrow", body);
142
154
  };
143
155
 
144
156
  const isRel = item => {
@@ -152,10 +164,10 @@ const isRel = item => {
152
164
  * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}.
153
165
  * (2) Suppress spacing between two adjacent relations.
154
166
  */
155
- export const buildExpression = function(expression, style, isOrdgroup) {
156
- if (expression.length === 1) {
167
+ export const buildExpression = function(expression, style, semisimple = false) {
168
+ if (!semisimple && expression.length === 1) {
157
169
  const group = buildGroup(expression[0], style);
158
- if (isOrdgroup && group instanceof MathNode && group.type === "mo") {
170
+ if (group instanceof MathNode && group.type === "mo") {
159
171
  // When TeX writers want to suppress spacing on an operator,
160
172
  // they often put the operator by itself inside braces.
161
173
  group.setAttribute("lspace", "0em");
@@ -185,8 +197,8 @@ export const buildExpression = function(expression, style, isOrdgroup) {
185
197
  * Equivalent to buildExpression, but wraps the elements in an <mrow>
186
198
  * if there's more than one. Returns a single node instead of an array.
187
199
  */
188
- export const buildExpressionRow = function(expression, style, isOrdgroup) {
189
- return makeRow(buildExpression(expression, style, isOrdgroup));
200
+ export const buildExpressionRow = function(expression, style, semisimple = false) {
201
+ return makeRow(buildExpression(expression, style, semisimple), semisimple);
190
202
  };
191
203
 
192
204
  /**
@@ -44,7 +44,7 @@ const getTag = (group, style, rowNum) => {
44
44
  if (tagContents) {
45
45
  // The author has written a \tag or a \notag in this row.
46
46
  if (tagContents.body) {
47
- tag = mml.buildExpressionRow(tagContents.body, style)
47
+ tag = mml.buildExpressionRow(tagContents.body, style, true)
48
48
  tag.classes = ["tml-tag"]
49
49
  } else {
50
50
  // \notag. Return an empty span.
@@ -91,7 +91,9 @@ function parseArray(
91
91
  parser.gullet.macros.set("\\cr", "\\\\\\relax");
92
92
  }
93
93
  if (addEqnNum) {
94
- parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}");
94
+ parser.gullet.macros.set("\\tag", "\\@ifstar\\envtag@literal\\envtag@paren")
95
+ parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}");
96
+ parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}")
95
97
  parser.gullet.macros.set("\\notag", "\\env@notag");
96
98
  parser.gullet.macros.set("\\nonumber", "\\env@notag")
97
99
  }
@@ -132,7 +134,8 @@ function parseArray(
132
134
  cell = {
133
135
  type: "ordgroup",
134
136
  mode: parser.mode,
135
- body: cell
137
+ body: cell,
138
+ semisimple: true
136
139
  };
137
140
  row.push(cell);
138
141
  const next = parser.fetch().text;
@@ -49,7 +49,8 @@ function cdArrow(arrowChar, labels, parser) {
49
49
  const arrowGroup = {
50
50
  type: "ordgroup",
51
51
  mode: "math",
52
- body: [leftLabel, sizedArrow, rightLabel]
52
+ body: [leftLabel, sizedArrow, rightLabel],
53
+ semisimple: true
53
54
  };
54
55
  return parser.callFunction("\\\\cdparent", [arrowGroup], []);
55
56
  }
@@ -34,20 +34,12 @@ const mathmlBuilder = (group, style) => {
34
34
  node.style.borderBottom = "0.065em solid"
35
35
  break
36
36
  case "\\cancel":
37
- node.style.background = `linear-gradient(to top left,
38
- rgba(0,0,0,0) 0%,
39
- rgba(0,0,0,0) calc(50% - 0.06em),
40
- rgba(0,0,0,1) 50%,
41
- rgba(0,0,0,0) calc(50% + 0.06em),
42
- rgba(0,0,0,0) 100%);`
37
+ // We can't use an inline background-gradient. It does not work client-side.
38
+ // So set a class and put the rule in the external CSS file.
39
+ node.classes.push("tml-cancel")
43
40
  break
44
41
  case "\\bcancel":
45
- node.style.background = `linear-gradient(to top right,
46
- rgba(0,0,0,0) 0%,
47
- rgba(0,0,0,0) calc(50% - 0.06em),
48
- rgba(0,0,0,1) 50%,
49
- rgba(0,0,0,0) calc(50% + 0.06em),
50
- rgba(0,0,0,0) 100%);`
42
+ node.classes.push("tml-bcancel")
51
43
  break
52
44
  /*
53
45
  case "\\longdiv":
@@ -94,18 +86,7 @@ rgba(0,0,0,0) 100%);`
94
86
  break
95
87
  }
96
88
  case "\\xcancel":
97
- node.style.background = `linear-gradient(to top left,
98
- rgba(0,0,0,0) 0%,
99
- rgba(0,0,0,0) calc(50% - 0.06em),
100
- rgba(0,0,0,1) 50%,
101
- rgba(0,0,0,0) calc(50% + 0.06em),
102
- rgba(0,0,0,0) 100%),
103
- linear-gradient(to top right,
104
- rgba(0,0,0,0) 0%,
105
- rgba(0,0,0,0) calc(50% - 0.06em),
106
- rgba(0,0,0,1) 50%,
107
- rgba(0,0,0,0) calc(50% + 0.06em),
108
- rgba(0,0,0,0) 100%);`
89
+ node.classes.push("tml-xcancel")
109
90
  break
110
91
  }
111
92
  if (group.backgroundColor) {
@@ -8,7 +8,7 @@ const mathmlBuilder = (group, style) => {
8
8
  const mathGroup = mml.buildGroup(group.body, newStyle)
9
9
 
10
10
  if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{}
11
- if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) {
11
+ if (font === "boldsymbol" && ["mo", "mpadded", "mrow"].includes(mathGroup.type)) {
12
12
  mathGroup.style.fontWeight = "bold"
13
13
  return mathGroup
14
14
  }
@@ -37,10 +37,10 @@ defineFunction({
37
37
  },
38
38
  mathmlBuilder(group, style) {
39
39
  if (group.isCharacterBox) {
40
- const inner = mml.buildExpression(group.body, style);
40
+ const inner = mml.buildExpression(group.body, style, true);
41
41
  return inner[0]
42
42
  } else {
43
- return mml.buildExpressionRow(group.body, style, true)
43
+ return mml.buildExpressionRow(group.body, style)
44
44
  }
45
45
  }
46
46
  });
@@ -17,6 +17,13 @@ export const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"]
17
17
  // NOTE: Unlike most `builders`s, this one handles not only "op", but also
18
18
  // "supsub" since some of them (like \int) can affect super/subscripting.
19
19
 
20
+ const setSpacing = node => {
21
+ // The user wrote a \mathop{…} function. Change spacing from default to OP spacing.
22
+ // The most likely spacing for an OP is a thin space per TeXbook p170.
23
+ node.attributes.lspace = "0.1667em"
24
+ node.attributes.rspace = "0.1667em"
25
+ }
26
+
20
27
  const mathmlBuilder = (group, style) => {
21
28
  let node;
22
29
 
@@ -28,9 +35,11 @@ const mathmlBuilder = (group, style) => {
28
35
  } else {
29
36
  node.setAttribute("movablelimits", "false")
30
37
  }
38
+ if (group.fromMathOp) { setSpacing(node) }
31
39
  } else if (group.body) {
32
40
  // This is an operator with children. Add them.
33
41
  node = new mathMLTree.MathNode("mo", mml.buildExpression(group.body, style));
42
+ if (group.fromMathOp) { setSpacing(node) }
34
43
  } else {
35
44
  // This is a text operator. Add all of the characters from the operator's name.
36
45
  node = new mathMLTree.MathNode("mi", [new mathMLTree.TextNode(group.name.slice(1))]);
@@ -150,6 +159,7 @@ defineFunction({
150
159
  limits: true,
151
160
  parentIsSupSub: false,
152
161
  symbol: isSymbol,
162
+ fromMathOp: true,
153
163
  stack: false,
154
164
  name: isSymbol ? arr[0].text : null,
155
165
  body: isSymbol ? null : ordargument(body)
@@ -4,6 +4,6 @@ import * as mml from "../buildMathML";
4
4
  defineFunctionBuilders({
5
5
  type: "ordgroup",
6
6
  mathmlBuilder(group, style) {
7
- return mml.buildExpressionRow(group.body, style, true);
7
+ return mml.buildExpressionRow(group.body, style, group.semisimple);
8
8
  }
9
9
  });
package/src/macros.js CHANGED
@@ -436,6 +436,8 @@ defineMacro("\\quad", "\\hskip1em\\relax");
436
436
  // \def\qquad{\hskip2em\relax}
437
437
  defineMacro("\\qquad", "\\hskip2em\\relax");
438
438
 
439
+ defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\relax")
440
+
439
441
  // \tag@in@display form of \tag
440
442
  defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren");
441
443
  defineMacro("\\tag@paren", "\\tag@literal{({#1})}");
@@ -8,7 +8,7 @@
8
8
  * https://mit-license.org/
9
9
  */
10
10
 
11
- export const version = "0.10.18";
11
+ export const version = "0.10.20";
12
12
 
13
13
  export function postProcess(block) {
14
14
  const labelMap = {}
package/src/symbols.js CHANGED
@@ -132,8 +132,8 @@ defineSymbol(math, textord, "\u2207", "\\nabla", true);
132
132
  defineSymbol(math, textord, "\u266d", "\\flat", true);
133
133
  defineSymbol(math, textord, "\u2113", "\\ell", true);
134
134
  defineSymbol(math, textord, "\u266e", "\\natural", true);
135
- defineSymbol(math, textord, "Å", "\\AA", true);
136
- defineSymbol(text, textord, "Å", "\\AA", true);
135
+ defineSymbol(math, textord, "Å", "\\Angstrom", true);
136
+ defineSymbol(text, textord, "Å", "\\Angstrom", true);
137
137
  defineSymbol(math, textord, "\u2663", "\\clubsuit", true);
138
138
  defineSymbol(math, textord, "\u2667", "\\varclubsuit", true);
139
139
  defineSymbol(math, textord, "\u2118", "\\wp", true);