temml 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/contrib/auto-render/README.md +89 -0
  4. package/contrib/auto-render/auto-render.js +128 -0
  5. package/contrib/auto-render/dist/auto-render.js +217 -0
  6. package/contrib/auto-render/dist/auto-render.min.js +1 -0
  7. package/contrib/auto-render/splitAtDelimiters.js +84 -0
  8. package/contrib/auto-render/test/auto-render-spec.js +234 -0
  9. package/contrib/auto-render/test/auto-render.js +217 -0
  10. package/contrib/auto-render/test/test_page.html +59 -0
  11. package/contrib/mhchem/README.md +26 -0
  12. package/contrib/mhchem/mhchem.js +1705 -0
  13. package/contrib/mhchem/mhchem.min.js +1 -0
  14. package/contrib/physics/README.md +20 -0
  15. package/contrib/physics/physics.js +131 -0
  16. package/contrib/texvc/README.md +23 -0
  17. package/contrib/texvc/texvc.js +61 -0
  18. package/dist/Temml-Asana.css +201 -0
  19. package/dist/Temml-Latin-Modern.css +216 -0
  20. package/dist/Temml-Libertinus.css +214 -0
  21. package/dist/Temml-Local.css +194 -0
  22. package/dist/Temml-STIX2.css +203 -0
  23. package/dist/Temml.woff2 +0 -0
  24. package/dist/temml.cjs +13122 -0
  25. package/dist/temml.js +11225 -0
  26. package/dist/temml.min.js +1 -0
  27. package/dist/temml.mjs +13120 -0
  28. package/dist/temmlPostProcess.js +70 -0
  29. package/package.json +34 -0
  30. package/src/Lexer.js +121 -0
  31. package/src/MacroExpander.js +437 -0
  32. package/src/Namespace.js +107 -0
  33. package/src/ParseError.js +64 -0
  34. package/src/Parser.js +977 -0
  35. package/src/Settings.js +49 -0
  36. package/src/SourceLocation.js +29 -0
  37. package/src/Style.js +144 -0
  38. package/src/Token.js +40 -0
  39. package/src/buildMathML.js +235 -0
  40. package/src/constants.js +25 -0
  41. package/src/defineEnvironment.js +25 -0
  42. package/src/defineFunction.js +69 -0
  43. package/src/defineMacro.js +11 -0
  44. package/src/domTree.js +185 -0
  45. package/src/environments/array.js +791 -0
  46. package/src/environments/cd.js +252 -0
  47. package/src/environments.js +8 -0
  48. package/src/functions/accent.js +127 -0
  49. package/src/functions/accentunder.js +38 -0
  50. package/src/functions/arrow.js +204 -0
  51. package/src/functions/cancelto.js +36 -0
  52. package/src/functions/char.js +33 -0
  53. package/src/functions/color.js +253 -0
  54. package/src/functions/cr.js +46 -0
  55. package/src/functions/def.js +259 -0
  56. package/src/functions/delimsizing.js +304 -0
  57. package/src/functions/enclose.js +193 -0
  58. package/src/functions/envTag.js +38 -0
  59. package/src/functions/environment.js +59 -0
  60. package/src/functions/font.js +123 -0
  61. package/src/functions/genfrac.js +333 -0
  62. package/src/functions/hbox.js +29 -0
  63. package/src/functions/horizBrace.js +32 -0
  64. package/src/functions/href.js +90 -0
  65. package/src/functions/html.js +95 -0
  66. package/src/functions/includegraphics.js +131 -0
  67. package/src/functions/kern.js +75 -0
  68. package/src/functions/label.js +29 -0
  69. package/src/functions/lap.js +75 -0
  70. package/src/functions/math.js +40 -0
  71. package/src/functions/mathchoice.js +41 -0
  72. package/src/functions/mclass.js +201 -0
  73. package/src/functions/multiscript.js +91 -0
  74. package/src/functions/not.js +46 -0
  75. package/src/functions/op.js +338 -0
  76. package/src/functions/operatorname.js +139 -0
  77. package/src/functions/ordgroup.js +9 -0
  78. package/src/functions/phantom.js +73 -0
  79. package/src/functions/pmb.js +31 -0
  80. package/src/functions/raise.js +68 -0
  81. package/src/functions/ref.js +28 -0
  82. package/src/functions/relax.js +16 -0
  83. package/src/functions/rule.js +52 -0
  84. package/src/functions/sizing.js +64 -0
  85. package/src/functions/smash.js +66 -0
  86. package/src/functions/sqrt.js +31 -0
  87. package/src/functions/styling.js +58 -0
  88. package/src/functions/supsub.js +135 -0
  89. package/src/functions/symbolsOp.js +53 -0
  90. package/src/functions/symbolsOrd.js +102 -0
  91. package/src/functions/symbolsSpacing.js +53 -0
  92. package/src/functions/tag.js +8 -0
  93. package/src/functions/text.js +75 -0
  94. package/src/functions/tip.js +63 -0
  95. package/src/functions/toggle.js +13 -0
  96. package/src/functions/verb.js +33 -0
  97. package/src/functions.js +57 -0
  98. package/src/linebreaking.js +159 -0
  99. package/src/macros.js +708 -0
  100. package/src/mathMLTree.js +175 -0
  101. package/src/parseNode.js +42 -0
  102. package/src/parseTree.js +40 -0
  103. package/src/postProcess.js +57 -0
  104. package/src/replace.js +225 -0
  105. package/src/stretchy.js +66 -0
  106. package/src/svg.js +110 -0
  107. package/src/symbols.js +972 -0
  108. package/src/tree.js +50 -0
  109. package/src/unicodeAccents.js +16 -0
  110. package/src/unicodeScripts.js +119 -0
  111. package/src/unicodeSupOrSub.js +108 -0
  112. package/src/unicodeSymbolBuilder.js +31 -0
  113. package/src/unicodeSymbols.js +320 -0
  114. package/src/units.js +109 -0
  115. package/src/utils.js +109 -0
  116. package/src/variant.js +103 -0
  117. package/temml.js +181 -0
