@pie-lib/math-input-mathlive 1.1.5-beta.9 → 2.0.1-next.20261109072207

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +84 -109
  2. package/dist/_virtual/_rolldown/runtime.js +11 -0
  3. package/dist/horizontal-keypad.d.ts +22 -0
  4. package/dist/horizontal-keypad.js +54 -0
  5. package/dist/index.d.ts +20 -0
  6. package/dist/index.js +12 -0
  7. package/dist/keypad/index.d.ts +40 -0
  8. package/dist/keypad/index.js +245 -0
  9. package/dist/keypad/keys-layout.d.ts +7 -0
  10. package/dist/keypad/keys-layout.js +5 -0
  11. package/dist/keys/basic-operators.d.ts +5 -0
  12. package/dist/keys/basic-operators.js +30 -0
  13. package/dist/keys/chars.d.ts +5 -0
  14. package/dist/keys/comparison.d.ts +4 -0
  15. package/dist/keys/comparison.js +32 -0
  16. package/dist/keys/constants.d.ts +4 -0
  17. package/dist/keys/constants.js +35 -0
  18. package/dist/keys/digits.d.ts +15 -0
  19. package/dist/keys/digits.js +34 -0
  20. package/dist/keys/edit.d.ts +6 -0
  21. package/dist/keys/edit.js +9 -0
  22. package/dist/keys/exponent.d.ts +4 -0
  23. package/dist/keys/exponent.js +28 -0
  24. package/dist/keys/fractions.d.ts +3 -0
  25. package/dist/keys/fractions.js +27 -0
  26. package/dist/keys/geometry.d.ts +23 -0
  27. package/dist/keys/geometry.js +127 -0
  28. package/dist/keys/grades.d.ts +9 -0
  29. package/dist/keys/grades.js +414 -0
  30. package/dist/keys/index.d.ts +6 -0
  31. package/dist/keys/index.js +50 -0
  32. package/dist/keys/log.d.ts +3 -0
  33. package/dist/keys/log.js +25 -0
  34. package/dist/keys/logic.d.ts +2 -0
  35. package/dist/keys/logic.js +13 -0
  36. package/dist/keys/matrices.d.ts +2 -0
  37. package/dist/keys/matrices.js +17 -0
  38. package/dist/keys/misc.d.ts +10 -0
  39. package/dist/keys/misc.js +60 -0
  40. package/dist/keys/navigation.d.ts +2 -0
  41. package/dist/keys/navigation.js +13 -0
  42. package/dist/keys/operators.d.ts +1 -0
  43. package/dist/keys/operators.js +11 -0
  44. package/dist/keys/statistics.d.ts +5 -0
  45. package/dist/keys/statistics.js +38 -0
  46. package/dist/keys/sub-sup.d.ts +2 -0
  47. package/dist/keys/sub-sup.js +17 -0
  48. package/dist/keys/trigonometry.d.ts +6 -0
  49. package/dist/keys/trigonometry.js +43 -0
  50. package/dist/keys/utils.d.ts +5 -0
  51. package/dist/keys/utils.js +24 -0
  52. package/dist/keys/vars.d.ts +3 -0
  53. package/dist/keys/vars.js +22 -0
  54. package/dist/latex-bridge.d.ts +197 -0
  55. package/dist/latex-bridge.js +210 -0
  56. package/dist/longdiv.d.ts +24 -0
  57. package/dist/longdiv.js +43 -0
  58. package/dist/math-input.d.ts +26 -0
  59. package/dist/math-input.js +74 -0
  60. package/dist/mathlive-instance.d.ts +221 -0
  61. package/dist/mathlive-instance.js +159 -0
  62. package/dist/mf/common-styles.d.ts +594 -0
  63. package/dist/mf/common-styles.js +80 -0
  64. package/dist/mf/field-label.d.ts +16 -0
  65. package/dist/mf/field-label.js +13 -0
  66. package/dist/mf/index.d.ts +4 -0
  67. package/dist/mf/index.js +21 -0
  68. package/dist/mf/input.d.ts +94 -0
  69. package/dist/mf/input.js +127 -0
  70. package/dist/mf/static.d.ts +143 -0
  71. package/dist/mf/static.js +230 -0
  72. package/dist/selection.d.ts +43 -0
  73. package/dist/selection.js +39 -0
  74. package/package.json +32 -18
  75. package/lib/__tests__/composites.test.js +0 -255
  76. package/lib/__tests__/drop-in-compat.test.js +0 -133
  77. package/lib/__tests__/embedded-fonts.test.js +0 -121
  78. package/lib/__tests__/index.test.js +0 -118
  79. package/lib/__tests__/input-imperative.test.js +0 -155
  80. package/lib/__tests__/keypad-label.test.js +0 -231
  81. package/lib/__tests__/keypad-render.test.js +0 -206
  82. package/lib/__tests__/latex-bridge.test.js +0 -386
  83. package/lib/__tests__/mathlive-instance.test.js +0 -419
  84. package/lib/__tests__/mount-race.test.js +0 -218
  85. package/lib/__tests__/static-prompts.test.js +0 -405
  86. package/lib/__tests__/tmp-markup.test.js +0 -26
  87. package/lib/horizontal-keypad.js +0 -101
  88. package/lib/horizontal-keypad.js.map +0 -1
  89. package/lib/index.js +0 -143
  90. package/lib/index.js.map +0 -1
  91. package/lib/keypad/index.js +0 -431
  92. package/lib/keypad/index.js.map +0 -1
  93. package/lib/keypad/keys-layout.js +0 -22
  94. package/lib/keypad/keys-layout.js.map +0 -1
  95. package/lib/keys/basic-operators.js +0 -33
  96. package/lib/keys/basic-operators.js.map +0 -1
  97. package/lib/keys/chars.js +0 -12
  98. package/lib/keys/chars.js.map +0 -1
  99. package/lib/keys/comparison.js +0 -39
  100. package/lib/keys/comparison.js.map +0 -1
  101. package/lib/keys/constants.js +0 -37
  102. package/lib/keys/constants.js.map +0 -1
  103. package/lib/keys/digits.js +0 -46
  104. package/lib/keys/digits.js.map +0 -1
  105. package/lib/keys/edit.js +0 -14
  106. package/lib/keys/edit.js.map +0 -1
  107. package/lib/keys/exponent.js +0 -30
  108. package/lib/keys/exponent.js.map +0 -1
  109. package/lib/keys/fractions.js +0 -29
  110. package/lib/keys/fractions.js.map +0 -1
  111. package/lib/keys/geometry.js +0 -143
  112. package/lib/keys/geometry.js.map +0 -1
  113. package/lib/keys/grades.js +0 -259
  114. package/lib/keys/grades.js.map +0 -1
  115. package/lib/keys/index.js +0 -35
  116. package/lib/keys/index.js.map +0 -1
  117. package/lib/keys/log.js +0 -27
  118. package/lib/keys/log.js.map +0 -1
  119. package/lib/keys/logic.js +0 -19
  120. package/lib/keys/logic.js.map +0 -1
  121. package/lib/keys/matrices.js +0 -19
  122. package/lib/keys/matrices.js.map +0 -1
  123. package/lib/keys/misc.js +0 -69
  124. package/lib/keys/misc.js.map +0 -1
  125. package/lib/keys/navigation.js +0 -20
  126. package/lib/keys/navigation.js.map +0 -1
  127. package/lib/keys/operators.js +0 -15
  128. package/lib/keys/operators.js.map +0 -1
  129. package/lib/keys/statistics.js +0 -40
  130. package/lib/keys/statistics.js.map +0 -1
  131. package/lib/keys/sub-sup.js +0 -19
  132. package/lib/keys/sub-sup.js.map +0 -1
  133. package/lib/keys/trigonometry.js +0 -45
  134. package/lib/keys/trigonometry.js.map +0 -1
  135. package/lib/keys/utils.js +0 -87
  136. package/lib/keys/utils.js.map +0 -1
  137. package/lib/keys/vars.js +0 -24
  138. package/lib/keys/vars.js.map +0 -1
  139. package/lib/latex-bridge.js +0 -508
  140. package/lib/latex-bridge.js.map +0 -1
  141. package/lib/math-input.js +0 -143
  142. package/lib/math-input.js.map +0 -1
  143. package/lib/mathlive-instance.js +0 -585
  144. package/lib/mathlive-instance.js.map +0 -1
  145. package/lib/mf/common-styles.js +0 -203
  146. package/lib/mf/common-styles.js.map +0 -1
  147. package/lib/mf/index.js +0 -84
  148. package/lib/mf/index.js.map +0 -1
  149. package/lib/mf/input.js +0 -364
  150. package/lib/mf/input.js.map +0 -1
  151. package/lib/mf/static.js +0 -500
  152. package/lib/mf/static.js.map +0 -1
  153. package/src/__tests__/composites.test.jsx +0 -220
  154. package/src/__tests__/drop-in-compat.test.jsx +0 -112
  155. package/src/__tests__/index.test.jsx +0 -109
  156. package/src/__tests__/input-imperative.test.jsx +0 -144
  157. package/src/__tests__/keypad-label.test.jsx +0 -283
  158. package/src/__tests__/keypad-render.test.jsx +0 -123
  159. package/src/__tests__/latex-bridge.test.js +0 -389
  160. package/src/__tests__/mathlive-instance.test.js +0 -418
  161. package/src/__tests__/mount-race.test.jsx +0 -142
  162. package/src/__tests__/static-prompts.test.jsx +0 -364
  163. package/src/horizontal-keypad.jsx +0 -73
  164. package/src/index.jsx +0 -63
  165. package/src/keypad/index.jsx +0 -386
  166. package/src/keypad/keys-layout.js +0 -16
  167. package/src/keys/basic-operators.js +0 -32
  168. package/src/keys/chars.js +0 -5
  169. package/src/keys/comparison.js +0 -28
  170. package/src/keys/constants.js +0 -35
  171. package/src/keys/digits.js +0 -40
  172. package/src/keys/edit.js +0 -3
  173. package/src/keys/exponent.js +0 -28
  174. package/src/keys/fractions.js +0 -26
  175. package/src/keys/geometry.js +0 -149
  176. package/src/keys/grades.js +0 -367
  177. package/src/keys/index.js +0 -20
  178. package/src/keys/log.js +0 -22
  179. package/src/keys/logic.js +0 -15
  180. package/src/keys/matrices.js +0 -15
  181. package/src/keys/misc.js +0 -71
  182. package/src/keys/navigation.js +0 -8
  183. package/src/keys/operators.js +0 -10
  184. package/src/keys/statistics.js +0 -38
  185. package/src/keys/sub-sup.js +0 -15
  186. package/src/keys/trigonometry.js +0 -15
  187. package/src/keys/utils.js +0 -66
  188. package/src/keys/vars.js +0 -19
  189. package/src/latex-bridge.js +0 -524
  190. package/src/math-input.jsx +0 -115
  191. package/src/mathlive-instance.js +0 -582
  192. package/src/mf/common-styles.js +0 -210
  193. package/src/mf/index.js +0 -30
  194. package/src/mf/input.jsx +0 -319
  195. package/src/mf/static.jsx +0 -479
