temml 0.9.1

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.
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,175 @@
1
+ //
2
+ /**
3
+ * These objects store data about MathML nodes.
4
+ * The `toNode` and `toMarkup` functions create namespaced DOM nodes and
5
+ * HTML text markup respectively.
6
+ */
7
+
8
+ import utils from "./utils";
9
+ import { DocumentFragment } from "./tree";
10
+ import { createClass } from "./domTree";
11
+
12
+ export function newDocumentFragment(children) {
13
+ return new DocumentFragment(children);
14
+ }
15
+
16
+ /**
17
+ * This node represents a general purpose MathML node of any type,
18
+ * for example, `"mo"` or `"mspace"`, corresponding to `<mo>` and
19
+ * `<mspace>` tags).
20
+ */
21
+ export class MathNode {
22
+ constructor(type, children, classes, style) {
23
+ this.type = type;
24
+ this.attributes = {};
25
+ this.children = children || [];
26
+ this.classes = classes || [];
27
+ this.style = style || {}; // Used for <mstyle> elements
28
+ }
29
+
30
+ /**
31
+ * Sets an attribute on a MathML node. MathML depends on attributes to convey a
32
+ * semantic content, so this is used heavily.
33
+ */
34
+ setAttribute(name, value) {
35
+ this.attributes[name] = value;
36
+ }
37
+
38
+ /**
39
+ * Gets an attribute on a MathML node.
40
+ */
41
+ getAttribute(name) {
42
+ return this.attributes[name];
43
+ }
44
+
45
+ /**
46
+ * Converts the math node into a MathML-namespaced DOM element.
47
+ */
48
+ toNode() {
49
+ const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type);
50
+
51
+ for (const attr in this.attributes) {
52
+ if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
53
+ node.setAttribute(attr, this.attributes[attr]);
54
+ }
55
+ }
56
+
57
+ if (this.classes.length > 0) {
58
+ node.className = createClass(this.classes);
59
+ }
60
+
61
+ // Apply inline styles
62
+ for (const style in this.style) {
63
+ if (Object.prototype.hasOwnProperty.call(this.style, style )) {
64
+ node.style[style] = this.style[style];
65
+ }
66
+ }
67
+
68
+ for (let i = 0; i < this.children.length; i++) {
69
+ node.appendChild(this.children[i].toNode());
70
+ }
71
+
72
+ return node;
73
+ }
74
+
75
+ /**
76
+ * Converts the math node into an HTML markup string.
77
+ */
78
+ toMarkup() {
79
+ let markup = "<" + this.type;
80
+
81
+ // Add the attributes
82
+ for (const attr in this.attributes) {
83
+ if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
84
+ markup += " " + attr + '="';
85
+ markup += utils.escape(this.attributes[attr]);
86
+ markup += '"';
87
+ }
88
+ }
89
+
90
+ if (this.classes.length > 0) {
91
+ markup += ` class="${utils.escape(createClass(this.classes))}"`;
92
+ }
93
+
94
+ let styles = "";
95
+
96
+ // Add the styles, after hyphenation
97
+ for (const style in this.style) {
98
+ if (Object.prototype.hasOwnProperty.call(this.style, style )) {
99
+ styles += `${utils.hyphenate(style)}:${this.style[style]};`;
100
+ }
101
+ }
102
+
103
+ if (styles) {
104
+ markup += ` style="${styles}"`;
105
+ }
106
+
107
+ markup += ">";
108
+
109
+ for (let i = 0; i < this.children.length; i++) {
110
+ markup += this.children[i].toMarkup();
111
+ }
112
+
113
+ markup += "</" + this.type + ">";
114
+
115
+ return markup;
116
+ }
117
+
118
+ /**
119
+ * Converts the math node into a string, similar to innerText, but escaped.
120
+ */
121
+ toText() {
122
+ return this.children.map((child) => child.toText()).join("");
123
+ }
124
+ }
125
+
126
+ /**
127
+ * This node represents a piece of text.
128
+ */
129
+ export class TextNode {
130
+ constructor(text) {
131
+ this.text = text;
132
+ }
133
+
134
+ /**
135
+ * Converts the text node into a DOM text node.
136
+ */
137
+ toNode() {
138
+ return document.createTextNode(this.text);
139
+ }
140
+
141
+ /**
142
+ * Converts the text node into escaped HTML markup
143
+ * (representing the text itself).
144
+ */
145
+ toMarkup() {
146
+ return utils.escape(this.toText());
147
+ }
148
+
149
+ /**
150
+ * Converts the text node into a string
151
+ * (representing the text iteself).
152
+ */
153
+ toText() {
154
+ return this.text;
155
+ }
156
+ }
157
+
158
+ // Do not make an <mrow> the only child of a <mstyle>.
159
+ // An <mstyle> acts as its own implicit <mrow>.
160
+ export const wrapWithMstyle = expression => {
161
+ let node
162
+ if (expression.length === 1 && expression[0].type === "mrow") {
163
+ node = expression.pop()
164
+ node.type = "mstyle"
165
+ } else {
166
+ node = new MathNode("mstyle", expression);
167
+ }
168
+ return node
169
+ }
170
+
171
+ export default {
172
+ MathNode,
173
+ TextNode,
174
+ newDocumentFragment
175
+ };
@@ -0,0 +1,42 @@
1
+ import { NON_ATOMS } from "./symbols";
2
+
3
+ /**
4
+ * Asserts that the node is of the given type and returns it with stricter
5
+ * typing. Throws if the node's type does not match.
6
+ */
7
+ export function assertNodeType(node, type) {
8
+ if (!node || node.type !== type) {
9
+ throw new Error(
10
+ `Expected node of type ${type}, but got ` +
11
+ (node ? `node of type ${node.type}` : String(node))
12
+ );
13
+ }
14
+ return node;
15
+ }
16
+
17
+ /**
18
+ * Returns the node more strictly typed iff it is of the given type. Otherwise,
19
+ * returns null.
20
+ */
21
+ export function assertSymbolNodeType(node) {
22
+ const typedNode = checkSymbolNodeType(node);
23
+ if (!typedNode) {
24
+ throw new Error(
25
+ `Expected node of symbol group type, but got ` +
26
+ (node ? `node of type ${node.type}` : String(node))
27
+ );
28
+ }
29
+ return typedNode;
30
+ }
31
+
32
+ /**
33
+ * Returns the node more strictly typed iff it is of the given type. Otherwise,
34
+ * returns null.
35
+ */
36
+ export function checkSymbolNodeType(node) {
37
+ if (node && (node.type === "atom" ||
38
+ Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) {
39
+ return node;
40
+ }
41
+ return null;
42
+ }
@@ -0,0 +1,40 @@
1
+ import Parser from "./Parser"
2
+ import ParseError from "./ParseError"
3
+
4
+ /**
5
+ * Parses an expression using a Parser, then returns the parsed result.
6
+ */
7
+ const parseTree = function(toParse, settings) {
8
+ if (!(typeof toParse === "string" || toParse instanceof String)) {
9
+ throw new TypeError("Temml can only parse string typed expression")
10
+ }
11
+ const parser = new Parser(toParse, settings)
12
+ // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
13
+ delete parser.gullet.macros.current["\\df@tag"]
14
+
15
+ let tree = parser.parse()
16
+
17
+ // LaTeX ignores a \tag placed outside an AMS environment.
18
+ if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) {
19
+ // If the input used \tag, it will set the \df@tag macro to the tag.
20
+ // In this case, we separately parse the tag and wrap the tree.
21
+ if (parser.gullet.macros.get("\\df@tag")) {
22
+ if (!settings.displayMode) {
23
+ throw new ParseError("\\tag works only in display mode")
24
+ }
25
+ parser.gullet.feed("\\df@tag")
26
+ tree = [
27
+ {
28
+ type: "tag",
29
+ mode: "text",
30
+ body: tree,
31
+ tag: parser.parse()
32
+ }
33
+ ]
34
+ }
35
+ }
36
+
37
+ return tree
38
+ }
39
+
40
+ export default parseTree
@@ -0,0 +1,57 @@
1
+ /* Temml Post Process
2
+ * Perform two tasks not done by Temml when it created each individual Temml <math> element.
3
+ * Given a block,
4
+ * 1. At each AMS auto-numbered environment, assign an id.
5
+ * 2. Populate the text contents of each \ref & \eqref
6
+ *
7
+ * As with other Temml code, this file is released under terms of the MIT license.
8
+ * https://mit-license.org/
9
+ */
10
+
11
+ export const version = "0.9.1";
12
+
13
+ export function postProcess(block) {
14
+ const labelMap = {}
15
+ let i = 0
16
+
17
+ // Get a collection of the parents of each \tag & auto-numbered equation
18
+ const parents = block.getElementsByClassName("tml-tageqn");
19
+ for (const parent of parents) {
20
+ const eqns = parent.getElementsByClassName("tml-eqn")
21
+ if (eqns. length > 0 ) {
22
+ // AMS automatically numbered equation.
23
+ // Assign an id.
24
+ i += 1;
25
+ eqns[0].id = "tml-eqn-" + i
26
+ // No need to write a number into the text content of the element.
27
+ // A CSS counter does that even if this postProcess() function is not used.
28
+ }
29
+ // If there is a \label, add it to labelMap
30
+ const labels = parent.getElementsByClassName("tml-label")
31
+ if (labels.length === 0) { continue }
32
+ if (eqns.length > 0) {
33
+ labelMap[labels[0].id] = String(i)
34
+ } else {
35
+ const tags = parent.getElementsByClassName("tml-tag")
36
+ if (tags.length > 0) {
37
+ labelMap[labels[0].id] = tags[0].textContent
38
+ }
39
+ }
40
+ }
41
+
42
+ // Populate \ref & \eqref text content
43
+ const refs = block.getElementsByClassName("tml-ref");
44
+ [...refs].forEach(ref => {
45
+ let str = labelMap[ref.getAttribute("href").slice(1)];
46
+ if (ref.className.indexOf("tml-eqref") === -1) {
47
+ // \ref. Omit parens.
48
+ str = str.replace(/^\(/, "")
49
+ str = str.replace(/\($/, "")
50
+ } {
51
+ // \eqref. Include parens
52
+ if (str.charAt(0) !== "(") { str = "(" + str }
53
+ if (str.slice(-1) !== ")") { str = str + ")" }
54
+ }
55
+ ref.textContent = str
56
+ })
57
+ }
package/src/replace.js ADDED
@@ -0,0 +1,225 @@
1
+ // Chromium does not support the MathML `mathvariant` attribute.
2
+ // Instead, we replace ASCII characters with Unicode characters that
3
+ // are defined in the font as bold, italic, double-struck, etc.
4
+ // This module identifies those Unicode code points.
5
+
6
+ // First, a few helpers.
7
+ const script = Object.freeze({
8
+ B: 0x20EA, // Offset from ASCII B to Unicode script B
9
+ E: 0x20EB,
10
+ F: 0x20EB,
11
+ H: 0x20C3,
12
+ I: 0x20C7,
13
+ L: 0x20C6,
14
+ M: 0x20E6,
15
+ R: 0x20C9,
16
+ e: 0x20CA,
17
+ g: 0x20A3,
18
+ o: 0x20C5
19
+ })
20
+
21
+ const frak = Object.freeze({
22
+ C: 0x20EA,
23
+ H: 0x20C4,
24
+ I: 0x20C8,
25
+ R: 0x20CA,
26
+ Z: 0x20CE
27
+ })
28
+
29
+ const bbb = Object.freeze({
30
+ C: 0x20BF, // blackboard bold
31
+ H: 0x20C5,
32
+ N: 0x20C7,
33
+ P: 0x20C9,
34
+ Q: 0x20C9,
35
+ R: 0x20CB,
36
+ Z: 0x20CA
37
+ })
38
+
39
+ const bold = Object.freeze({
40
+ "\u03f5": 0x1D2E7, // lunate epsilon
41
+ "\u03d1": 0x1D30C, // vartheta
42
+ "\u03f0": 0x1D2EE, // varkappa
43
+ "\u03c6": 0x1D319, // varphi
44
+ "\u03f1": 0x1D2EF, // varrho
45
+ "\u03d6": 0x1D30B // varpi
46
+ })
47
+
48
+ const boldItalic = Object.freeze({
49
+ "\u03f5": 0x1D35B, // lunate epsilon
50
+ "\u03d1": 0x1D380, // vartheta
51
+ "\u03f0": 0x1D362, // varkappa
52
+ "\u03c6": 0x1D38D, // varphi
53
+ "\u03f1": 0x1D363, // varrho
54
+ "\u03d6": 0x1D37F // varpi
55
+ })
56
+
57
+ const boldsf = Object.freeze({
58
+ "\u03f5": 0x1D395, // lunate epsilon
59
+ "\u03d1": 0x1D3BA, // vartheta
60
+ "\u03f0": 0x1D39C, // varkappa
61
+ "\u03c6": 0x1D3C7, // varphi
62
+ "\u03f1": 0x1D39D, // varrho
63
+ "\u03d6": 0x1D3B9 // varpi
64
+ })
65
+
66
+ const bisf = Object.freeze({
67
+ "\u03f5": 0x1D3CF, // lunate epsilon
68
+ "\u03d1": 0x1D3F4, // vartheta
69
+ "\u03f0": 0x1D3D6, // varkappa
70
+ "\u03c6": 0x1D401, // varphi
71
+ "\u03f1": 0x1D3D7, // varrho
72
+ "\u03d6": 0x1D3F3 // varpi
73
+ })
74
+
75
+ // Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf
76
+ const offset = Object.freeze({
77
+ upperCaseLatin: { // A-Z
78
+ "normal": ch => { return 0 },
79
+ "bold": ch => { return 0x1D3BF },
80
+ "italic": ch => { return 0x1D3F3 },
81
+ "bold-italic": ch => { return 0x1D427 },
82
+ "script": ch => { return script[ch] || 0x1D45B },
83
+ "script-bold": ch => { return 0x1D48F },
84
+ "fraktur": ch => { return frak[ch] || 0x1D4C3 },
85
+ "fraktur-bold": ch => { return 0x1D52B },
86
+ "double-struck": ch => { return bbb[ch] || 0x1D4F7 },
87
+ "sans-serif": ch => { return 0x1D55F },
88
+ "sans-serif-bold": ch => { return 0x1D593 },
89
+ "sans-serif-italic": ch => { return 0x1D5C7 },
90
+ "sans-serif-bold-italic": ch => { return 0x1D63C },
91
+ "monospace": ch => { return 0x1D62F }
92
+ },
93
+ lowerCaseLatin: { // a-z
94
+ "normal": ch => { return 0 },
95
+ "bold": ch => { return 0x1D3B9 },
96
+ "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED },
97
+ "bold-italic": ch => { return 0x1D421 },
98
+ "script": ch => { return script[ch] || 0x1D455 },
99
+ "script-bold": ch => { return 0x1D489 },
100
+ "fraktur": ch => { return 0x1D4BD },
101
+ "fraktur-bold": ch => { return 0x1D525 },
102
+ "double-struck": ch => { return 0x1D4F1 },
103
+ "sans-serif": ch => { return 0x1D559 },
104
+ "sans-serif-bold": ch => { return 0x1D58D },
105
+ "sans-serif-italic": ch => { return 0x1D5C1 },
106
+ "sans-serif-bold-italic": ch => { return 0x1D5F5 },
107
+ "monospace": ch => { return 0x1D629 }
108
+ },
109
+ upperCaseGreek: { // A-Ω ∇
110
+ "normal": ch => { return 0 },
111
+ "bold": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 },
112
+ "italic": ch => { return ch === "∇" ? 0x1B4F4 : 0x1D351 },
113
+ // \boldsymbol actually returns upright bold for upperCaseGreek
114
+ "bold-italic": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 },
115
+ "script": ch => { return 0 },
116
+ "script-bold": ch => { return 0 },
117
+ "fraktur": ch => { return 0 },
118
+ "fraktur-bold": ch => { return 0 },
119
+ "double-struck": ch => { return 0 },
120
+ // Unicode has no code points for regular-weight san-serif Greek. Use bold.
121
+ "sans-serif": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 },
122
+ "sans-serif-bold": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 },
123
+ "sans-serif-italic": ch => { return 0 },
124
+ "sans-serif-bold-italic": ch => { return ch === "∇" ? 0x1B5A2 : 0x1D3FF },
125
+ "monospace": ch => { return 0 }
126
+ },
127
+ lowerCaseGreek: { // α-ω
128
+ "normal": ch => { return 0 },
129
+ "bold": ch => { return 0x1D311 },
130
+ "italic": ch => { return 0x1D34B },
131
+ "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 },
132
+ "script": ch => { return 0 },
133
+ "script-bold": ch => { return 0 },
134
+ "fraktur": ch => { return 0 },
135
+ "fraktur-bold": ch => { return 0 },
136
+ "double-struck": ch => { return 0 },
137
+ // Unicode has no code points for regular-weight san-serif Greek. Use bold.
138
+ "sans-serif": ch => { return 0x1D3BF },
139
+ "sans-serif-bold": ch => { return 0x1D3BF },
140
+ "sans-serif-italic": ch => { return 0 },
141
+ "sans-serif-bold-italic": ch => { return 0x1D3F9 },
142
+ "monospace": ch => { return 0 }
143
+ },
144
+ varGreek: { // \varGamma, etc
145
+ "normal": ch => { return 0 },
146
+ "bold": ch => { return bold[ch] || -51 },
147
+ "italic": ch => { return 0 },
148
+ "bold-italic": ch => { return boldItalic[ch] || 0x3A },
149
+ "script": ch => { return 0 },
150
+ "script-bold": ch => { return 0 },
151
+ "fraktur": ch => { return 0 },
152
+ "fraktur-bold": ch => { return 0 },
153
+ "double-struck": ch => { return 0 },
154
+ "sans-serif": ch => { return boldsf[ch] || 0x74 },
155
+ "sans-serif-bold": ch => { return boldsf[ch] || 0x74 },
156
+ "sans-serif-italic": ch => { return 0 },
157
+ "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE },
158
+ "monospace": ch => { return 0 }
159
+ },
160
+ numeral: { // 0-9
161
+ "normal": ch => { return 0 },
162
+ "bold": ch => { return 0x1D79E },
163
+ "italic": ch => { return 0 },
164
+ "bold-italic": ch => { return 0 },
165
+ "script": ch => { return 0 },
166
+ "script-bold": ch => { return 0 },
167
+ "fraktur": ch => { return 0 },
168
+ "fraktur-bold": ch => { return 0 },
169
+ "double-struck": ch => { return 0x1D7A8 },
170
+ "sans-serif": ch => { return 0x1D7B2 },
171
+ "sans-serif-bold": ch => { return 0x1D7BC },
172
+ "sans-serif-italic": ch => { return 0 },
173
+ "sans-serif-bold-italic": ch => { return 0 },
174
+ "monospace": ch => { return 0x1D7C6 }
175
+ }
176
+ })
177
+
178
+ export const variantChar = (ch, variant) => {
179
+ const codePoint = ch.codePointAt(0)
180
+ const block = 0x40 < codePoint && codePoint < 0x5b
181
+ ? "upperCaseLatin"
182
+ : 0x60 < codePoint && codePoint < 0x7b
183
+ ? "lowerCaseLatin"
184
+ : (0x390 < codePoint && codePoint < 0x3AA) || ch === "∇"
185
+ ? "upperCaseGreek"
186
+ : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5"
187
+ ? "lowerCaseGreek"
188
+ : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch]
189
+ ? "varGreek"
190
+ : (0x2F < codePoint && codePoint < 0x3A)
191
+ ? "numeral"
192
+ : "other"
193
+ return block === "other"
194
+ ? ch
195
+ : String.fromCodePoint(codePoint + offset[block][variant](ch))
196
+ }
197
+
198
+ export const smallCaps = Object.freeze({
199
+ a: "ᴀ",
200
+ b: "ʙ",
201
+ c: "ᴄ",
202
+ d: "ᴅ",
203
+ e: "ᴇ",
204
+ f: "ꜰ",
205
+ g: "ɢ",
206
+ h: "ʜ",
207
+ i: "ɪ",
208
+ j: "ᴊ",
209
+ k: "ᴋ",
210
+ l: "ʟ",
211
+ m: "ᴍ",
212
+ n: "ɴ",
213
+ o: "ᴏ",
214
+ p: "ᴘ",
215
+ q: "ǫ",
216
+ r: "ʀ",
217
+ s: "s",
218
+ t: "ᴛ",
219
+ u: "ᴜ",
220
+ v: "ᴠ",
221
+ w: "ᴡ",
222
+ x: "x",
223
+ y: "ʏ",
224
+ z: "ᴢ"
225
+ })
@@ -0,0 +1,66 @@
1
+ /**
2
+ * This file provides support for building horizontal stretchy elements.
3
+ */
4
+
5
+ import mathMLTree from "./mathMLTree"
6
+
7
+ const stretchyCodePoint = {
8
+ widehat: "^",
9
+ widecheck: "ˇ",
10
+ widetilde: "~",
11
+ wideparen: "⏜", // \u23dc
12
+ utilde: "~",
13
+ overleftarrow: "\u2190",
14
+ underleftarrow: "\u2190",
15
+ xleftarrow: "\u2190",
16
+ overrightarrow: "\u2192",
17
+ underrightarrow: "\u2192",
18
+ xrightarrow: "\u2192",
19
+ underbrace: "\u23df",
20
+ overbrace: "\u23de",
21
+ overgroup: "\u23e0",
22
+ overparen: "⏜",
23
+ undergroup: "\u23e1",
24
+ underparen: "\u23dd",
25
+ overleftrightarrow: "\u2194",
26
+ underleftrightarrow: "\u2194",
27
+ xleftrightarrow: "\u2194",
28
+ Overrightarrow: "\u21d2",
29
+ xRightarrow: "\u21d2",
30
+ overleftharpoon: "\u21bc",
31
+ xleftharpoonup: "\u21bc",
32
+ overrightharpoon: "\u21c0",
33
+ xrightharpoonup: "\u21c0",
34
+ xLeftarrow: "\u21d0",
35
+ xLeftrightarrow: "\u21d4",
36
+ xhookleftarrow: "\u21a9",
37
+ xhookrightarrow: "\u21aa",
38
+ xmapsto: "\u21a6",
39
+ xrightharpoondown: "\u21c1",
40
+ xleftharpoondown: "\u21bd",
41
+ xtwoheadleftarrow: "\u219e",
42
+ xtwoheadrightarrow: "\u21a0",
43
+ xlongequal: "=",
44
+ xrightleftarrows: "\u21c4",
45
+ yields: "\u2192",
46
+ yieldsLeft: "\u2190",
47
+ mesomerism: "\u2194",
48
+ longrightharpoonup: "\u21c0",
49
+ longleftharpoondown: "\u21bd",
50
+ eqrightharpoonup: "\u21c0",
51
+ eqleftharpoondown: "\u21bd",
52
+ "\\cdrightarrow": "\u2192",
53
+ "\\cdleftarrow": "\u2190",
54
+ "\\cdlongequal": "="
55
+ }
56
+
57
+ const mathMLnode = function(label) {
58
+ const child = new mathMLTree.TextNode(stretchyCodePoint[label.slice(1)])
59
+ const node = new mathMLTree.MathNode("mo", [child])
60
+ node.setAttribute("stretchy", "true")
61
+ return node
62
+ }
63
+
64
+ export default {
65
+ mathMLnode
66
+ }