@@ -0,0 +1,46 @@
1
+ import defineFunction, { ordargument } from "../defineFunction";
2
+ import symbols from "../symbols";
3
+ import * as mml from "../buildMathML";
4
+ import utils from "../utils"
5
+
6
+ defineFunction({
7
+ type: "not",
8
+ names: ["\\not"],
9
+ props: {
10
+ numArgs: 1,
11
+ primitive: true,
12
+ allowedInText: false
13
+ },
14
+ handler({ parser }, args) {
15
+ const isCharacterBox = utils.isCharacterBox(args[0])
16
+ let body
17
+ if (isCharacterBox) {
18
+ body = ordargument(args[0])
19
+ if (body[0].text.charAt(0) === "\\") {
20
+ body[0].text = symbols.math[body[0].text].replace
21
+ }
22
+ // \u0338 is the Unicode Combining Long Solidus Overlay
23
+ body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1)
24
+ } else {
25
+ // When the argument is not a character box, TeX does an awkward, poorly placed overlay.
26
+ // We'll do the same.
27
+ const notNode = { type: "textord", mode: "math", text: "\u0338" }
28
+ const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } }
29
+ body = [notNode, kernNode, args[0]]
30
+ }
31
+ return {
32
+ type: "not",
33
+ mode: parser.mode,
34
+ body,
35
+ isCharacterBox
36
+ };
37
+ },
38
+ mathmlBuilder(group, style) {
39
+ if (group.isCharacterBox) {
40
+ const inner = mml.buildExpression(group.body, style);
41
+ return inner[0]
42
+ } else {
43
+ return mml.buildExpressionRow(group.body, style, true)
44
+ }
45
+ }
46
+ });
@@ -0,0 +1,338 @@
1
+ // Limits, symbols
2
+ import defineFunction, { ordargument } from "../defineFunction";
3
+ import * as mathMLTree from "../mathMLTree";
4
+ import * as mml from "../buildMathML";
5
+ import { delimiters, delimiterSizes } from "./delimsizing"
6
+
7
+ // Some helpers
8
+
9
+ const ordAtomTypes = ["textord", "mathord", "atom"]
10
+
11
+ // Most operators have a large successor symbol, but these don't.
12
+ const noSuccessor = ["\\smallint"];
13
+
14
+ // Math operators (e.g. \sin) need a space between these types and themselves:
15
+ export const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
16
+
17
+ const dels = ["}", "\\left", "\\middle", "\\right"]
18
+ const isDelimiter = str => str.length > 0 &&
19
+ (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str))
20
+
21
+ // NOTE: Unlike most `builders`s, this one handles not only "op", but also
22
+ // "supsub" since some of them (like \int) can affect super/subscripting.
23
+
24
+ const mathmlBuilder = (group, style) => {
25
+ let node;
26
+
27
+ if (group.symbol) {
28
+ // This is a symbol. Just add the symbol.
29
+ node = new mathMLTree.MathNode("mo", [mml.makeText(group.name, group.mode)]);
30
+ if (noSuccessor.includes(group.name)) {
31
+ node.setAttribute("largeop", "false")
32
+ } else {
33
+ node.setAttribute("movablelimits", "false")
34
+ }
35
+ } else if (group.body) {
36
+ // This is an operator with children. Add them.
37
+ node = new mathMLTree.MathNode("mo", mml.buildExpression(group.body, style));
38
+ } else {
39
+ // This is a text operator. Add all of the characters from the operator's name.
40
+ node = new mathMLTree.MathNode("mi", [new mathMLTree.TextNode(group.name.slice(1))]);
41
+
42
+ if (!group.parentIsSupSub) {
43
+ // Append an invisible <mo>&ApplyFunction;</mo>.
44
+ // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
45
+ const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")]);
46
+ const row = [node, operator]
47
+ // Set spacing
48
+ if (group.needsLeadingSpace) {
49
+ const lead = new mathMLTree.MathNode("mspace")
50
+ lead.setAttribute("width", "0.1667em") // thin space.
51
+ row.unshift(lead)
52
+ }
53
+ if (!group.isFollowedByDelimiter) {
54
+ const trail = new mathMLTree.MathNode("mspace")
55
+ trail.setAttribute("width", "0.1667em") // thin space.
56
+ row.push(trail)
57
+ }
58
+ node = new mathMLTree.MathNode("mrow", row)
59
+ }
60
+ }
61
+
62
+ return node;
63
+ };
64
+
65
+ const singleCharBigOps = {
66
+ "\u220F": "\\prod",
67
+ "\u2210": "\\coprod",
68
+ "\u2211": "\\sum",
69
+ "\u22c0": "\\bigwedge",
70
+ "\u22c1": "\\bigvee",
71
+ "\u22c2": "\\bigcap",
72
+ "\u22c3": "\\bigcup",
73
+ "\u2a00": "\\bigodot",
74
+ "\u2a01": "\\bigoplus",
75
+ "\u2a02": "\\bigotimes",
76
+ "\u2a04": "\\biguplus",
77
+ "\u2a05": "\\bigsqcap",
78
+ "\u2a06": "\\bigsqcup"
79
+ };
80
+
81
+ defineFunction({
82
+ type: "op",
83
+ names: [
84
+ "\\coprod",
85
+ "\\bigvee",
86
+ "\\bigwedge",
87
+ "\\biguplus",
88
+ "\\bigcap",
89
+ "\\bigcup",
90
+ "\\intop",
91
+ "\\prod",
92
+ "\\sum",
93
+ "\\bigotimes",
94
+ "\\bigoplus",
95
+ "\\bigodot",
96
+ "\\bigsqcap",
97
+ "\\bigsqcup",
98
+ "\\smallint",
99
+ "\u220F",
100
+ "\u2210",
101
+ "\u2211",
102
+ "\u22c0",
103
+ "\u22c1",
104
+ "\u22c2",
105
+ "\u22c3",
106
+ "\u2a00",
107
+ "\u2a01",
108
+ "\u2a02",
109
+ "\u2a04",
110
+ "\u2a06"
111
+ ],
112
+ props: {
113
+ numArgs: 0
114
+ },
115
+ handler: ({ parser, funcName }, args) => {
116
+ let fName = funcName;
117
+ if (fName.length === 1) {
118
+ fName = singleCharBigOps[fName];
119
+ }
120
+ return {
121
+ type: "op",
122
+ mode: parser.mode,
123
+ limits: true,
124
+ parentIsSupSub: false,
125
+ symbol: true,
126
+ stack: false, // This is true for \stackrel{}, not here.
127
+ name: fName
128
+ };
129
+ },
130
+ mathmlBuilder
131
+ });
132
+
133
+ // Note: calling defineFunction with a type that's already been defined only
134
+ // works because the same mathmlBuilder is being used.
135
+ defineFunction({
136
+ type: "op",
137
+ names: ["\\mathop"],
138
+ props: {
139
+ numArgs: 1,
140
+ primitive: true
141
+ },
142
+ handler: ({ parser }, args) => {
143
+ const body = args[0];
144
+ // It would be convienient to just wrap a <mo> around the argument.
145
+ // But if the argument is a <mi> or <mord>, that would be invalid MathML.
146
+ // In that case, we instead promote the text contents of the body to the parent.
147
+ const arr = (body.body) ? body.body : [body];
148
+ const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type)
149
+ return {
150
+ type: "op",
151
+ mode: parser.mode,
152
+ limits: true,
153
+ parentIsSupSub: false,
154
+ symbol: isSymbol,
155
+ stack: false,
156
+ name: isSymbol ? arr[0].text : null,
157
+ body: isSymbol ? null : ordargument(body)
158
+ };
159
+ },
160
+ mathmlBuilder
161
+ });
162
+
163
+ // There are 2 flags for operators; whether they produce limits in
164
+ // displaystyle, and whether they are symbols and should grow in
165
+ // displaystyle. These four groups cover the four possible choices.
166
+
167
+ const singleCharIntegrals = {
168
+ "\u222b": "\\int",
169
+ "\u222c": "\\iint",
170
+ "\u222d": "\\iiint",
171
+ "\u222e": "\\oint",
172
+ "\u222f": "\\oiint",
173
+ "\u2230": "\\oiiint",
174
+ "\u2231": "\\intclockwise",
175
+ "\u2232": "\\varointclockwise",
176
+ "\u2a0c": "\\iiiint",
177
+ "\u2a0d": "\\intbar",
178
+ "\u2a0e": "\\intBar",
179
+ "\u2a0f": "\\fint",
180
+ "\u2a12": "\\rppolint",
181
+ "\u2a13": "\\scpolint",
182
+ "\u2a15": "\\pointint",
183
+ "\u2a16": "\\sqint",
184
+ "\u2a17": "\\intlarhk",
185
+ "\u2a18": "\\intx",
186
+ "\u2a19": "\\intcap",
187
+ "\u2a1a": "\\intcup"
188
+ };
189
+
190
+ // No limits, not symbols
191
+ defineFunction({
192
+ type: "op",
193
+ names: [
194
+ "\\arcsin",
195
+ "\\arccos",
196
+ "\\arctan",
197
+ "\\arctg",
198
+ "\\arcctg",
199
+ "\\arg",
200
+ "\\ch",
201
+ "\\cos",
202
+ "\\cosec",
203
+ "\\cosh",
204
+ "\\cot",
205
+ "\\cotg",
206
+ "\\coth",
207
+ "\\csc",
208
+ "\\ctg",
209
+ "\\cth",
210
+ "\\deg",
211
+ "\\dim",
212
+ "\\exp",
213
+ "\\hom",
214
+ "\\ker",
215
+ "\\lg",
216
+ "\\ln",
217
+ "\\log",
218
+ "\\sec",
219
+ "\\sin",
220
+ "\\sinh",
221
+ "\\sh",
222
+ "\\sgn",
223
+ "\\tan",
224
+ "\\tanh",
225
+ "\\tg",
226
+ "\\th"
227
+ ],
228
+ props: {
229
+ numArgs: 0
230
+ },
231
+ handler({ parser, funcName }) {
232
+ const prevAtomType = parser.prevAtomType
233
+ const next = parser.gullet.future().text
234
+ return {
235
+ type: "op",
236
+ mode: parser.mode,
237
+ limits: false,
238
+ parentIsSupSub: false,
239
+ symbol: false,
240
+ stack: false,
241
+ isFollowedByDelimiter: isDelimiter(next),
242
+ needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
243
+ name: funcName
244
+ };
245
+ },
246
+ mathmlBuilder
247
+ });
248
+
249
+ // Limits, not symbols
250
+ defineFunction({
251
+ type: "op",
252
+ names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"],
253
+ props: {
254
+ numArgs: 0
255
+ },
256
+ handler({ parser, funcName }) {
257
+ const prevAtomType = parser.prevAtomType
258
+ const next = parser.gullet.future().text
259
+ return {
260
+ type: "op",
261
+ mode: parser.mode,
262
+ limits: true,
263
+ parentIsSupSub: false,
264
+ symbol: false,
265
+ stack: false,
266
+ isFollowedByDelimiter: isDelimiter(next),
267
+ needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
268
+ name: funcName
269
+ };
270
+ },
271
+ mathmlBuilder
272
+ });
273
+
274
+ // No limits, symbols
275
+ defineFunction({
276
+ type: "op",
277
+ names: [
278
+ "\\int",
279
+ "\\iint",
280
+ "\\iiint",
281
+ "\\iiiint",
282
+ "\\oint",
283
+ "\\oiint",
284
+ "\\oiiint",
285
+ "\\intclockwise",
286
+ "\\varointclockwise",
287
+ "\\intbar",
288
+ "\\intBar",
289
+ "\\fint",
290
+ "\\rppolint",
291
+ "\\scpolint",
292
+ "\\pointint",
293
+ "\\sqint",
294
+ "\\intlarhk",
295
+ "\\intx",
296
+ "\\intcap",
297
+ "\\intcup",
298
+ "\u222b",
299
+ "\u222c",
300
+ "\u222d",
301
+ "\u222e",
302
+ "\u222f",
303
+ "\u2230",
304
+ "\u2231",
305
+ "\u2232",
306
+ "\u2a0c",
307
+ "\u2a0d",
308
+ "\u2a0e",
309
+ "\u2a0f",
310
+ "\u2a12",
311
+ "\u2a13",
312
+ "\u2a15",
313
+ "\u2a16",
314
+ "\u2a17",
315
+ "\u2a18",
316
+ "\u2a19",
317
+ "\u2a1a"
318
+ ],
319
+ props: {
320
+ numArgs: 0
321
+ },
322
+ handler({ parser, funcName }) {
323
+ let fName = funcName;
324
+ if (fName.length === 1) {
325
+ fName = singleCharIntegrals[fName];
326
+ }
327
+ return {
328
+ type: "op",
329
+ mode: parser.mode,
330
+ limits: false,
331
+ parentIsSupSub: false,
332
+ symbol: true,
333
+ stack: false,
334
+ name: fName
335
+ };
336
+ },
337
+ mathmlBuilder
338
+ });
@@ -0,0 +1,139 @@
1
+ import defineFunction, { ordargument } from "../defineFunction"
2
+ import defineMacro from "../defineMacro";
3
+ import mathMLTree from "../mathMLTree"
4
+ import { spaceCharacter } from "./kern"
5
+ import { ordTypes } from "./op"
6
+ import { delimiters, delimiterSizes } from "./delimsizing"
7
+
8
+ import * as mml from "../buildMathML"
9
+
10
+ const dels = ["}", "\\left", "\\middle", "\\right"]
11
+ const isDelimiter = str => str.length > 0 &&
12
+ (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str))
13
+
14
+ // NOTE: Unlike most builders, this one handles not only
15
+ // "operatorname", but also "supsub" since \operatorname* can
16
+ // affect super/subscripting.
17
+
18
+ const mathmlBuilder = (group, style) => {
19
+ let expression = mml.buildExpression(group.body, style.withFont("mathrm"))
20
+
21
+ // Is expression a string or has it something like a fraction?
22
+ let isAllString = true; // default
23
+ for (let i = 0; i < expression.length; i++) {
24
+ const node = expression[i]
25
+ if (node instanceof mathMLTree.MathNode) {
26
+ switch (node.type) {
27
+ case "mi":
28
+ case "mn":
29
+ case "ms":
30
+ case "mtext":
31
+ break; // Do nothing yet.
32
+ case "mspace":
33
+ {
34
+ if (node.attributes.width) {
35
+ const width = node.attributes.width.replace("em", "")
36
+ const ch = spaceCharacter(Number(width))
37
+ if (ch === "") {
38
+ isAllString = false
39
+ } else {
40
+ expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)])
41
+ }
42
+ }
43
+ }
44
+ break
45
+ case "mo": {
46
+ const child = node.children[0]
47
+ if (node.children.length === 1 && child instanceof mathMLTree.TextNode) {
48
+ child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*")
49
+ } else {
50
+ isAllString = false
51
+ }
52
+ break
53
+ }
54
+ default:
55
+ isAllString = false
56
+ }
57
+ } else {
58
+ isAllString = false
59
+ }
60
+ }
61
+
62
+ if (isAllString) {
63
+ // Write a single TextNode instead of multiple nested tags.
64
+ const word = expression.map((node) => node.toText()).join("")
65
+ expression = [new mathMLTree.TextNode(word)]
66
+ } else if (
67
+ expression.length === 1
68
+ && ["mover", "munder"].includes(expression[0].type) &&
69
+ (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext")
70
+ ) {
71
+ expression[0].children[0].type = "mi"
72
+ if (group.parentIsSupSub) {
73
+ return new mathMLTree.MathNode("mrow", expression)
74
+ } else {
75
+ const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")])
76
+ return mathMLTree.newDocumentFragment([expression[0], operator])
77
+ }
78
+ }
79
+
80
+ let wrapper;
81
+ if (isAllString) {
82
+ wrapper = new mathMLTree.MathNode("mi", expression)
83
+ wrapper.setAttribute("mathvariant", "normal")
84
+ } else {
85
+ wrapper = new mathMLTree.MathNode("mrow", expression)
86
+ }
87
+
88
+ if (!group.parentIsSupSub) {
89
+ // Append an <mo>&ApplyFunction;</mo>.
90
+ // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
91
+ const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")])
92
+ const fragment = [wrapper, operator]
93
+ if (group.needsLeadingSpace) {
94
+ // LaTeX gives operator spacing, but a <mi> gets ord spacing.
95
+ // So add a leading space.
96
+ const space = new mathMLTree.MathNode("mspace")
97
+ space.setAttribute("width", "0.1667em") // thin space.
98
+ fragment.unshift(space)
99
+ }
100
+ if (!group.isFollowedByDelimiter) {
101
+ const trail = new mathMLTree.MathNode("mspace")
102
+ trail.setAttribute("width", "0.1667em") // thin space.
103
+ fragment.push(trail)
104
+ }
105
+ return mathMLTree.newDocumentFragment(fragment)
106
+ }
107
+
108
+ return wrapper
109
+ };
110
+
111
+ // \operatorname
112
+ // amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
113
+ defineFunction({
114
+ type: "operatorname",
115
+ names: ["\\operatorname@", "\\operatornamewithlimits"],
116
+ props: {
117
+ numArgs: 1,
118
+ allowedInArgument: true
119
+ },
120
+ handler: ({ parser, funcName }, args) => {
121
+ const body = args[0]
122
+ const prevAtomType = parser.prevAtomType
123
+ const next = parser.gullet.future().text
124
+ return {
125
+ type: "operatorname",
126
+ mode: parser.mode,
127
+ body: ordargument(body),
128
+ alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"),
129
+ limits: false,
130
+ parentIsSupSub: false,
131
+ isFollowedByDelimiter: isDelimiter(next),
132
+ needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType)
133
+ };
134
+ },
135
+ mathmlBuilder
136
+ });
137
+
138
+ defineMacro("\\operatorname",
139
+ "\\@ifstar\\operatornamewithlimits\\operatorname@");
@@ -0,0 +1,9 @@
1
+ import { defineFunctionBuilders } from "../defineFunction";
2
+ import * as mml from "../buildMathML";
3
+
4
+ defineFunctionBuilders({
5
+ type: "ordgroup",
6
+ mathmlBuilder(group, style) {
7
+ return mml.buildExpressionRow(group.body, style, true);
8
+ }
9
+ });
@@ -0,0 +1,73 @@
1
+ import defineFunction, { ordargument } from "../defineFunction";
2
+ import mathMLTree from "../mathMLTree";
3
+ import * as mml from "../buildMathML";
4
+
5
+ defineFunction({
6
+ type: "phantom",
7
+ names: ["\\phantom"],
8
+ props: {
9
+ numArgs: 1,
10
+ allowedInText: true
11
+ },
12
+ handler: ({ parser }, args) => {
13
+ const body = args[0];
14
+ return {
15
+ type: "phantom",
16
+ mode: parser.mode,
17
+ body: ordargument(body)
18
+ };
19
+ },
20
+ mathmlBuilder: (group, style) => {
21
+ const inner = mml.buildExpression(group.body, style);
22
+ return new mathMLTree.MathNode("mphantom", inner);
23
+ }
24
+ });
25
+
26
+ defineFunction({
27
+ type: "hphantom",
28
+ names: ["\\hphantom"],
29
+ props: {
30
+ numArgs: 1,
31
+ allowedInText: true
32
+ },
33
+ handler: ({ parser }, args) => {
34
+ const body = args[0];
35
+ return {
36
+ type: "hphantom",
37
+ mode: parser.mode,
38
+ body
39
+ };
40
+ },
41
+ mathmlBuilder: (group, style) => {
42
+ const inner = mml.buildExpression(ordargument(group.body), style);
43
+ const phantom = new mathMLTree.MathNode("mphantom", inner);
44
+ const node = new mathMLTree.MathNode("mpadded", [phantom]);
45
+ node.setAttribute("height", "0px");
46
+ node.setAttribute("depth", "0px");
47
+ return node;
48
+ }
49
+ });
50
+
51
+ defineFunction({
52
+ type: "vphantom",
53
+ names: ["\\vphantom"],
54
+ props: {
55
+ numArgs: 1,
56
+ allowedInText: true
57
+ },
58
+ handler: ({ parser }, args) => {
59
+ const body = args[0];
60
+ return {
61
+ type: "vphantom",
62
+ mode: parser.mode,
63
+ body
64
+ };
65
+ },
66
+ mathmlBuilder: (group, style) => {
67
+ const inner = mml.buildExpression(ordargument(group.body), style);
68
+ const phantom = new mathMLTree.MathNode("mphantom", inner);
69
+ const node = new mathMLTree.MathNode("mpadded", [phantom]);
70
+ node.setAttribute("width", "0px");
71
+ return node;
72
+ }
73
+ });
@@ -0,0 +1,31 @@
1
+ import defineFunction, { ordargument } from "../defineFunction"
2
+ import { wrapWithMstyle } from "../mathMLTree"
3
+ import * as mml from "../buildMathML"
4
+
5
+ // \pmb is a simulation of bold font.
6
+ // The version of \pmb in ambsy.sty works by typesetting three copies of the argument
7
+ // with small offsets. We use CSS text-shadow.
8
+ // It's a hack. Not as good as a real bold font. Better than nothing.
9
+
10
+ defineFunction({
11
+ type: "pmb",
12
+ names: ["\\pmb"],
13
+ props: {
14
+ numArgs: 1,
15
+ allowedInText: true
16
+ },
17
+ handler({ parser }, args) {
18
+ return {
19
+ type: "pmb",
20
+ mode: parser.mode,
21
+ body: ordargument(args[0])
22
+ }
23
+ },
24
+ mathmlBuilder(group, style) {
25
+ const inner = mml.buildExpression(group.body, style)
26
+ // Wrap with an <mstyle> element.
27
+ const node = wrapWithMstyle(inner)
28
+ node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px")
29
+ return node
30
+ }
31
+ })
@@ -0,0 +1,68 @@
1
+ import defineFunction from "../defineFunction"
2
+ import { StyleLevel } from "../constants"
3
+ import mathMLTree from "../mathMLTree"
4
+ import { assertNodeType } from "../parseNode"
5
+ import { calculateSize } from "../units"
6
+ import * as mml from "../buildMathML"
7
+
8
+ const sign = num => num >= 0 ? "+" : "-"
9
+
10
+ // \raise, \lower, and \raisebox
11
+
12
+ const mathmlBuilder = (group, style) => {
13
+ const newStyle = style.withLevel(StyleLevel.TEXT)
14
+ const node = new mathMLTree.MathNode("mpadded", [mml.buildGroup(group.body, newStyle)])
15
+ const dy = calculateSize(group.dy, style)
16
+ node.setAttribute("voffset", dy.number + dy.unit)
17
+ const dyAbs = Math.abs(dy.number)
18
+ // The next two lines do not work in Chromium.
19
+ // TODO: Find some other way to adjust height and depth.
20
+ node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit)
21
+ node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit)
22
+ return node
23
+ }
24
+
25
+ defineFunction({
26
+ type: "raise",
27
+ names: ["\\raise", "\\lower"],
28
+ props: {
29
+ numArgs: 2,
30
+ argTypes: ["size", "primitive"],
31
+ primitive: true
32
+ },
33
+ handler({ parser, funcName }, args) {
34
+ const amount = assertNodeType(args[0], "size").value;
35
+ if (funcName === "\\lower") { amount.number *= -1 }
36
+ const body = args[1]
37
+ return {
38
+ type: "raise",
39
+ mode: parser.mode,
40
+ dy: amount,
41
+ body
42
+ };
43
+ },
44
+ mathmlBuilder
45
+ })
46
+
47
+
48
+ defineFunction({
49
+ type: "raise",
50
+ names: ["\\raisebox"],
51
+ props: {
52
+ numArgs: 2,
53
+ argTypes: ["size", "hbox"],
54
+ allowedInText: true
55
+ },
56
+ handler({ parser, funcName }, args) {
57
+ const amount = assertNodeType(args[0], "size").value
58
+ const body = args[1]
59
+ return {
60
+ type: "raise",
61
+ mode: parser.mode,
62
+ dy: amount,
63
+ body
64
+ };
65
+ },
66
+ mathmlBuilder
67
+ })
68
+