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,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
+ }