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