@@ -1,389 +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
- // `5′6″` typed or pasted as characters serialises as bare commands. A bare
256
- // `\prime` is full size in MathJax while `''` is a superscript, so storing
257
- // `5\prime6''` drew the single prime larger than each stroke of the double.
258
- it('stores bare primes as apostrophes, so single and double match', () => {
259
- expect(fromMathLive('5\\prime6\\doubleprime')).toEqual("5'6''");
260
- expect(fromMathLive('5\\prime 6\\doubleprime')).toEqual("5' 6''");
261
- expect(fromMathLive('\\prime')).toEqual("'");
262
- expect(fromMathLive('\\frac{5\\prime}{2}')).toEqual("\\frac{5'}{2}");
263
- });
264
-
265
- // Inside a script a prime is already a superscript; an apostrophe there
266
- // would be a prime *of* the script.
267
- it('keeps primes that are inside a superscript or subscript', () => {
268
- expect(fromMathLive('x^{\\prime 2}')).toEqual('x^{\\prime 2}');
269
- expect(fromMathLive('x^\\prime')).toEqual('x^\\prime');
270
- expect(fromMathLive('x_{\\prime}')).toEqual('x_{\\prime}');
271
- // MathJax has no \doubleprime: spell it out rather than leave red text
272
- expect(fromMathLive('x^{\\doubleprime 2}')).toEqual('x^{\\prime\\prime 2}');
273
- });
274
-
275
- it('closes the script scope at the matching brace', () => {
276
- expect(fromMathLive('x^{2}\\prime')).toEqual("x^{2}'");
277
- expect(fromMathLive('x^{\\frac{a}{b}}6\\doubleprime')).toEqual("x^{\\frac{a}{b}}6''");
278
- });
279
-
280
- it('does not touch commands that merely start with "prime"', () => {
281
- expect(fromMathLive('\\primes')).toEqual('\\primes');
282
- expect(fromMathLive('\\backprime')).toEqual('\\backprime');
283
- });
284
-
285
- it('no keypad key inserts an alias name', () => {
286
- /* eslint-disable global-require */
287
- const fs = require('fs');
288
- const path = require('path');
289
- /* eslint-enable global-require */
290
- const keysDir = path.resolve(__dirname, '../keys');
291
- const keys = [];
292
-
293
- const collect = (v) => {
294
- if (Array.isArray(v)) return v.forEach(collect);
295
- if (v && typeof v === 'object' && (v.command || v.latex || v.write)) keys.push(v);
296
- };
297
-
298
- fs.readdirSync(keysDir)
299
- .filter((f) => /\.js$/.test(f))
300
- // eslint-disable-next-line global-require, import/no-dynamic-require
301
- .forEach((f) => Object.values(require(path.join(keysDir, f))).forEach(collect));
302
-
303
- expect(keys.length).toBeGreaterThan(50);
304
-
305
- keys.forEach((k) => {
306
- const action = keyToAction(k);
307
- const value = (action && action.value) || '';
308
-
309
- Object.keys(MATHQUILL_ALIASES).forEach((alias) => {
310
- expect(new RegExp(`\\${alias}(?![a-zA-Z])`).test(value)).toBe(false);
311
- });
312
- });
313
- });
314
- });
315
-
316
- describe('keyToAction', () => {
317
- it('prefers latex when there is no command', () => {
318
- expect(keyToAction({ latex: '\\pi', write: 'p' })).toEqual({ type: 'insert', value: '\\pi' });
319
- });
320
-
321
- it('uses write', () => {
322
- expect(keyToAction({ write: 'x' })).toEqual({ type: 'insert', value: 'x' });
323
- });
324
-
325
- it('expands commands that take arguments into placeholders', () => {
326
- expect(keyToAction({ command: '\\frac' })).toEqual({ type: 'insert', value: '\\frac{#?}{#?}' });
327
- expect(keyToAction({ command: '\\sqrt' })).toEqual({ type: 'insert', value: '\\sqrt{#?}' });
328
- expect(keyToAction({ command: '^' })).toEqual({ type: 'insert', value: '^{#?}' });
329
- });
330
-
331
- // MathQuill's `/` turned the preceding expression into the numerator: type
332
- // 5, press the key, get 5/_ with the caret in the denominator. `#@` is
333
- // MathLive's "selection, or the item before the cursor" token, and is what
334
- // MathLive binds to `/` itself.
335
- it('division takes the preceding item as the numerator', () => {
336
- expect(keyToAction({ command: '/' })).toEqual({ type: 'insert', value: '\\frac{#@}{#?}' });
337
- });
338
-
339
- it('an explicit blank-over-blank fraction stays empty', () => {
340
- // distinct from `/`: this key is meant to insert two empty slots
341
- expect(keyToAction({ command: '\\frac' })).toEqual({ type: 'insert', value: '\\frac{#?}{#?}' });
342
- });
343
-
344
- it('the x-over-blank key routes through division', () => {
345
- // eslint-disable-next-line global-require
346
- const { xOverBlank } = require('../keys/fractions');
347
-
348
- expect(xOverBlank.command).toEqual('/');
349
- expect(keyToAction(xOverBlank).value).toEqual('\\frac{#@}{#?}');
350
- });
351
-
352
- it('passes argument-less commands through', () => {
353
- expect(keyToAction({ command: '\\pi' })).toEqual({ type: 'insert', value: '\\pi' });
354
- });
355
-
356
- it('concatenates array commands (MathQuill cmd() applied them in sequence)', () => {
357
- // Measured Angle
358
- expect(keyToAction({ command: ['m', '\\angle'] })).toEqual({ type: 'insert', value: 'm\\angle' });
359
- // log base n - the `_` part must still expand to a placeholder
360
- expect(keyToAction({ command: ['\\log', '_'] })).toEqual({ type: 'insert', value: '\\log_{#?}' });
361
- });
362
-
363
- it('always returns a string value for insert actions', () => {
364
- [{ command: ['m', '\\angle'] }, { command: '\\frac' }, { write: 'x' }, { latex: '\\pi' }].forEach((k) => {
365
- expect(typeof keyToAction(k).value).toBe('string');
366
- });
367
- });
368
-
369
- it('maps keystrokes to MathLive selectors', () => {
370
- expect(keyToAction({ keystroke: 'Left' })).toEqual({ type: 'command', value: 'moveToPreviousChar' });
371
- expect(keyToAction({ keystroke: 'Right' })).toEqual({ type: 'command', value: 'moveToNextChar' });
372
- expect(keyToAction({ keystroke: 'Backspace' })).toEqual({ type: 'command', value: 'deleteBackward' });
373
- });
374
-
375
- it('returns undefined for unknown/empty input', () => {
376
- expect(keyToAction(undefined)).toBeUndefined();
377
- expect(keyToAction({})).toBeUndefined();
378
- expect(keyToAction({ keystroke: 'Nope' })).toBeUndefined();
379
- });
380
-
381
- it('latex wins over command only when command is absent', () => {
382
- // a key with both should use the command path (matches MathInput.keypadPress)
383
- expect(keyToAction({ latex: '\\frac{}{}', command: '\\frac' })).toEqual({
384
- type: 'insert',
385
- value: '\\frac{#?}{#?}',
386
- });
387
- });
388
- });
389
- });