@pie-lib/math-input-mathlive 1.0.9-next.6637 → 1.0.10

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 (51) hide show
  1. package/README.md +14 -5
  2. package/lib/__tests__/composites.test.js +255 -0
  3. package/lib/__tests__/composites.test.js.map +1 -0
  4. package/lib/__tests__/drop-in-compat.test.js +133 -0
  5. package/lib/__tests__/drop-in-compat.test.js.map +1 -0
  6. package/lib/__tests__/index.test.js +118 -0
  7. package/lib/__tests__/index.test.js.map +1 -0
  8. package/lib/__tests__/input-imperative.test.js +155 -0
  9. package/lib/__tests__/input-imperative.test.js.map +1 -0
  10. package/lib/__tests__/keypad-label.test.js +118 -0
  11. package/lib/__tests__/keypad-label.test.js.map +1 -0
  12. package/lib/__tests__/keypad-render.test.js +206 -0
  13. package/lib/__tests__/keypad-render.test.js.map +1 -0
  14. package/lib/__tests__/latex-bridge.test.js +280 -0
  15. package/lib/__tests__/latex-bridge.test.js.map +1 -0
  16. package/lib/__tests__/mathlive-instance.test.js +279 -0
  17. package/lib/__tests__/mathlive-instance.test.js.map +1 -0
  18. package/lib/__tests__/mount-race.test.js +195 -0
  19. package/lib/__tests__/mount-race.test.js.map +1 -0
  20. package/lib/__tests__/static-prompts.test.js +282 -0
  21. package/lib/__tests__/static-prompts.test.js.map +1 -0
  22. package/lib/keypad/index.js +11 -13
  23. package/lib/keypad/index.js.map +1 -1
  24. package/lib/keys/geometry.js +7 -4
  25. package/lib/keys/geometry.js.map +1 -1
  26. package/lib/latex-bridge.js +18 -3
  27. package/lib/latex-bridge.js.map +1 -1
  28. package/lib/mathlive-instance.js +103 -11
  29. package/lib/mathlive-instance.js.map +1 -1
  30. package/lib/mf/common-styles.js +33 -4
  31. package/lib/mf/common-styles.js.map +1 -1
  32. package/lib/mf/input.js +22 -5
  33. package/lib/mf/input.js.map +1 -1
  34. package/lib/mf/static.js +21 -4
  35. package/lib/mf/static.js.map +1 -1
  36. package/package.json +3 -4
  37. package/src/__tests__/composites.test.jsx +220 -0
  38. package/src/__tests__/keypad-label.test.jsx +81 -14
  39. package/src/__tests__/keypad-render.test.jsx +123 -0
  40. package/src/__tests__/latex-bridge.test.js +21 -0
  41. package/src/__tests__/mathlive-instance.test.js +87 -0
  42. package/src/__tests__/mount-race.test.jsx +130 -0
  43. package/src/__tests__/static-prompts.test.jsx +251 -0
  44. package/src/keypad/index.jsx +11 -13
  45. package/src/keys/geometry.js +7 -2
  46. package/src/latex-bridge.js +18 -3
  47. package/src/mathlive-instance.js +111 -11
  48. package/src/mf/common-styles.js +33 -4
  49. package/src/mf/input.jsx +23 -5
  50. package/src/mf/static.jsx +24 -4
  51. package/LICENSE.md +0 -5
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
5
+ var _latexBridge = require("../latex-bridge");
6
+ describe('latex-bridge', function () {
7
+ describe('toMathLive', function () {
8
+ it('passes plain latex through', function () {
9
+ expect((0, _latexBridge.toMathLive)('\\frac{1}{2}')).toEqual('\\frac{1}{2}');
10
+ });
11
+ it('handles empty/nullish', function () {
12
+ expect((0, _latexBridge.toMathLive)('')).toEqual('');
13
+ expect((0, _latexBridge.toMathLive)(undefined)).toEqual('');
14
+ expect((0, _latexBridge.toMathLive)(null)).toEqual('');
15
+ });
16
+ it('converts a newLine embed to a multiline environment', function () {
17
+ expect((0, _latexBridge.toMathLive)("a".concat(_latexBridge.NEWLINE_EMBED, "b"))).toEqual('\\displaylines{a \\\\ b}');
18
+ });
19
+ it('converts multiple newLine embeds', function () {
20
+ expect((0, _latexBridge.toMathLive)("a".concat(_latexBridge.NEWLINE_EMBED, "b").concat(_latexBridge.NEWLINE_EMBED, "c"))).toEqual('\\displaylines{a \\\\ b \\\\ c}');
21
+ });
22
+ it('converts MathQuill answer blocks to placeholders', function () {
23
+ expect((0, _latexBridge.toMathLive)('x=\\MathQuillMathField[r1]{}')).toEqual('x=\\placeholder[r1]{}');
24
+ });
25
+ it('preserves answer block content', function () {
26
+ expect((0, _latexBridge.toMathLive)('\\MathQuillMathField[r2]{7}')).toEqual('\\placeholder[r2]{7}');
27
+ });
28
+ it('defaults an unnamed answer block id', function () {
29
+ expect((0, _latexBridge.toMathLive)('\\MathQuillMathField[]{}')).toEqual("\\placeholder[".concat(_latexBridge.DEFAULT_FIELD_ID, "]{}"));
30
+ });
31
+ it('handles answer blocks and newlines together', function () {
32
+ expect((0, _latexBridge.toMathLive)("\\MathQuillMathField[r1]{}".concat(_latexBridge.NEWLINE_EMBED, "x"))).toEqual('\\displaylines{\\placeholder[r1]{} \\\\ x}');
33
+ });
34
+ });
35
+ describe('fromMathLive', function () {
36
+ it('passes plain latex through', function () {
37
+ expect((0, _latexBridge.fromMathLive)('\\frac{1}{2}')).toEqual('\\frac{1}{2}');
38
+ });
39
+ it('unwraps displaylines back to newLine embeds', function () {
40
+ expect((0, _latexBridge.fromMathLive)('\\displaylines{a \\\\ b}')).toEqual("a".concat(_latexBridge.NEWLINE_EMBED, "b"));
41
+ });
42
+ it('converts placeholders back to MathQuill answer blocks', function () {
43
+ expect((0, _latexBridge.fromMathLive)('x=\\placeholder[r1]{}')).toEqual('x=\\MathQuillMathField[r1]{}');
44
+ });
45
+ it('round-trips a newline document', function () {
46
+ var stored = "a".concat(_latexBridge.NEWLINE_EMBED, "b").concat(_latexBridge.NEWLINE_EMBED, "c");
47
+ expect((0, _latexBridge.fromMathLive)((0, _latexBridge.toMathLive)(stored))).toEqual(stored);
48
+ });
49
+ it('round-trips an answer-block document', function () {
50
+ var stored = 'x=\\MathQuillMathField[r1]{}+\\MathQuillMathField[r2]{3}';
51
+ expect((0, _latexBridge.fromMathLive)((0, _latexBridge.toMathLive)(stored))).toEqual(stored);
52
+ });
53
+
54
+ // MathLive serialises empty slots as \placeholder{}, which MathJax (used by
55
+ // @pie-lib/math-rendering for prompts/previews) renders as red error text.
56
+ it('strips unnamed placeholders that MathLive adds', function () {
57
+ expect((0, _latexBridge.fromMathLive)('\\longdiv{\\placeholder{}}')).toEqual('\\longdiv{}');
58
+ expect((0, _latexBridge.fromMathLive)('\\frac{\\placeholder{}}{\\placeholder{}}')).toEqual('\\frac{}{}');
59
+ });
60
+ it('keeps content inside an unnamed placeholder', function () {
61
+ expect((0, _latexBridge.fromMathLive)('\\sqrt{\\placeholder{7}}')).toEqual('\\sqrt{7}');
62
+ });
63
+ it('handles a bare \\placeholder with no argument', function () {
64
+ expect((0, _latexBridge.fromMathLive)('\\longdiv{\\placeholder}')).toEqual('\\longdiv{}');
65
+ });
66
+ it('never leaks the token \\placeholder', function () {
67
+ ['\\longdiv{\\placeholder{}}', '\\frac{\\placeholder{}}{x}', '\\placeholder{}'].forEach(function (l) {
68
+ expect((0, _latexBridge.fromMathLive)(l)).not.toContain('\\placeholder');
69
+ });
70
+ });
71
+ it('still maps NAMED placeholders to answer blocks', function () {
72
+ // named ones are answer blocks and must survive
73
+ expect((0, _latexBridge.fromMathLive)('\\placeholder[r1]{}')).toEqual('\\MathQuillMathField[r1]{}');
74
+ });
75
+ it('round-trips answer blocks combined with newlines', function () {
76
+ var stored = "\\MathQuillMathField[r1]{}".concat(_latexBridge.NEWLINE_EMBED, "y");
77
+ expect((0, _latexBridge.fromMathLive)((0, _latexBridge.toMathLive)(stored))).toEqual(stored);
78
+ });
79
+ });
80
+
81
+ // A MathLive macro serialises from the arguments it was created with, so text
82
+ // typed inside its expansion never comes back out of getValue('latex').
83
+ // Argument-taking pie commands must therefore become native constructs before
84
+ // they reach a mathfield.
85
+ describe('toNativeCommands', function () {
86
+ it('expands \\longdiv to native \\enclose', function () {
87
+ expect((0, _latexBridge.toNativeCommands)('\\longdiv{1234}')).toEqual('\\enclose{longdiv}{1234}');
88
+ expect((0, _latexBridge.toNativeCommands)('\\longdiv{}')).toEqual('\\enclose{longdiv}{}');
89
+ });
90
+ it('expands \\overarc to native \\overparen', function () {
91
+ expect((0, _latexBridge.toNativeCommands)('\\overarc{AB}')).toEqual('\\overparen{AB}');
92
+ });
93
+ it('expands \\abs to native \\left|..\\right|', function () {
94
+ expect((0, _latexBridge.toNativeCommands)('\\abs{x}')).toEqual('\\left|x\\right|');
95
+ expect((0, _latexBridge.toNativeCommands)('\\abs{}')).toEqual('\\left|\\right|');
96
+ });
97
+ it('handles nested braces inside \\abs', function () {
98
+ expect((0, _latexBridge.toNativeCommands)('\\abs{\\frac{1}{2}}')).toEqual('\\left|\\frac{1}{2}\\right|');
99
+ });
100
+ it('handles several occurrences', function () {
101
+ expect((0, _latexBridge.toNativeCommands)('\\abs{a}+\\abs{b}')).toEqual('\\left|a\\right|+\\left|b\\right|');
102
+ expect((0, _latexBridge.toNativeCommands)('\\longdiv{1}\\longdiv{2}')).toEqual('\\enclose{longdiv}{1}\\enclose{longdiv}{2}');
103
+ });
104
+ it('leaves other latex untouched', function () {
105
+ ['\\frac{1}{2}', '\\pi', '\\sqrt{x}', '\\overline{AB}'].forEach(function (l) {
106
+ expect((0, _latexBridge.toNativeCommands)(l)).toEqual(l);
107
+ });
108
+ });
109
+ it('handles nullish input', function () {
110
+ expect((0, _latexBridge.toNativeCommands)(undefined)).toEqual('');
111
+ expect((0, _latexBridge.toNativeCommands)('')).toEqual('');
112
+ });
113
+ it('is applied by toMathLive', function () {
114
+ expect((0, _latexBridge.toMathLive)('\\longdiv{5}')).toEqual('\\enclose{longdiv}{5}');
115
+ });
116
+ it('does not leave a pie macro in what reaches the field', function () {
117
+ ['\\longdiv{7}', '\\abs{7}', '\\overarc{7}'].forEach(function (l) {
118
+ var out = (0, _latexBridge.toMathLive)(l);
119
+ expect(out).not.toMatch(/\\longdiv|\\abs|\\overarc/);
120
+ });
121
+ });
122
+ });
123
+ describe('fieldIds', function () {
124
+ it('returns ids in document order', function () {
125
+ expect((0, _latexBridge.fieldIds)('\\MathQuillMathField[r1]{}+\\MathQuillMathField[r2]{}')).toEqual(['r1', 'r2']);
126
+ });
127
+ it('returns [] when there are none', function () {
128
+ expect((0, _latexBridge.fieldIds)('x+y')).toEqual([]);
129
+ expect((0, _latexBridge.fieldIds)(undefined)).toEqual([]);
130
+ });
131
+ it('is repeatable (regex lastIndex is reset)', function () {
132
+ var latex = '\\MathQuillMathField[r1]{}';
133
+ expect((0, _latexBridge.fieldIds)(latex)).toEqual(['r1']);
134
+ expect((0, _latexBridge.fieldIds)(latex)).toEqual(['r1']);
135
+ });
136
+ });
137
+ describe('keyToAction', function () {
138
+ it('prefers latex when there is no command', function () {
139
+ expect((0, _latexBridge.keyToAction)({
140
+ latex: '\\pi',
141
+ write: 'p'
142
+ })).toEqual({
143
+ type: 'insert',
144
+ value: '\\pi'
145
+ });
146
+ });
147
+ it('uses write', function () {
148
+ expect((0, _latexBridge.keyToAction)({
149
+ write: 'x'
150
+ })).toEqual({
151
+ type: 'insert',
152
+ value: 'x'
153
+ });
154
+ });
155
+ it('expands commands that take arguments into placeholders', function () {
156
+ expect((0, _latexBridge.keyToAction)({
157
+ command: '\\frac'
158
+ })).toEqual({
159
+ type: 'insert',
160
+ value: '\\frac{#?}{#?}'
161
+ });
162
+ expect((0, _latexBridge.keyToAction)({
163
+ command: '\\sqrt'
164
+ })).toEqual({
165
+ type: 'insert',
166
+ value: '\\sqrt{#?}'
167
+ });
168
+ expect((0, _latexBridge.keyToAction)({
169
+ command: '^'
170
+ })).toEqual({
171
+ type: 'insert',
172
+ value: '^{#?}'
173
+ });
174
+ });
175
+
176
+ // MathQuill's `/` turned the preceding expression into the numerator: type
177
+ // 5, press the key, get 5/_ with the caret in the denominator. `#@` is
178
+ // MathLive's "selection, or the item before the cursor" token, and is what
179
+ // MathLive binds to `/` itself.
180
+ it('division takes the preceding item as the numerator', function () {
181
+ expect((0, _latexBridge.keyToAction)({
182
+ command: '/'
183
+ })).toEqual({
184
+ type: 'insert',
185
+ value: '\\frac{#@}{#?}'
186
+ });
187
+ });
188
+ it('an explicit blank-over-blank fraction stays empty', function () {
189
+ // distinct from `/`: this key is meant to insert two empty slots
190
+ expect((0, _latexBridge.keyToAction)({
191
+ command: '\\frac'
192
+ })).toEqual({
193
+ type: 'insert',
194
+ value: '\\frac{#?}{#?}'
195
+ });
196
+ });
197
+ it('the x-over-blank key routes through division', function () {
198
+ // eslint-disable-next-line global-require
199
+ var _require = require('../keys/fractions'),
200
+ xOverBlank = _require.xOverBlank;
201
+ expect(xOverBlank.command).toEqual('/');
202
+ expect((0, _latexBridge.keyToAction)(xOverBlank).value).toEqual('\\frac{#@}{#?}');
203
+ });
204
+ it('passes argument-less commands through', function () {
205
+ expect((0, _latexBridge.keyToAction)({
206
+ command: '\\pi'
207
+ })).toEqual({
208
+ type: 'insert',
209
+ value: '\\pi'
210
+ });
211
+ });
212
+ it('concatenates array commands (MathQuill cmd() applied them in sequence)', function () {
213
+ // Measured Angle
214
+ expect((0, _latexBridge.keyToAction)({
215
+ command: ['m', '\\angle']
216
+ })).toEqual({
217
+ type: 'insert',
218
+ value: 'm\\angle'
219
+ });
220
+ // log base n - the `_` part must still expand to a placeholder
221
+ expect((0, _latexBridge.keyToAction)({
222
+ command: ['\\log', '_']
223
+ })).toEqual({
224
+ type: 'insert',
225
+ value: '\\log_{#?}'
226
+ });
227
+ });
228
+ it('always returns a string value for insert actions', function () {
229
+ [{
230
+ command: ['m', '\\angle']
231
+ }, {
232
+ command: '\\frac'
233
+ }, {
234
+ write: 'x'
235
+ }, {
236
+ latex: '\\pi'
237
+ }].forEach(function (k) {
238
+ expect((0, _typeof2["default"])((0, _latexBridge.keyToAction)(k).value)).toBe('string');
239
+ });
240
+ });
241
+ it('maps keystrokes to MathLive selectors', function () {
242
+ expect((0, _latexBridge.keyToAction)({
243
+ keystroke: 'Left'
244
+ })).toEqual({
245
+ type: 'command',
246
+ value: 'moveToPreviousChar'
247
+ });
248
+ expect((0, _latexBridge.keyToAction)({
249
+ keystroke: 'Right'
250
+ })).toEqual({
251
+ type: 'command',
252
+ value: 'moveToNextChar'
253
+ });
254
+ expect((0, _latexBridge.keyToAction)({
255
+ keystroke: 'Backspace'
256
+ })).toEqual({
257
+ type: 'command',
258
+ value: 'deleteBackward'
259
+ });
260
+ });
261
+ it('returns undefined for unknown/empty input', function () {
262
+ expect((0, _latexBridge.keyToAction)(undefined)).toBeUndefined();
263
+ expect((0, _latexBridge.keyToAction)({})).toBeUndefined();
264
+ expect((0, _latexBridge.keyToAction)({
265
+ keystroke: 'Nope'
266
+ })).toBeUndefined();
267
+ });
268
+ it('latex wins over command only when command is absent', function () {
269
+ // a key with both should use the command path (matches MathInput.keypadPress)
270
+ expect((0, _latexBridge.keyToAction)({
271
+ latex: '\\frac{}{}',
272
+ command: '\\frac'
273
+ })).toEqual({
274
+ type: 'insert',
275
+ value: '\\frac{#?}{#?}'
276
+ });
277
+ });
278
+ });
279
+ });
280
+ //# sourceMappingURL=latex-bridge.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latex-bridge.test.js","names":["_latexBridge","require","describe","it","expect","toMathLive","toEqual","undefined","concat","NEWLINE_EMBED","DEFAULT_FIELD_ID","fromMathLive","stored","forEach","l","not","toContain","toNativeCommands","out","toMatch","fieldIds","latex","keyToAction","write","type","value","command","_require","xOverBlank","k","_typeof2","toBe","keystroke","toBeUndefined"],"sources":["../../src/__tests__/latex-bridge.test.js"],"sourcesContent":["import {\n toMathLive,\n fromMathLive,\n fieldIds,\n keyToAction,\n toNativeCommands,\n NEWLINE_EMBED,\n DEFAULT_FIELD_ID,\n} from '../latex-bridge';\n\ndescribe('latex-bridge', () => {\n describe('toMathLive', () => {\n it('passes plain latex through', () => {\n expect(toMathLive('\\\\frac{1}{2}')).toEqual('\\\\frac{1}{2}');\n });\n\n it('handles empty/nullish', () => {\n expect(toMathLive('')).toEqual('');\n expect(toMathLive(undefined)).toEqual('');\n expect(toMathLive(null)).toEqual('');\n });\n\n it('converts a newLine embed to a multiline environment', () => {\n expect(toMathLive(`a${NEWLINE_EMBED}b`)).toEqual('\\\\displaylines{a \\\\\\\\ b}');\n });\n\n it('converts multiple newLine embeds', () => {\n expect(toMathLive(`a${NEWLINE_EMBED}b${NEWLINE_EMBED}c`)).toEqual('\\\\displaylines{a \\\\\\\\ b \\\\\\\\ c}');\n });\n\n it('converts MathQuill answer blocks to placeholders', () => {\n expect(toMathLive('x=\\\\MathQuillMathField[r1]{}')).toEqual('x=\\\\placeholder[r1]{}');\n });\n\n it('preserves answer block content', () => {\n expect(toMathLive('\\\\MathQuillMathField[r2]{7}')).toEqual('\\\\placeholder[r2]{7}');\n });\n\n it('defaults an unnamed answer block id', () => {\n expect(toMathLive('\\\\MathQuillMathField[]{}')).toEqual(`\\\\placeholder[${DEFAULT_FIELD_ID}]{}`);\n });\n\n it('handles answer blocks and newlines together', () => {\n expect(toMathLive(`\\\\MathQuillMathField[r1]{}${NEWLINE_EMBED}x`)).toEqual(\n '\\\\displaylines{\\\\placeholder[r1]{} \\\\\\\\ x}',\n );\n });\n });\n\n describe('fromMathLive', () => {\n it('passes plain latex through', () => {\n expect(fromMathLive('\\\\frac{1}{2}')).toEqual('\\\\frac{1}{2}');\n });\n\n it('unwraps displaylines back to newLine embeds', () => {\n expect(fromMathLive('\\\\displaylines{a \\\\\\\\ b}')).toEqual(`a${NEWLINE_EMBED}b`);\n });\n\n it('converts placeholders back to MathQuill answer blocks', () => {\n expect(fromMathLive('x=\\\\placeholder[r1]{}')).toEqual('x=\\\\MathQuillMathField[r1]{}');\n });\n\n it('round-trips a newline document', () => {\n const stored = `a${NEWLINE_EMBED}b${NEWLINE_EMBED}c`;\n\n expect(fromMathLive(toMathLive(stored))).toEqual(stored);\n });\n\n it('round-trips an answer-block document', () => {\n const stored = 'x=\\\\MathQuillMathField[r1]{}+\\\\MathQuillMathField[r2]{3}';\n\n expect(fromMathLive(toMathLive(stored))).toEqual(stored);\n });\n\n // MathLive serialises empty slots as \\placeholder{}, which MathJax (used by\n // @pie-lib/math-rendering for prompts/previews) renders as red error text.\n it('strips unnamed placeholders that MathLive adds', () => {\n expect(fromMathLive('\\\\longdiv{\\\\placeholder{}}')).toEqual('\\\\longdiv{}');\n expect(fromMathLive('\\\\frac{\\\\placeholder{}}{\\\\placeholder{}}')).toEqual('\\\\frac{}{}');\n });\n\n it('keeps content inside an unnamed placeholder', () => {\n expect(fromMathLive('\\\\sqrt{\\\\placeholder{7}}')).toEqual('\\\\sqrt{7}');\n });\n\n it('handles a bare \\\\placeholder with no argument', () => {\n expect(fromMathLive('\\\\longdiv{\\\\placeholder}')).toEqual('\\\\longdiv{}');\n });\n\n it('never leaks the token \\\\placeholder', () => {\n ['\\\\longdiv{\\\\placeholder{}}', '\\\\frac{\\\\placeholder{}}{x}', '\\\\placeholder{}'].forEach((l) => {\n expect(fromMathLive(l)).not.toContain('\\\\placeholder');\n });\n });\n\n it('still maps NAMED placeholders to answer blocks', () => {\n // named ones are answer blocks and must survive\n expect(fromMathLive('\\\\placeholder[r1]{}')).toEqual('\\\\MathQuillMathField[r1]{}');\n });\n\n it('round-trips answer blocks combined with newlines', () => {\n const stored = `\\\\MathQuillMathField[r1]{}${NEWLINE_EMBED}y`;\n\n expect(fromMathLive(toMathLive(stored))).toEqual(stored);\n });\n });\n\n // A MathLive macro serialises from the arguments it was created with, so text\n // typed inside its expansion never comes back out of getValue('latex').\n // Argument-taking pie commands must therefore become native constructs before\n // they reach a mathfield.\n describe('toNativeCommands', () => {\n it('expands \\\\longdiv to native \\\\enclose', () => {\n expect(toNativeCommands('\\\\longdiv{1234}')).toEqual('\\\\enclose{longdiv}{1234}');\n expect(toNativeCommands('\\\\longdiv{}')).toEqual('\\\\enclose{longdiv}{}');\n });\n\n it('expands \\\\overarc to native \\\\overparen', () => {\n expect(toNativeCommands('\\\\overarc{AB}')).toEqual('\\\\overparen{AB}');\n });\n\n it('expands \\\\abs to native \\\\left|..\\\\right|', () => {\n expect(toNativeCommands('\\\\abs{x}')).toEqual('\\\\left|x\\\\right|');\n expect(toNativeCommands('\\\\abs{}')).toEqual('\\\\left|\\\\right|');\n });\n\n it('handles nested braces inside \\\\abs', () => {\n expect(toNativeCommands('\\\\abs{\\\\frac{1}{2}}')).toEqual('\\\\left|\\\\frac{1}{2}\\\\right|');\n });\n\n it('handles several occurrences', () => {\n expect(toNativeCommands('\\\\abs{a}+\\\\abs{b}')).toEqual('\\\\left|a\\\\right|+\\\\left|b\\\\right|');\n expect(toNativeCommands('\\\\longdiv{1}\\\\longdiv{2}')).toEqual('\\\\enclose{longdiv}{1}\\\\enclose{longdiv}{2}');\n });\n\n it('leaves other latex untouched', () => {\n ['\\\\frac{1}{2}', '\\\\pi', '\\\\sqrt{x}', '\\\\overline{AB}'].forEach((l) => {\n expect(toNativeCommands(l)).toEqual(l);\n });\n });\n\n it('handles nullish input', () => {\n expect(toNativeCommands(undefined)).toEqual('');\n expect(toNativeCommands('')).toEqual('');\n });\n\n it('is applied by toMathLive', () => {\n expect(toMathLive('\\\\longdiv{5}')).toEqual('\\\\enclose{longdiv}{5}');\n });\n\n it('does not leave a pie macro in what reaches the field', () => {\n ['\\\\longdiv{7}', '\\\\abs{7}', '\\\\overarc{7}'].forEach((l) => {\n const out = toMathLive(l);\n\n expect(out).not.toMatch(/\\\\longdiv|\\\\abs|\\\\overarc/);\n });\n });\n });\n\n describe('fieldIds', () => {\n it('returns ids in document order', () => {\n expect(fieldIds('\\\\MathQuillMathField[r1]{}+\\\\MathQuillMathField[r2]{}')).toEqual(['r1', 'r2']);\n });\n\n it('returns [] when there are none', () => {\n expect(fieldIds('x+y')).toEqual([]);\n expect(fieldIds(undefined)).toEqual([]);\n });\n\n it('is repeatable (regex lastIndex is reset)', () => {\n const latex = '\\\\MathQuillMathField[r1]{}';\n\n expect(fieldIds(latex)).toEqual(['r1']);\n expect(fieldIds(latex)).toEqual(['r1']);\n });\n });\n\n describe('keyToAction', () => {\n it('prefers latex when there is no command', () => {\n expect(keyToAction({ latex: '\\\\pi', write: 'p' })).toEqual({ type: 'insert', value: '\\\\pi' });\n });\n\n it('uses write', () => {\n expect(keyToAction({ write: 'x' })).toEqual({ type: 'insert', value: 'x' });\n });\n\n it('expands commands that take arguments into placeholders', () => {\n expect(keyToAction({ command: '\\\\frac' })).toEqual({ type: 'insert', value: '\\\\frac{#?}{#?}' });\n expect(keyToAction({ command: '\\\\sqrt' })).toEqual({ type: 'insert', value: '\\\\sqrt{#?}' });\n expect(keyToAction({ command: '^' })).toEqual({ type: 'insert', value: '^{#?}' });\n });\n\n // MathQuill's `/` turned the preceding expression into the numerator: type\n // 5, press the key, get 5/_ with the caret in the denominator. `#@` is\n // MathLive's \"selection, or the item before the cursor\" token, and is what\n // MathLive binds to `/` itself.\n it('division takes the preceding item as the numerator', () => {\n expect(keyToAction({ command: '/' })).toEqual({ type: 'insert', value: '\\\\frac{#@}{#?}' });\n });\n\n it('an explicit blank-over-blank fraction stays empty', () => {\n // distinct from `/`: this key is meant to insert two empty slots\n expect(keyToAction({ command: '\\\\frac' })).toEqual({ type: 'insert', value: '\\\\frac{#?}{#?}' });\n });\n\n it('the x-over-blank key routes through division', () => {\n // eslint-disable-next-line global-require\n const { xOverBlank } = require('../keys/fractions');\n\n expect(xOverBlank.command).toEqual('/');\n expect(keyToAction(xOverBlank).value).toEqual('\\\\frac{#@}{#?}');\n });\n\n it('passes argument-less commands through', () => {\n expect(keyToAction({ command: '\\\\pi' })).toEqual({ type: 'insert', value: '\\\\pi' });\n });\n\n it('concatenates array commands (MathQuill cmd() applied them in sequence)', () => {\n // Measured Angle\n expect(keyToAction({ command: ['m', '\\\\angle'] })).toEqual({ type: 'insert', value: 'm\\\\angle' });\n // log base n - the `_` part must still expand to a placeholder\n expect(keyToAction({ command: ['\\\\log', '_'] })).toEqual({ type: 'insert', value: '\\\\log_{#?}' });\n });\n\n it('always returns a string value for insert actions', () => {\n [{ command: ['m', '\\\\angle'] }, { command: '\\\\frac' }, { write: 'x' }, { latex: '\\\\pi' }].forEach((k) => {\n expect(typeof keyToAction(k).value).toBe('string');\n });\n });\n\n it('maps keystrokes to MathLive selectors', () => {\n expect(keyToAction({ keystroke: 'Left' })).toEqual({ type: 'command', value: 'moveToPreviousChar' });\n expect(keyToAction({ keystroke: 'Right' })).toEqual({ type: 'command', value: 'moveToNextChar' });\n expect(keyToAction({ keystroke: 'Backspace' })).toEqual({ type: 'command', value: 'deleteBackward' });\n });\n\n it('returns undefined for unknown/empty input', () => {\n expect(keyToAction(undefined)).toBeUndefined();\n expect(keyToAction({})).toBeUndefined();\n expect(keyToAction({ keystroke: 'Nope' })).toBeUndefined();\n });\n\n it('latex wins over command only when command is absent', () => {\n // a key with both should use the command path (matches MathInput.keypadPress)\n expect(keyToAction({ latex: '\\\\frac{}{}', command: '\\\\frac' })).toEqual({\n type: 'insert',\n value: '\\\\frac{#?}{#?}',\n });\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
5
+ describe('mathlive-instance', function () {
6
+ var instance;
7
+ beforeEach(function () {
8
+ jest.resetModules();
9
+ // eslint-disable-next-line global-require
10
+ instance = require('../mathlive-instance');
11
+ instance.__resetEmbeds();
12
+ });
13
+ describe('registerEmbed', function () {
14
+ it('registers a known embed and exposes it as a macro', function () {
15
+ instance.registerEmbed('answerBlock', function () {
16
+ return {
17
+ htmlString: '<div class="answerBlock"></div>',
18
+ latex: function latex() {
19
+ return '\\embed{answerBlock}[]';
20
+ }
21
+ };
22
+ });
23
+ expect(instance.registeredEmbeds()).toEqual(['answerBlock']);
24
+ // The macro tags output with data-embed so CSS can target it, replacing
25
+ // MathQuill's htmlString hook.
26
+ expect(instance.getMacros().answerBlock).toEqual('\\htmlData{embed=answerBlock}{\\placeholder{}}');
27
+ });
28
+ it('registers newLine as a harmless macro (it is handled by latex-bridge)', function () {
29
+ instance.registerEmbed('newLine', function () {
30
+ return {
31
+ latex: function latex() {
32
+ return '\\embed{newLine}[]';
33
+ }
34
+ };
35
+ });
36
+ expect(instance.getMacros().newLine).toEqual('\\htmlData{embed=newLine}{}');
37
+ });
38
+ it('falls back to a placeholder for an unknown embed', function () {
39
+ instance.registerEmbed('somethingCustom', function () {
40
+ return {
41
+ htmlString: '<b>x</b>'
42
+ };
43
+ });
44
+ expect(instance.getMacros().somethingCustom).toEqual('\\htmlData{embed=somethingCustom}{\\placeholder{}}');
45
+ });
46
+ it('honours an explicit mathliveLatex from the factory', function () {
47
+ instance.registerEmbed('custom', function () {
48
+ return {
49
+ mathliveLatex: '\\alpha'
50
+ };
51
+ });
52
+ expect(instance.getMacros().custom).toEqual('\\htmlData{embed=custom}{\\alpha}');
53
+ });
54
+ it('does not throw when the factory throws', function () {
55
+ expect(function () {
56
+ return instance.registerEmbed('bad', function () {
57
+ throw new Error('boom');
58
+ });
59
+ }).not.toThrow();
60
+ expect(instance.registeredEmbeds()).toEqual(['bad']);
61
+ });
62
+ it('ignores bad arguments', function () {
63
+ instance.registerEmbed(undefined, function () {
64
+ return {};
65
+ });
66
+ instance.registerEmbed('noFactory', undefined);
67
+ expect(instance.registeredEmbeds()).toEqual([]);
68
+ });
69
+ it('always includes the pie macro set', function () {
70
+ var macros = instance.getMacros();
71
+ expect(macros.parallelogram).toBeDefined();
72
+ expect(macros.longdiv).toBeDefined();
73
+ expect(macros.napprox).toEqual('\\not\\approx');
74
+ });
75
+
76
+ // Argument-taking macros exist only so previously authored latex parses.
77
+ // Editing never goes through them: MathLive serialises a macro from its
78
+ // original arguments, so typed content never comes back out.
79
+ it('argument-taking macros are plain parse-only definitions', function () {
80
+ ['longdiv', 'overarc', 'abs'].forEach(function (name) {
81
+ expect((0, _typeof2["default"])(instance.PIE_MACROS[name])).toBe('string');
82
+ expect(instance.PIE_MACROS[name]).toContain('#1');
83
+ });
84
+ });
85
+ it('argument-less symbols stay atomic', function () {
86
+ ['perpendicular', 'square', 'degree', 'napprox', 'parallelogram'].forEach(function (name) {
87
+ expect((0, _typeof2["default"])(instance.PIE_MACROS[name])).toBe('string');
88
+ });
89
+ });
90
+ it('longdiv matches the MathJax macro used by math-rendering', function () {
91
+ expect(instance.PIE_MACROS.longdiv).toEqual('\\enclose{longdiv}{#1}');
92
+ });
93
+ });
94
+ describe('applyStaticMath', function () {
95
+ it('returns undefined without an element', function () {
96
+ expect(instance.applyStaticMath(null, 'x')).toBeUndefined();
97
+ });
98
+ it('defers (returns undefined) when MathLive has not loaded', function () {
99
+ var el = document.createElement('div');
100
+ expect(instance.applyStaticMath(el, 'x')).toBeUndefined();
101
+ });
102
+ it('renders synchronously once MathLive is available', function () {
103
+ var el = document.createElement('div');
104
+ instance.__setMathLiveForTest({
105
+ convertLatexToMarkup: function convertLatexToMarkup(l) {
106
+ return "<span>".concat(l, "</span>");
107
+ }
108
+ });
109
+ expect(instance.applyStaticMath(el, '\\pi')).toBe(el);
110
+ expect(el.innerHTML).toEqual('<span>\\pi</span>');
111
+ });
112
+ it('falls back to the element textContent when no latex is passed', function () {
113
+ var el = document.createElement('div');
114
+ el.textContent = '\\theta';
115
+ instance.__setMathLiveForTest({
116
+ convertLatexToMarkup: function convertLatexToMarkup(l) {
117
+ return "<i>".concat(l, "</i>");
118
+ }
119
+ });
120
+ instance.applyStaticMath(el);
121
+ expect(el.innerHTML).toEqual('<i>\\theta</i>');
122
+ });
123
+ it('bridges stored latex (newLine embed) before rendering', function () {
124
+ var el = document.createElement('div');
125
+ instance.__setMathLiveForTest({
126
+ convertLatexToMarkup: function convertLatexToMarkup(l) {
127
+ return l;
128
+ }
129
+ });
130
+ instance.applyStaticMath(el, 'a\\embed{newLine}[]b');
131
+
132
+ // \embed{newLine}[] must become a multiline environment
133
+ expect(el.innerHTML).toContain('displaylines');
134
+ });
135
+ });
136
+ describe('configureFonts', function () {
137
+ // MathLive's default fontsDirectory is the relative './fonts/', which it
138
+ // resolves against its own (empty, when bundled) script url and throws
139
+ // "Invalid base URL" from loadFonts. Paths must become absolute.
140
+ it('is exported and callable before MathLive loads', function () {
141
+ expect((0, _typeof2["default"])(instance.configureFonts)).toBe('function');
142
+ expect(function () {
143
+ return instance.configureFonts('/mathlive-fonts');
144
+ }).not.toThrow();
145
+ });
146
+ it('accepts null to disable font loading', function () {
147
+ expect(function () {
148
+ return instance.configureFonts(null);
149
+ }).not.toThrow();
150
+ });
151
+ it('applies an absolute url to an already-loaded MathfieldElement', function () {
152
+ var MathfieldElement = {};
153
+
154
+ // simulate a loaded instance
155
+ instance.__setMathLiveForTest({
156
+ MathfieldElement: MathfieldElement
157
+ });
158
+ instance.configureFonts('/mathlive-fonts');
159
+ expect(MathfieldElement.fontsDirectory).toEqual("".concat(document.baseURI.replace(/\/$/, ''), "/mathlive-fonts"));
160
+ expect(MathfieldElement.fontsDirectory.startsWith('http')).toBe(true);
161
+ });
162
+
163
+ // \neq, \nsim and \ncong are built from Private Use Area glyphs that only
164
+ // the KaTeX fonts contain, so "no fonts" renders garbage rather than
165
+ // degrading gracefully - hence a CDN fallback by default.
166
+ it('falls back to a version-pinned CDN when nothing is configured', function () {
167
+ var MathfieldElement = {};
168
+ instance.__setMathLiveForTest({
169
+ MathfieldElement: MathfieldElement,
170
+ version: {
171
+ mathlive: '9.9.9'
172
+ }
173
+ });
174
+ instance.configureFonts(undefined);
175
+ expect(MathfieldElement.fontsDirectory).toEqual('https://unpkg.com/mathlive@9.9.9/fonts');
176
+ });
177
+ it('uses /fonts, not /dist/fonts (the latter 404s on unpkg)', function () {
178
+ var MathfieldElement = {};
179
+ instance.__setMathLiveForTest({
180
+ MathfieldElement: MathfieldElement,
181
+ version: {
182
+ mathlive: '0.110.0'
183
+ }
184
+ });
185
+ instance.configureFonts(undefined);
186
+ expect(MathfieldElement.fontsDirectory).toEqual('https://unpkg.com/mathlive@0.110.0/fonts');
187
+ expect(MathfieldElement.fontsDirectory).not.toContain('/dist/');
188
+ });
189
+ it('a configured path wins over the CDN', function () {
190
+ var MathfieldElement = {};
191
+ instance.__setMathLiveForTest({
192
+ MathfieldElement: MathfieldElement,
193
+ version: {
194
+ mathlive: '0.110.0'
195
+ }
196
+ });
197
+ instance.configureFonts('/mathlive-fonts');
198
+ expect(MathfieldElement.fontsDirectory).not.toContain('unpkg.com');
199
+ });
200
+ it('null still opts out entirely', function () {
201
+ var MathfieldElement = {};
202
+ instance.__setMathLiveForTest({
203
+ MathfieldElement: MathfieldElement,
204
+ version: {
205
+ mathlive: '0.110.0'
206
+ }
207
+ });
208
+ instance.configureFonts(null);
209
+ expect(MathfieldElement.fontsDirectory).toBeNull();
210
+ });
211
+ it('leaves a fully-qualified url untouched', function () {
212
+ var MathfieldElement = {};
213
+ instance.__setMathLiveForTest({
214
+ MathfieldElement: MathfieldElement
215
+ });
216
+ instance.configureFonts('https://cdn.example.com/fonts');
217
+ expect(MathfieldElement.fontsDirectory).toEqual('https://cdn.example.com/fonts');
218
+ });
219
+ it('passes null through rather than resolving it', function () {
220
+ var MathfieldElement = {};
221
+ instance.__setMathLiveForTest({
222
+ MathfieldElement: MathfieldElement
223
+ });
224
+ instance.configureFonts(null);
225
+ expect(MathfieldElement.fontsDirectory).toBeNull();
226
+ });
227
+ });
228
+
229
+ // A live <math-field> renders in shadow DOM, so nothing in the page's
230
+ // stylesheets reaches it - the stretchy-accent fix has to be injected there.
231
+ describe('applyShadowStyles', function () {
232
+ var host = function host() {
233
+ var el = document.createElement('div');
234
+ el.attachShadow({
235
+ mode: 'open'
236
+ });
237
+ return el;
238
+ };
239
+ it('is a no-op without a shadow root', function () {
240
+ expect(function () {
241
+ return instance.applyShadowStyles(undefined);
242
+ }).not.toThrow();
243
+ expect(function () {
244
+ return instance.applyShadowStyles(document.createElement('div'));
245
+ }).not.toThrow();
246
+ });
247
+ it('injects the accent fix into the shadow root', function () {
248
+ var el = host();
249
+ instance.applyShadowStyles(el);
250
+ var viaSheet = el.shadowRoot.__pieAccentSheet;
251
+ var viaStyle = el.shadowRoot.querySelector('style[data-pie-accent]');
252
+ var css = viaSheet ? 'adopted' : viaStyle && viaStyle.textContent || '';
253
+ expect(viaSheet || viaStyle).toBeTruthy();
254
+ if (viaStyle) {
255
+ expect(css).toContain('margin-left:0 !important');
256
+ // scoped so single-glyph accents keep their centring offset
257
+ expect(css).toContain(':has(.ML__stretchy)');
258
+ }
259
+ });
260
+ it('does not inject twice', function () {
261
+ var el = host();
262
+ instance.applyShadowStyles(el);
263
+ instance.applyShadowStyles(el);
264
+ var styles = el.shadowRoot.querySelectorAll('style[data-pie-accent]');
265
+
266
+ // either one adopted sheet, or exactly one style node
267
+ expect(el.shadowRoot.__pieAccentSheet ? 1 : styles.length).toBe(1);
268
+ });
269
+ });
270
+ describe('latexToMarkup', function () {
271
+ it('returns empty string when MathLive is not loaded', function () {
272
+ expect(instance.latexToMarkup('\\pi')).toEqual('');
273
+ });
274
+ it('returns empty string for empty latex', function () {
275
+ expect(instance.latexToMarkup('')).toEqual('');
276
+ });
277
+ });
278
+ });
279
+ //# sourceMappingURL=mathlive-instance.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mathlive-instance.test.js","names":["describe","instance","beforeEach","jest","resetModules","require","__resetEmbeds","it","registerEmbed","htmlString","latex","expect","registeredEmbeds","toEqual","getMacros","answerBlock","newLine","somethingCustom","mathliveLatex","custom","Error","not","toThrow","undefined","macros","parallelogram","toBeDefined","longdiv","napprox","forEach","name","_typeof2","PIE_MACROS","toBe","toContain","applyStaticMath","toBeUndefined","el","document","createElement","__setMathLiveForTest","convertLatexToMarkup","l","concat","innerHTML","textContent","configureFonts","MathfieldElement","fontsDirectory","baseURI","replace","startsWith","version","mathlive","toBeNull","host","attachShadow","mode","applyShadowStyles","viaSheet","shadowRoot","__pieAccentSheet","viaStyle","querySelector","css","toBeTruthy","styles","querySelectorAll","length","latexToMarkup"],"sources":["../../src/__tests__/mathlive-instance.test.js"],"sourcesContent":["describe('mathlive-instance', () => {\n let instance;\n\n beforeEach(() => {\n jest.resetModules();\n // eslint-disable-next-line global-require\n instance = require('../mathlive-instance');\n instance.__resetEmbeds();\n });\n\n describe('registerEmbed', () => {\n it('registers a known embed and exposes it as a macro', () => {\n instance.registerEmbed('answerBlock', () => ({\n htmlString: '<div class=\"answerBlock\"></div>',\n latex: () => '\\\\embed{answerBlock}[]',\n }));\n\n expect(instance.registeredEmbeds()).toEqual(['answerBlock']);\n // The macro tags output with data-embed so CSS can target it, replacing\n // MathQuill's htmlString hook.\n expect(instance.getMacros().answerBlock).toEqual('\\\\htmlData{embed=answerBlock}{\\\\placeholder{}}');\n });\n\n it('registers newLine as a harmless macro (it is handled by latex-bridge)', () => {\n instance.registerEmbed('newLine', () => ({ latex: () => '\\\\embed{newLine}[]' }));\n\n expect(instance.getMacros().newLine).toEqual('\\\\htmlData{embed=newLine}{}');\n });\n\n it('falls back to a placeholder for an unknown embed', () => {\n instance.registerEmbed('somethingCustom', () => ({ htmlString: '<b>x</b>' }));\n\n expect(instance.getMacros().somethingCustom).toEqual('\\\\htmlData{embed=somethingCustom}{\\\\placeholder{}}');\n });\n\n it('honours an explicit mathliveLatex from the factory', () => {\n instance.registerEmbed('custom', () => ({ mathliveLatex: '\\\\alpha' }));\n\n expect(instance.getMacros().custom).toEqual('\\\\htmlData{embed=custom}{\\\\alpha}');\n });\n\n it('does not throw when the factory throws', () => {\n expect(() =>\n instance.registerEmbed('bad', () => {\n throw new Error('boom');\n }),\n ).not.toThrow();\n\n expect(instance.registeredEmbeds()).toEqual(['bad']);\n });\n\n it('ignores bad arguments', () => {\n instance.registerEmbed(undefined, () => ({}));\n instance.registerEmbed('noFactory', undefined);\n\n expect(instance.registeredEmbeds()).toEqual([]);\n });\n\n it('always includes the pie macro set', () => {\n const macros = instance.getMacros();\n\n expect(macros.parallelogram).toBeDefined();\n expect(macros.longdiv).toBeDefined();\n expect(macros.napprox).toEqual('\\\\not\\\\approx');\n });\n\n // Argument-taking macros exist only so previously authored latex parses.\n // Editing never goes through them: MathLive serialises a macro from its\n // original arguments, so typed content never comes back out.\n it('argument-taking macros are plain parse-only definitions', () => {\n ['longdiv', 'overarc', 'abs'].forEach((name) => {\n expect(typeof instance.PIE_MACROS[name]).toBe('string');\n expect(instance.PIE_MACROS[name]).toContain('#1');\n });\n });\n\n it('argument-less symbols stay atomic', () => {\n ['perpendicular', 'square', 'degree', 'napprox', 'parallelogram'].forEach((name) => {\n expect(typeof instance.PIE_MACROS[name]).toBe('string');\n });\n });\n\n it('longdiv matches the MathJax macro used by math-rendering', () => {\n expect(instance.PIE_MACROS.longdiv).toEqual('\\\\enclose{longdiv}{#1}');\n });\n });\n\n describe('applyStaticMath', () => {\n it('returns undefined without an element', () => {\n expect(instance.applyStaticMath(null, 'x')).toBeUndefined();\n });\n\n it('defers (returns undefined) when MathLive has not loaded', () => {\n const el = document.createElement('div');\n\n expect(instance.applyStaticMath(el, 'x')).toBeUndefined();\n });\n\n it('renders synchronously once MathLive is available', () => {\n const el = document.createElement('div');\n\n instance.__setMathLiveForTest({ convertLatexToMarkup: (l) => `<span>${l}</span>` });\n\n expect(instance.applyStaticMath(el, '\\\\pi')).toBe(el);\n expect(el.innerHTML).toEqual('<span>\\\\pi</span>');\n });\n\n it('falls back to the element textContent when no latex is passed', () => {\n const el = document.createElement('div');\n\n el.textContent = '\\\\theta';\n instance.__setMathLiveForTest({ convertLatexToMarkup: (l) => `<i>${l}</i>` });\n instance.applyStaticMath(el);\n\n expect(el.innerHTML).toEqual('<i>\\\\theta</i>');\n });\n\n it('bridges stored latex (newLine embed) before rendering', () => {\n const el = document.createElement('div');\n\n instance.__setMathLiveForTest({ convertLatexToMarkup: (l) => l });\n instance.applyStaticMath(el, 'a\\\\embed{newLine}[]b');\n\n // \\embed{newLine}[] must become a multiline environment\n expect(el.innerHTML).toContain('displaylines');\n });\n });\n\n describe('configureFonts', () => {\n // MathLive's default fontsDirectory is the relative './fonts/', which it\n // resolves against its own (empty, when bundled) script url and throws\n // \"Invalid base URL\" from loadFonts. Paths must become absolute.\n it('is exported and callable before MathLive loads', () => {\n expect(typeof instance.configureFonts).toBe('function');\n expect(() => instance.configureFonts('/mathlive-fonts')).not.toThrow();\n });\n\n it('accepts null to disable font loading', () => {\n expect(() => instance.configureFonts(null)).not.toThrow();\n });\n\n it('applies an absolute url to an already-loaded MathfieldElement', () => {\n const MathfieldElement = {};\n\n // simulate a loaded instance\n instance.__setMathLiveForTest({ MathfieldElement });\n instance.configureFonts('/mathlive-fonts');\n\n expect(MathfieldElement.fontsDirectory).toEqual(`${document.baseURI.replace(/\\/$/, '')}/mathlive-fonts`);\n expect(MathfieldElement.fontsDirectory.startsWith('http')).toBe(true);\n });\n\n // \\neq, \\nsim and \\ncong are built from Private Use Area glyphs that only\n // the KaTeX fonts contain, so \"no fonts\" renders garbage rather than\n // degrading gracefully - hence a CDN fallback by default.\n it('falls back to a version-pinned CDN when nothing is configured', () => {\n const MathfieldElement = {};\n\n instance.__setMathLiveForTest({ MathfieldElement, version: { mathlive: '9.9.9' } });\n instance.configureFonts(undefined);\n\n expect(MathfieldElement.fontsDirectory).toEqual('https://unpkg.com/mathlive@9.9.9/fonts');\n });\n\n it('uses /fonts, not /dist/fonts (the latter 404s on unpkg)', () => {\n const MathfieldElement = {};\n\n instance.__setMathLiveForTest({ MathfieldElement, version: { mathlive: '0.110.0' } });\n instance.configureFonts(undefined);\n\n expect(MathfieldElement.fontsDirectory).toEqual('https://unpkg.com/mathlive@0.110.0/fonts');\n expect(MathfieldElement.fontsDirectory).not.toContain('/dist/');\n });\n\n it('a configured path wins over the CDN', () => {\n const MathfieldElement = {};\n\n instance.__setMathLiveForTest({ MathfieldElement, version: { mathlive: '0.110.0' } });\n instance.configureFonts('/mathlive-fonts');\n\n expect(MathfieldElement.fontsDirectory).not.toContain('unpkg.com');\n });\n\n it('null still opts out entirely', () => {\n const MathfieldElement = {};\n\n instance.__setMathLiveForTest({ MathfieldElement, version: { mathlive: '0.110.0' } });\n instance.configureFonts(null);\n\n expect(MathfieldElement.fontsDirectory).toBeNull();\n });\n\n it('leaves a fully-qualified url untouched', () => {\n const MathfieldElement = {};\n\n instance.__setMathLiveForTest({ MathfieldElement });\n instance.configureFonts('https://cdn.example.com/fonts');\n\n expect(MathfieldElement.fontsDirectory).toEqual('https://cdn.example.com/fonts');\n });\n\n it('passes null through rather than resolving it', () => {\n const MathfieldElement = {};\n\n instance.__setMathLiveForTest({ MathfieldElement });\n instance.configureFonts(null);\n\n expect(MathfieldElement.fontsDirectory).toBeNull();\n });\n });\n\n // A live <math-field> renders in shadow DOM, so nothing in the page's\n // stylesheets reaches it - the stretchy-accent fix has to be injected there.\n describe('applyShadowStyles', () => {\n const host = () => {\n const el = document.createElement('div');\n\n el.attachShadow({ mode: 'open' });\n\n return el;\n };\n\n it('is a no-op without a shadow root', () => {\n expect(() => instance.applyShadowStyles(undefined)).not.toThrow();\n expect(() => instance.applyShadowStyles(document.createElement('div'))).not.toThrow();\n });\n\n it('injects the accent fix into the shadow root', () => {\n const el = host();\n\n instance.applyShadowStyles(el);\n\n const viaSheet = el.shadowRoot.__pieAccentSheet;\n const viaStyle = el.shadowRoot.querySelector('style[data-pie-accent]');\n const css = viaSheet ? 'adopted' : (viaStyle && viaStyle.textContent) || '';\n\n expect(viaSheet || viaStyle).toBeTruthy();\n\n if (viaStyle) {\n expect(css).toContain('margin-left:0 !important');\n // scoped so single-glyph accents keep their centring offset\n expect(css).toContain(':has(.ML__stretchy)');\n }\n });\n\n it('does not inject twice', () => {\n const el = host();\n\n instance.applyShadowStyles(el);\n instance.applyShadowStyles(el);\n\n const styles = el.shadowRoot.querySelectorAll('style[data-pie-accent]');\n\n // either one adopted sheet, or exactly one style node\n expect(el.shadowRoot.__pieAccentSheet ? 1 : styles.length).toBe(1);\n });\n });\n\n describe('latexToMarkup', () => {\n it('returns empty string when MathLive is not loaded', () => {\n expect(instance.latexToMarkup('\\\\pi')).toEqual('');\n });\n\n it('returns empty string for empty latex', () => {\n expect(instance.latexToMarkup('')).toEqual('');\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}