@pie-lib/math-input-mathlive 1.1.5-beta.8 → 2.0.1-next.20261107131445
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/README.md +84 -109
- package/dist/_virtual/_rolldown/runtime.js +11 -0
- package/dist/horizontal-keypad.d.ts +22 -0
- package/dist/horizontal-keypad.js +54 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +12 -0
- package/dist/keypad/index.d.ts +40 -0
- package/dist/keypad/index.js +245 -0
- package/dist/keypad/keys-layout.d.ts +7 -0
- package/dist/keypad/keys-layout.js +5 -0
- package/dist/keys/basic-operators.d.ts +5 -0
- package/dist/keys/basic-operators.js +30 -0
- package/dist/keys/chars.d.ts +5 -0
- package/dist/keys/comparison.d.ts +4 -0
- package/dist/keys/comparison.js +32 -0
- package/dist/keys/constants.d.ts +4 -0
- package/dist/keys/constants.js +35 -0
- package/dist/keys/digits.d.ts +15 -0
- package/dist/keys/digits.js +34 -0
- package/dist/keys/edit.d.ts +6 -0
- package/dist/keys/edit.js +9 -0
- package/dist/keys/exponent.d.ts +4 -0
- package/dist/keys/exponent.js +28 -0
- package/dist/keys/fractions.d.ts +3 -0
- package/dist/keys/fractions.js +27 -0
- package/dist/keys/geometry.d.ts +23 -0
- package/dist/keys/geometry.js +127 -0
- package/dist/keys/grades.d.ts +9 -0
- package/dist/keys/grades.js +414 -0
- package/dist/keys/index.d.ts +6 -0
- package/dist/keys/index.js +50 -0
- package/dist/keys/log.d.ts +3 -0
- package/dist/keys/log.js +25 -0
- package/dist/keys/logic.d.ts +2 -0
- package/dist/keys/logic.js +13 -0
- package/dist/keys/matrices.d.ts +2 -0
- package/dist/keys/matrices.js +17 -0
- package/dist/keys/misc.d.ts +10 -0
- package/dist/keys/misc.js +60 -0
- package/dist/keys/navigation.d.ts +2 -0
- package/dist/keys/navigation.js +13 -0
- package/dist/keys/operators.d.ts +1 -0
- package/dist/keys/operators.js +11 -0
- package/dist/keys/statistics.d.ts +5 -0
- package/dist/keys/statistics.js +38 -0
- package/dist/keys/sub-sup.d.ts +2 -0
- package/dist/keys/sub-sup.js +17 -0
- package/dist/keys/trigonometry.d.ts +6 -0
- package/dist/keys/trigonometry.js +43 -0
- package/dist/keys/utils.d.ts +5 -0
- package/dist/keys/utils.js +24 -0
- package/dist/keys/vars.d.ts +3 -0
- package/dist/keys/vars.js +22 -0
- package/dist/latex-bridge.d.ts +197 -0
- package/dist/latex-bridge.js +210 -0
- package/dist/longdiv.d.ts +24 -0
- package/dist/longdiv.js +43 -0
- package/dist/math-input.d.ts +26 -0
- package/dist/math-input.js +74 -0
- package/dist/mathlive-instance.d.ts +221 -0
- package/dist/mathlive-instance.js +159 -0
- package/dist/mf/common-styles.d.ts +594 -0
- package/dist/mf/common-styles.js +80 -0
- package/dist/mf/field-label.d.ts +16 -0
- package/dist/mf/field-label.js +13 -0
- package/dist/mf/index.d.ts +4 -0
- package/dist/mf/index.js +21 -0
- package/dist/mf/input.d.ts +94 -0
- package/dist/mf/input.js +127 -0
- package/dist/mf/static.d.ts +143 -0
- package/dist/mf/static.js +230 -0
- package/dist/selection.d.ts +43 -0
- package/dist/selection.js +39 -0
- package/package.json +32 -18
- package/lib/__tests__/composites.test.js +0 -255
- package/lib/__tests__/drop-in-compat.test.js +0 -133
- package/lib/__tests__/embedded-fonts.test.js +0 -121
- package/lib/__tests__/index.test.js +0 -118
- package/lib/__tests__/input-imperative.test.js +0 -155
- package/lib/__tests__/input-selection.test.js +0 -103
- package/lib/__tests__/keypad-label.test.js +0 -231
- package/lib/__tests__/keypad-render.test.js +0 -206
- package/lib/__tests__/latex-bridge.test.js +0 -386
- package/lib/__tests__/mathlive-instance.test.js +0 -419
- package/lib/__tests__/mount-race.test.js +0 -218
- package/lib/__tests__/selection.test.js +0 -195
- package/lib/__tests__/static-prompts.test.js +0 -405
- package/lib/__tests__/tmp-markup.test.js +0 -26
- package/lib/horizontal-keypad.js +0 -101
- package/lib/horizontal-keypad.js.map +0 -1
- package/lib/index.js +0 -143
- package/lib/index.js.map +0 -1
- package/lib/keypad/index.js +0 -431
- package/lib/keypad/index.js.map +0 -1
- package/lib/keypad/keys-layout.js +0 -22
- package/lib/keypad/keys-layout.js.map +0 -1
- package/lib/keys/basic-operators.js +0 -33
- package/lib/keys/basic-operators.js.map +0 -1
- package/lib/keys/chars.js +0 -12
- package/lib/keys/chars.js.map +0 -1
- package/lib/keys/comparison.js +0 -39
- package/lib/keys/comparison.js.map +0 -1
- package/lib/keys/constants.js +0 -37
- package/lib/keys/constants.js.map +0 -1
- package/lib/keys/digits.js +0 -46
- package/lib/keys/digits.js.map +0 -1
- package/lib/keys/edit.js +0 -14
- package/lib/keys/edit.js.map +0 -1
- package/lib/keys/exponent.js +0 -30
- package/lib/keys/exponent.js.map +0 -1
- package/lib/keys/fractions.js +0 -29
- package/lib/keys/fractions.js.map +0 -1
- package/lib/keys/geometry.js +0 -143
- package/lib/keys/geometry.js.map +0 -1
- package/lib/keys/grades.js +0 -259
- package/lib/keys/grades.js.map +0 -1
- package/lib/keys/index.js +0 -35
- package/lib/keys/index.js.map +0 -1
- package/lib/keys/log.js +0 -27
- package/lib/keys/log.js.map +0 -1
- package/lib/keys/logic.js +0 -19
- package/lib/keys/logic.js.map +0 -1
- package/lib/keys/matrices.js +0 -19
- package/lib/keys/matrices.js.map +0 -1
- package/lib/keys/misc.js +0 -69
- package/lib/keys/misc.js.map +0 -1
- package/lib/keys/navigation.js +0 -20
- package/lib/keys/navigation.js.map +0 -1
- package/lib/keys/operators.js +0 -15
- package/lib/keys/operators.js.map +0 -1
- package/lib/keys/statistics.js +0 -40
- package/lib/keys/statistics.js.map +0 -1
- package/lib/keys/sub-sup.js +0 -19
- package/lib/keys/sub-sup.js.map +0 -1
- package/lib/keys/trigonometry.js +0 -45
- package/lib/keys/trigonometry.js.map +0 -1
- package/lib/keys/utils.js +0 -87
- package/lib/keys/utils.js.map +0 -1
- package/lib/keys/vars.js +0 -24
- package/lib/keys/vars.js.map +0 -1
- package/lib/latex-bridge.js +0 -445
- package/lib/latex-bridge.js.map +0 -1
- package/lib/math-input.js +0 -143
- package/lib/math-input.js.map +0 -1
- package/lib/mathlive-instance.js +0 -585
- package/lib/mathlive-instance.js.map +0 -1
- package/lib/mf/common-styles.js +0 -203
- package/lib/mf/common-styles.js.map +0 -1
- package/lib/mf/index.js +0 -84
- package/lib/mf/index.js.map +0 -1
- package/lib/mf/input.js +0 -372
- package/lib/mf/input.js.map +0 -1
- package/lib/mf/static.js +0 -500
- package/lib/mf/static.js.map +0 -1
- package/lib/selection.js +0 -148
- package/lib/selection.js.map +0 -1
- package/src/__tests__/composites.test.jsx +0 -220
- package/src/__tests__/drop-in-compat.test.jsx +0 -112
- package/src/__tests__/index.test.jsx +0 -109
- package/src/__tests__/input-imperative.test.jsx +0 -144
- package/src/__tests__/input-selection.test.jsx +0 -64
- package/src/__tests__/keypad-label.test.jsx +0 -283
- package/src/__tests__/keypad-render.test.jsx +0 -123
- package/src/__tests__/latex-bridge.test.js +0 -359
- package/src/__tests__/mathlive-instance.test.js +0 -418
- package/src/__tests__/mount-race.test.jsx +0 -142
- package/src/__tests__/selection.test.js +0 -212
- package/src/__tests__/static-prompts.test.jsx +0 -364
- package/src/horizontal-keypad.jsx +0 -73
- package/src/index.jsx +0 -63
- package/src/keypad/index.jsx +0 -386
- package/src/keypad/keys-layout.js +0 -16
- package/src/keys/basic-operators.js +0 -32
- package/src/keys/chars.js +0 -5
- package/src/keys/comparison.js +0 -28
- package/src/keys/constants.js +0 -35
- package/src/keys/digits.js +0 -40
- package/src/keys/edit.js +0 -3
- package/src/keys/exponent.js +0 -28
- package/src/keys/fractions.js +0 -26
- package/src/keys/geometry.js +0 -149
- package/src/keys/grades.js +0 -367
- package/src/keys/index.js +0 -20
- package/src/keys/log.js +0 -22
- package/src/keys/logic.js +0 -15
- package/src/keys/matrices.js +0 -15
- package/src/keys/misc.js +0 -71
- package/src/keys/navigation.js +0 -8
- package/src/keys/operators.js +0 -10
- package/src/keys/statistics.js +0 -38
- package/src/keys/sub-sup.js +0 -15
- package/src/keys/trigonometry.js +0 -15
- package/src/keys/utils.js +0 -66
- package/src/keys/vars.js +0 -19
- package/src/latex-bridge.js +0 -449
- package/src/math-input.jsx +0 -115
- package/src/mathlive-instance.js +0 -582
- package/src/mf/common-styles.js +0 -210
- package/src/mf/index.js +0 -30
- package/src/mf/input.jsx +0 -328
- package/src/mf/static.jsx +0 -479
- package/src/selection.js +0 -146
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
toMathLive,
|
|
3
|
-
fromMathLive,
|
|
4
|
-
fieldIds,
|
|
5
|
-
keyToAction,
|
|
6
|
-
toNativeCommands,
|
|
7
|
-
toCanonicalCommands,
|
|
8
|
-
MATHQUILL_ALIASES,
|
|
9
|
-
NEWLINE_EMBED,
|
|
10
|
-
DEFAULT_FIELD_ID,
|
|
11
|
-
} from '../latex-bridge';
|
|
12
|
-
|
|
13
|
-
describe('latex-bridge', () => {
|
|
14
|
-
describe('toMathLive', () => {
|
|
15
|
-
it('passes plain latex through', () => {
|
|
16
|
-
expect(toMathLive('\\frac{1}{2}')).toEqual('\\frac{1}{2}');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('handles empty/nullish', () => {
|
|
20
|
-
expect(toMathLive('')).toEqual('');
|
|
21
|
-
expect(toMathLive(undefined)).toEqual('');
|
|
22
|
-
expect(toMathLive(null)).toEqual('');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('converts a newLine embed to a multiline environment', () => {
|
|
26
|
-
expect(toMathLive(`a${NEWLINE_EMBED}b`)).toEqual('\\displaylines{a \\\\ b}');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('converts multiple newLine embeds', () => {
|
|
30
|
-
expect(toMathLive(`a${NEWLINE_EMBED}b${NEWLINE_EMBED}c`)).toEqual('\\displaylines{a \\\\ b \\\\ c}');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('converts MathQuill answer blocks to placeholders', () => {
|
|
34
|
-
expect(toMathLive('x=\\MathQuillMathField[r1]{}')).toEqual('x=\\placeholder[r1]{}');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('preserves answer block content', () => {
|
|
38
|
-
expect(toMathLive('\\MathQuillMathField[r2]{7}')).toEqual('\\placeholder[r2]{7}');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('defaults an unnamed answer block id', () => {
|
|
42
|
-
expect(toMathLive('\\MathQuillMathField[]{}')).toEqual(`\\placeholder[${DEFAULT_FIELD_ID}]{}`);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('handles answer blocks and newlines together', () => {
|
|
46
|
-
expect(toMathLive(`\\MathQuillMathField[r1]{}${NEWLINE_EMBED}x`)).toEqual(
|
|
47
|
-
'\\displaylines{\\placeholder[r1]{} \\\\ x}',
|
|
48
|
-
);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('fromMathLive', () => {
|
|
53
|
-
it('passes plain latex through', () => {
|
|
54
|
-
expect(fromMathLive('\\frac{1}{2}')).toEqual('\\frac{1}{2}');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('unwraps displaylines back to newLine embeds', () => {
|
|
58
|
-
expect(fromMathLive('\\displaylines{a \\\\ b}')).toEqual(`a${NEWLINE_EMBED}b`);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('converts placeholders back to MathQuill answer blocks', () => {
|
|
62
|
-
expect(fromMathLive('x=\\placeholder[r1]{}')).toEqual('x=\\MathQuillMathField[r1]{}');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('round-trips a newline document', () => {
|
|
66
|
-
const stored = `a${NEWLINE_EMBED}b${NEWLINE_EMBED}c`;
|
|
67
|
-
|
|
68
|
-
expect(fromMathLive(toMathLive(stored))).toEqual(stored);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('round-trips an answer-block document', () => {
|
|
72
|
-
const stored = 'x=\\MathQuillMathField[r1]{}+\\MathQuillMathField[r2]{3}';
|
|
73
|
-
|
|
74
|
-
expect(fromMathLive(toMathLive(stored))).toEqual(stored);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// MathLive serialises empty slots as \placeholder{}, which MathJax (used by
|
|
78
|
-
// @pie-lib/math-rendering for prompts/previews) renders as red error text.
|
|
79
|
-
it('strips unnamed placeholders that MathLive adds', () => {
|
|
80
|
-
expect(fromMathLive('\\longdiv{\\placeholder{}}')).toEqual('\\longdiv{}');
|
|
81
|
-
expect(fromMathLive('\\frac{\\placeholder{}}{\\placeholder{}}')).toEqual('\\frac{}{}');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('keeps content inside an unnamed placeholder', () => {
|
|
85
|
-
expect(fromMathLive('\\sqrt{\\placeholder{7}}')).toEqual('\\sqrt{7}');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('handles a bare \\placeholder with no argument', () => {
|
|
89
|
-
expect(fromMathLive('\\longdiv{\\placeholder}')).toEqual('\\longdiv{}');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('never leaks the token \\placeholder', () => {
|
|
93
|
-
['\\longdiv{\\placeholder{}}', '\\frac{\\placeholder{}}{x}', '\\placeholder{}'].forEach((l) => {
|
|
94
|
-
expect(fromMathLive(l)).not.toContain('\\placeholder');
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('still maps NAMED placeholders to answer blocks', () => {
|
|
99
|
-
// named ones are answer blocks and must survive
|
|
100
|
-
expect(fromMathLive('\\placeholder[r1]{}')).toEqual('\\MathQuillMathField[r1]{}');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('round-trips answer blocks combined with newlines', () => {
|
|
104
|
-
const stored = `\\MathQuillMathField[r1]{}${NEWLINE_EMBED}y`;
|
|
105
|
-
|
|
106
|
-
expect(fromMathLive(toMathLive(stored))).toEqual(stored);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// A MathLive macro serialises from the arguments it was created with, so text
|
|
111
|
-
// typed inside its expansion never comes back out of getValue('latex').
|
|
112
|
-
// Argument-taking pie commands must therefore become native constructs before
|
|
113
|
-
// they reach a mathfield.
|
|
114
|
-
describe('toNativeCommands', () => {
|
|
115
|
-
it('expands \\longdiv to native \\enclose', () => {
|
|
116
|
-
expect(toNativeCommands('\\longdiv{1234}')).toEqual('\\enclose{longdiv}{1234}');
|
|
117
|
-
expect(toNativeCommands('\\longdiv{}')).toEqual('\\enclose{longdiv}{}');
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('expands \\overarc to native \\overparen', () => {
|
|
121
|
-
expect(toNativeCommands('\\overarc{AB}')).toEqual('\\overparen{AB}');
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('expands \\abs to native \\left|..\\right|', () => {
|
|
125
|
-
expect(toNativeCommands('\\abs{x}')).toEqual('\\left|x\\right|');
|
|
126
|
-
expect(toNativeCommands('\\abs{}')).toEqual('\\left|\\right|');
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('handles nested braces inside \\abs', () => {
|
|
130
|
-
expect(toNativeCommands('\\abs{\\frac{1}{2}}')).toEqual('\\left|\\frac{1}{2}\\right|');
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('handles several occurrences', () => {
|
|
134
|
-
expect(toNativeCommands('\\abs{a}+\\abs{b}')).toEqual('\\left|a\\right|+\\left|b\\right|');
|
|
135
|
-
expect(toNativeCommands('\\longdiv{1}\\longdiv{2}')).toEqual('\\enclose{longdiv}{1}\\enclose{longdiv}{2}');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// `%` starts a comment in real LaTeX, so MathLive drops it and everything
|
|
139
|
-
// after it. MathQuill had no comments, so latex authored under it - or by
|
|
140
|
-
// hand - can carry a bare `%` that would silently truncate the expression.
|
|
141
|
-
it('escapes a bare % so it cannot comment out the rest of the line', () => {
|
|
142
|
-
expect(toNativeCommands('%')).toEqual('\\%');
|
|
143
|
-
expect(toNativeCommands('50%')).toEqual('50\\%');
|
|
144
|
-
expect(toNativeCommands('x%y')).toEqual('x\\%y');
|
|
145
|
-
expect(toNativeCommands('a%b%c')).toEqual('a\\%b\\%c');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('leaves an already-escaped % alone', () => {
|
|
149
|
-
expect(toNativeCommands('\\%')).toEqual('\\%');
|
|
150
|
-
expect(toNativeCommands('50\\%')).toEqual('50\\%');
|
|
151
|
-
// idempotent: toMathLive may run over latex that came back out of a field
|
|
152
|
-
expect(toNativeCommands(toNativeCommands('50%'))).toEqual('50\\%');
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// `\\` is a line break, not an escape, so the `%` after it is still bare.
|
|
156
|
-
it('counts backslashes to decide whether a % is escaped', () => {
|
|
157
|
-
expect(toNativeCommands('a\\\\%b')).toEqual('a\\\\\\%b');
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('leaves other latex untouched', () => {
|
|
161
|
-
['\\frac{1}{2}', '\\pi', '\\sqrt{x}', '\\overline{AB}'].forEach((l) => {
|
|
162
|
-
expect(toNativeCommands(l)).toEqual(l);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('handles nullish input', () => {
|
|
167
|
-
expect(toNativeCommands(undefined)).toEqual('');
|
|
168
|
-
expect(toNativeCommands('')).toEqual('');
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('is applied by toMathLive', () => {
|
|
172
|
-
expect(toMathLive('\\longdiv{5}')).toEqual('\\enclose{longdiv}{5}');
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('does not leave a pie macro in what reaches the field', () => {
|
|
176
|
-
['\\longdiv{7}', '\\abs{7}', '\\overarc{7}'].forEach((l) => {
|
|
177
|
-
const out = toMathLive(l);
|
|
178
|
-
|
|
179
|
-
expect(out).not.toMatch(/\\longdiv|\\abs|\\overarc/);
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
describe('fieldIds', () => {
|
|
185
|
-
it('returns ids in document order', () => {
|
|
186
|
-
expect(fieldIds('\\MathQuillMathField[r1]{}+\\MathQuillMathField[r2]{}')).toEqual(['r1', 'r2']);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('returns [] when there are none', () => {
|
|
190
|
-
expect(fieldIds('x+y')).toEqual([]);
|
|
191
|
-
expect(fieldIds(undefined)).toEqual([]);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('is repeatable (regex lastIndex is reset)', () => {
|
|
195
|
-
const latex = '\\MathQuillMathField[r1]{}';
|
|
196
|
-
|
|
197
|
-
expect(fieldIds(latex)).toEqual(['r1']);
|
|
198
|
-
expect(fieldIds(latex)).toEqual(['r1']);
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// MathQuill registered some keypad names as aliases of a different command:
|
|
203
|
-
// the divide key stored `\div`, not `\divide`. MathLive knows `\divide` only as
|
|
204
|
-
// a pie macro and serialises it under that name, so it reached storage and
|
|
205
|
-
// MathJax (which has no `\divide`) rendered it as red text.
|
|
206
|
-
describe('MathQuill command aliases', () => {
|
|
207
|
-
it('the divide and perpendicular keys insert the command MathQuill stored', () => {
|
|
208
|
-
/* eslint-disable global-require */
|
|
209
|
-
const { divide } = require('../keys/basic-operators');
|
|
210
|
-
// Exported under a pre-existing misspelling.
|
|
211
|
-
const { perpindicular: perpendicular } = require('../keys/geometry');
|
|
212
|
-
/* eslint-enable global-require */
|
|
213
|
-
|
|
214
|
-
expect(keyToAction(divide)).toEqual({ type: 'insert', value: '\\div' });
|
|
215
|
-
expect(keyToAction(perpendicular)).toEqual({ type: 'insert', value: '\\perp' });
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it('stores the canonical command for latex that still carries an alias', () => {
|
|
219
|
-
// Typed into the field, or saved before the keypad resolved the alias.
|
|
220
|
-
expect(fromMathLive('1\\divide 6')).toEqual('1\\div 6');
|
|
221
|
-
expect(fromMathLive('a\\perpendicular b')).toEqual('a\\perp b');
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it('only replaces whole command names', () => {
|
|
225
|
-
// \divideontimes is a real AMS symbol and must survive.
|
|
226
|
-
expect(toCanonicalCommands('a\\divideontimes b')).toEqual('a\\divideontimes b');
|
|
227
|
-
expect(toCanonicalCommands('\\divide\\divide')).toEqual('\\div\\div');
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// The double prime key: MathLive serialises `5''` as `5^{\doubleprime}`,
|
|
231
|
-
// which MathJax cannot render (red `\doubleprime`). MathQuill stored `5''`.
|
|
232
|
-
it('stores the double prime key as apostrophes', () => {
|
|
233
|
-
expect(fromMathLive('5^{\\doubleprime}')).toEqual("5''");
|
|
234
|
-
expect(fromMathLive('x^{\\prime}')).toEqual("x'");
|
|
235
|
-
expect(fromMathLive('x^{\\prime\\prime\\prime}')).toEqual("x'''");
|
|
236
|
-
expect(fromMathLive('\\doubleprime')).toEqual("''");
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// Typing `'` twice yields two superscript groups - a MathJax double-exponent
|
|
240
|
-
// error - so they collapse into apostrophes too.
|
|
241
|
-
it('collapses adjacent prime superscripts', () => {
|
|
242
|
-
expect(fromMathLive('x^{\\prime}^{\\prime}')).toEqual("x''");
|
|
243
|
-
expect(fromMathLive('5^{\\prime}^{\\doubleprime}')).toEqual("5'''");
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it('leaves superscripts that hold more than primes alone', () => {
|
|
247
|
-
expect(fromMathLive('x^{\\prime 2}')).toEqual('x^{\\prime 2}');
|
|
248
|
-
expect(fromMathLive('x^{2}')).toEqual('x^{2}');
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
it('round-trips stored primes unchanged', () => {
|
|
252
|
-
expect(fromMathLive("12^{\\circ}30'15''")).toEqual("12^{\\circ}30'15''");
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('no keypad key inserts an alias name', () => {
|
|
256
|
-
/* eslint-disable global-require */
|
|
257
|
-
const fs = require('fs');
|
|
258
|
-
const path = require('path');
|
|
259
|
-
/* eslint-enable global-require */
|
|
260
|
-
const keysDir = path.resolve(__dirname, '../keys');
|
|
261
|
-
const keys = [];
|
|
262
|
-
|
|
263
|
-
const collect = (v) => {
|
|
264
|
-
if (Array.isArray(v)) return v.forEach(collect);
|
|
265
|
-
if (v && typeof v === 'object' && (v.command || v.latex || v.write)) keys.push(v);
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
fs.readdirSync(keysDir)
|
|
269
|
-
.filter((f) => /\.js$/.test(f))
|
|
270
|
-
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
271
|
-
.forEach((f) => Object.values(require(path.join(keysDir, f))).forEach(collect));
|
|
272
|
-
|
|
273
|
-
expect(keys.length).toBeGreaterThan(50);
|
|
274
|
-
|
|
275
|
-
keys.forEach((k) => {
|
|
276
|
-
const action = keyToAction(k);
|
|
277
|
-
const value = (action && action.value) || '';
|
|
278
|
-
|
|
279
|
-
Object.keys(MATHQUILL_ALIASES).forEach((alias) => {
|
|
280
|
-
expect(new RegExp(`\\${alias}(?![a-zA-Z])`).test(value)).toBe(false);
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
describe('keyToAction', () => {
|
|
287
|
-
it('prefers latex when there is no command', () => {
|
|
288
|
-
expect(keyToAction({ latex: '\\pi', write: 'p' })).toEqual({ type: 'insert', value: '\\pi' });
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
it('uses write', () => {
|
|
292
|
-
expect(keyToAction({ write: 'x' })).toEqual({ type: 'insert', value: 'x' });
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('expands commands that take arguments into placeholders', () => {
|
|
296
|
-
expect(keyToAction({ command: '\\frac' })).toEqual({ type: 'insert', value: '\\frac{#?}{#?}' });
|
|
297
|
-
expect(keyToAction({ command: '\\sqrt' })).toEqual({ type: 'insert', value: '\\sqrt{#?}' });
|
|
298
|
-
expect(keyToAction({ command: '^' })).toEqual({ type: 'insert', value: '^{#?}' });
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// MathQuill's `/` turned the preceding expression into the numerator: type
|
|
302
|
-
// 5, press the key, get 5/_ with the caret in the denominator. `#@` is
|
|
303
|
-
// MathLive's "selection, or the item before the cursor" token, and is what
|
|
304
|
-
// MathLive binds to `/` itself.
|
|
305
|
-
it('division takes the preceding item as the numerator', () => {
|
|
306
|
-
expect(keyToAction({ command: '/' })).toEqual({ type: 'insert', value: '\\frac{#@}{#?}' });
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it('an explicit blank-over-blank fraction stays empty', () => {
|
|
310
|
-
// distinct from `/`: this key is meant to insert two empty slots
|
|
311
|
-
expect(keyToAction({ command: '\\frac' })).toEqual({ type: 'insert', value: '\\frac{#?}{#?}' });
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it('the x-over-blank key routes through division', () => {
|
|
315
|
-
// eslint-disable-next-line global-require
|
|
316
|
-
const { xOverBlank } = require('../keys/fractions');
|
|
317
|
-
|
|
318
|
-
expect(xOverBlank.command).toEqual('/');
|
|
319
|
-
expect(keyToAction(xOverBlank).value).toEqual('\\frac{#@}{#?}');
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
it('passes argument-less commands through', () => {
|
|
323
|
-
expect(keyToAction({ command: '\\pi' })).toEqual({ type: 'insert', value: '\\pi' });
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it('concatenates array commands (MathQuill cmd() applied them in sequence)', () => {
|
|
327
|
-
// Measured Angle
|
|
328
|
-
expect(keyToAction({ command: ['m', '\\angle'] })).toEqual({ type: 'insert', value: 'm\\angle' });
|
|
329
|
-
// log base n - the `_` part must still expand to a placeholder
|
|
330
|
-
expect(keyToAction({ command: ['\\log', '_'] })).toEqual({ type: 'insert', value: '\\log_{#?}' });
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
it('always returns a string value for insert actions', () => {
|
|
334
|
-
[{ command: ['m', '\\angle'] }, { command: '\\frac' }, { write: 'x' }, { latex: '\\pi' }].forEach((k) => {
|
|
335
|
-
expect(typeof keyToAction(k).value).toBe('string');
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it('maps keystrokes to MathLive selectors', () => {
|
|
340
|
-
expect(keyToAction({ keystroke: 'Left' })).toEqual({ type: 'command', value: 'moveToPreviousChar' });
|
|
341
|
-
expect(keyToAction({ keystroke: 'Right' })).toEqual({ type: 'command', value: 'moveToNextChar' });
|
|
342
|
-
expect(keyToAction({ keystroke: 'Backspace' })).toEqual({ type: 'command', value: 'deleteBackward' });
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
it('returns undefined for unknown/empty input', () => {
|
|
346
|
-
expect(keyToAction(undefined)).toBeUndefined();
|
|
347
|
-
expect(keyToAction({})).toBeUndefined();
|
|
348
|
-
expect(keyToAction({ keystroke: 'Nope' })).toBeUndefined();
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
it('latex wins over command only when command is absent', () => {
|
|
352
|
-
// a key with both should use the command path (matches MathInput.keypadPress)
|
|
353
|
-
expect(keyToAction({ latex: '\\frac{}{}', command: '\\frac' })).toEqual({
|
|
354
|
-
type: 'insert',
|
|
355
|
-
value: '\\frac{#?}{#?}',
|
|
356
|
-
});
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
});
|