temml 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -0
- package/README.md +44 -0
- package/contrib/auto-render/README.md +89 -0
- package/contrib/auto-render/auto-render.js +128 -0
- package/contrib/auto-render/dist/auto-render.js +217 -0
- package/contrib/auto-render/dist/auto-render.min.js +1 -0
- package/contrib/auto-render/splitAtDelimiters.js +84 -0
- package/contrib/auto-render/test/auto-render-spec.js +234 -0
- package/contrib/auto-render/test/auto-render.js +217 -0
- package/contrib/auto-render/test/test_page.html +59 -0
- package/contrib/mhchem/README.md +26 -0
- package/contrib/mhchem/mhchem.js +1705 -0
- package/contrib/mhchem/mhchem.min.js +1 -0
- package/contrib/physics/README.md +20 -0
- package/contrib/physics/physics.js +131 -0
- package/contrib/texvc/README.md +23 -0
- package/contrib/texvc/texvc.js +61 -0
- package/dist/Temml-Asana.css +201 -0
- package/dist/Temml-Latin-Modern.css +216 -0
- package/dist/Temml-Libertinus.css +214 -0
- package/dist/Temml-Local.css +194 -0
- package/dist/Temml-STIX2.css +203 -0
- package/dist/Temml.woff2 +0 -0
- package/dist/temml.cjs +13122 -0
- package/dist/temml.js +11225 -0
- package/dist/temml.min.js +1 -0
- package/dist/temml.mjs +13120 -0
- package/dist/temmlPostProcess.js +70 -0
- package/package.json +34 -0
- package/src/Lexer.js +121 -0
- package/src/MacroExpander.js +437 -0
- package/src/Namespace.js +107 -0
- package/src/ParseError.js +64 -0
- package/src/Parser.js +977 -0
- package/src/Settings.js +49 -0
- package/src/SourceLocation.js +29 -0
- package/src/Style.js +144 -0
- package/src/Token.js +40 -0
- package/src/buildMathML.js +235 -0
- package/src/constants.js +25 -0
- package/src/defineEnvironment.js +25 -0
- package/src/defineFunction.js +69 -0
- package/src/defineMacro.js +11 -0
- package/src/domTree.js +185 -0
- package/src/environments/array.js +791 -0
- package/src/environments/cd.js +252 -0
- package/src/environments.js +8 -0
- package/src/functions/accent.js +127 -0
- package/src/functions/accentunder.js +38 -0
- package/src/functions/arrow.js +204 -0
- package/src/functions/cancelto.js +36 -0
- package/src/functions/char.js +33 -0
- package/src/functions/color.js +253 -0
- package/src/functions/cr.js +46 -0
- package/src/functions/def.js +259 -0
- package/src/functions/delimsizing.js +304 -0
- package/src/functions/enclose.js +193 -0
- package/src/functions/envTag.js +38 -0
- package/src/functions/environment.js +59 -0
- package/src/functions/font.js +123 -0
- package/src/functions/genfrac.js +333 -0
- package/src/functions/hbox.js +29 -0
- package/src/functions/horizBrace.js +32 -0
- package/src/functions/href.js +90 -0
- package/src/functions/html.js +95 -0
- package/src/functions/includegraphics.js +131 -0
- package/src/functions/kern.js +75 -0
- package/src/functions/label.js +29 -0
- package/src/functions/lap.js +75 -0
- package/src/functions/math.js +40 -0
- package/src/functions/mathchoice.js +41 -0
- package/src/functions/mclass.js +201 -0
- package/src/functions/multiscript.js +91 -0
- package/src/functions/not.js +46 -0
- package/src/functions/op.js +338 -0
- package/src/functions/operatorname.js +139 -0
- package/src/functions/ordgroup.js +9 -0
- package/src/functions/phantom.js +73 -0
- package/src/functions/pmb.js +31 -0
- package/src/functions/raise.js +68 -0
- package/src/functions/ref.js +28 -0
- package/src/functions/relax.js +16 -0
- package/src/functions/rule.js +52 -0
- package/src/functions/sizing.js +64 -0
- package/src/functions/smash.js +66 -0
- package/src/functions/sqrt.js +31 -0
- package/src/functions/styling.js +58 -0
- package/src/functions/supsub.js +135 -0
- package/src/functions/symbolsOp.js +53 -0
- package/src/functions/symbolsOrd.js +102 -0
- package/src/functions/symbolsSpacing.js +53 -0
- package/src/functions/tag.js +8 -0
- package/src/functions/text.js +75 -0
- package/src/functions/tip.js +63 -0
- package/src/functions/toggle.js +13 -0
- package/src/functions/verb.js +33 -0
- package/src/functions.js +57 -0
- package/src/linebreaking.js +159 -0
- package/src/macros.js +708 -0
- package/src/mathMLTree.js +175 -0
- package/src/parseNode.js +42 -0
- package/src/parseTree.js +40 -0
- package/src/postProcess.js +57 -0
- package/src/replace.js +225 -0
- package/src/stretchy.js +66 -0
- package/src/svg.js +110 -0
- package/src/symbols.js +972 -0
- package/src/tree.js +50 -0
- package/src/unicodeAccents.js +16 -0
- package/src/unicodeScripts.js +119 -0
- package/src/unicodeSupOrSub.js +108 -0
- package/src/unicodeSymbolBuilder.js +31 -0
- package/src/unicodeSymbols.js +320 -0
- package/src/units.js +109 -0
- package/src/utils.js +109 -0
- package/src/variant.js +103 -0
- 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
|
+
};
|
package/src/parseNode.js
ADDED
@@ -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
|
+
}
|
package/src/parseTree.js
ADDED
@@ -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
|
+
})
|
package/src/stretchy.js
ADDED
@@ -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
|
+
}
|