@pie-lib/math-input-mathlive 1.0.11 → 1.0.12
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/lib/keys/misc.js +9 -2
- package/lib/keys/misc.js.map +1 -1
- package/lib/latex-bridge.js +30 -0
- package/lib/latex-bridge.js.map +1 -1
- package/lib/mathlive-instance.js +67 -3
- package/lib/mathlive-instance.js.map +1 -1
- package/lib/mf/input.js +7 -0
- package/lib/mf/input.js.map +1 -1
- package/lib/mf/static.js +82 -1
- package/lib/mf/static.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/keypad-label.test.jsx +58 -5
- package/src/__tests__/latex-bridge.test.js +22 -0
- package/src/__tests__/mathlive-instance.test.js +128 -0
- package/src/__tests__/mount-race.test.jsx +1 -0
- package/src/__tests__/static-prompts.test.jsx +113 -0
- package/src/keys/misc.js +8 -2
- package/src/latex-bridge.js +34 -0
- package/src/mathlive-instance.js +75 -1
- package/src/mf/input.jsx +15 -1
- package/src/mf/static.jsx +94 -2
- package/lib/__tests__/composites.test.js +0 -255
- package/lib/__tests__/composites.test.js.map +0 -1
- package/lib/__tests__/drop-in-compat.test.js +0 -133
- package/lib/__tests__/drop-in-compat.test.js.map +0 -1
- package/lib/__tests__/index.test.js +0 -118
- package/lib/__tests__/index.test.js.map +0 -1
- package/lib/__tests__/input-imperative.test.js +0 -155
- package/lib/__tests__/input-imperative.test.js.map +0 -1
- package/lib/__tests__/keypad-label.test.js +0 -118
- package/lib/__tests__/keypad-label.test.js.map +0 -1
- package/lib/__tests__/keypad-render.test.js +0 -206
- package/lib/__tests__/keypad-render.test.js.map +0 -1
- package/lib/__tests__/latex-bridge.test.js +0 -280
- package/lib/__tests__/latex-bridge.test.js.map +0 -1
- package/lib/__tests__/mathlive-instance.test.js +0 -279
- package/lib/__tests__/mathlive-instance.test.js.map +0 -1
- package/lib/__tests__/mount-race.test.js +0 -195
- package/lib/__tests__/mount-race.test.js.map +0 -1
- package/lib/__tests__/static-prompts.test.js +0 -282
- package/lib/__tests__/static-prompts.test.js.map +0 -1
package/src/keys/misc.js
CHANGED
|
@@ -29,10 +29,16 @@ export const brackets = set({
|
|
|
29
29
|
command: '[',
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
+
// `%` must be escaped. MathQuill was not a real LaTeX parser: it defined
|
|
33
|
+
// `LatexCmds['%']` as a symbol that *serialised* to `\%`, so a bare `%` worked
|
|
34
|
+
// both as a label and as a command. MathLive parses LaTeX properly, where `%`
|
|
35
|
+
// begins a comment - it rendered nothing (a blank button) and, once inserted,
|
|
36
|
+
// silently swallowed the rest of the expression. `\%` is what MathQuill stored
|
|
37
|
+
// all along, so this changes the key only, not the saved latex.
|
|
32
38
|
export const percentage = set({
|
|
33
39
|
name: 'Percent',
|
|
34
|
-
latex: '
|
|
35
|
-
command: '
|
|
40
|
+
latex: '\\%',
|
|
41
|
+
command: '\\%',
|
|
36
42
|
});
|
|
37
43
|
|
|
38
44
|
export const approx = set({
|
package/src/latex-bridge.js
CHANGED
|
@@ -114,6 +114,40 @@ export const toNativeCommands = (latex) => {
|
|
|
114
114
|
out = replaceAbs(out);
|
|
115
115
|
out = out.replace(/\\longdiv\{/g, '\\enclose{longdiv}{');
|
|
116
116
|
out = out.replace(/\\overarc\{/g, '\\overparen{');
|
|
117
|
+
out = escapeBareComments(out);
|
|
118
|
+
|
|
119
|
+
return out;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Escape an unescaped `%`.
|
|
124
|
+
*
|
|
125
|
+
* In real LaTeX `%` starts a comment, so MathLive discards it *and everything
|
|
126
|
+
* after it*: `50%` renders as `50`, and `x%y` as just `x`. MathQuill had no
|
|
127
|
+
* such notion - it treated `%` as a symbol - so latex from anywhere outside the
|
|
128
|
+
* keypad may still carry a bare one.
|
|
129
|
+
*
|
|
130
|
+
* Only a `%` preceded by an even number of backslashes is bare: `\%` is already
|
|
131
|
+
* escaped, while the `%` in `\\%` (a line break, then a comment) is not.
|
|
132
|
+
*
|
|
133
|
+
* @param {string} latex
|
|
134
|
+
* @returns {string}
|
|
135
|
+
*/
|
|
136
|
+
const escapeBareComments = (latex) => {
|
|
137
|
+
if (latex.indexOf('%') === -1) {
|
|
138
|
+
return latex;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let out = '';
|
|
142
|
+
// Consecutive backslashes immediately before the current character.
|
|
143
|
+
let backslashes = 0;
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < latex.length; i++) {
|
|
146
|
+
const ch = latex[i];
|
|
147
|
+
|
|
148
|
+
out += ch === '%' && backslashes % 2 === 0 ? '\\%' : ch;
|
|
149
|
+
backslashes = ch === '\\' ? backslashes + 1 : 0;
|
|
150
|
+
}
|
|
117
151
|
|
|
118
152
|
return out;
|
|
119
153
|
};
|
package/src/mathlive-instance.js
CHANGED
|
@@ -196,7 +196,81 @@ const configureLoaded = () => {
|
|
|
196
196
|
* `:has(.ML__stretchy)` keeps the fix to stretchy accents; single-glyph accents
|
|
197
197
|
* (`\hat{x}`, `\vec{x}`) still need their centring offset.
|
|
198
198
|
*/
|
|
199
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Marker put on the host `<math-field>` while a `\placeholder{}` is selected,
|
|
201
|
+
* so the caret rules below apply to a placeholder and nothing else.
|
|
202
|
+
*/
|
|
203
|
+
export const PLACEHOLDER_CARET_CLASS = 'pie-caret-in-placeholder';
|
|
204
|
+
|
|
205
|
+
/** What MathLive serialises a `#?` slot as. */
|
|
206
|
+
const PLACEHOLDER_LATEX = '\\placeholder{}';
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* A blinking caret inside a selected placeholder box.
|
|
210
|
+
*
|
|
211
|
+
* A keypad key such as `\frac` inserts `\frac{#?}{#?}`. MathLive turns each
|
|
212
|
+
* `#?` into a `\placeholder{}` atom and *selects* the first one. That atom is a
|
|
213
|
+
* leaf - the offsets around it are "before" and "after", there is no position
|
|
214
|
+
* inside it - so MathLive renders **no caret element at all** and shows only
|
|
215
|
+
* the selection highlight. The box therefore looked focused (blue) but dead,
|
|
216
|
+
* where MathQuill used to blink a cursor inside its empty box.
|
|
217
|
+
*
|
|
218
|
+
* So the caret is drawn here. `:not(:has(.ML__selected))` picks the innermost
|
|
219
|
+
* selected element (MathLive puts the class on a wrapper *and* the glyph span,
|
|
220
|
+
* which would otherwise give two carets), and the `ML__caret-blink` keyframes
|
|
221
|
+
* plus `--_caret-color` are MathLive's own, already in this shadow root.
|
|
222
|
+
*
|
|
223
|
+
* Typing still replaces the whole placeholder, which for an empty box is
|
|
224
|
+
* indistinguishable from inserting at the caret.
|
|
225
|
+
*/
|
|
226
|
+
const PLACEHOLDER_CARET_CSS = [
|
|
227
|
+
`:host(.${PLACEHOLDER_CARET_CLASS}) .ML__selected:not(:has(.ML__selected)){position:relative}`,
|
|
228
|
+
`:host(.${PLACEHOLDER_CARET_CLASS}) .ML__selected:not(:has(.ML__selected))::after{`,
|
|
229
|
+
'content:"";position:absolute;left:50%;top:12%;height:76%;',
|
|
230
|
+
'border-right:2px solid var(--_caret-color, currentColor);',
|
|
231
|
+
'animation:ML__caret-blink 1.05s step-end forwards infinite}',
|
|
232
|
+
].join('');
|
|
233
|
+
|
|
234
|
+
const SHADOW_CSS = '.ML__latex .ML__center:has(.ML__stretchy){margin-left:0 !important}' + PLACEHOLDER_CARET_CSS;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Keep {@link PLACEHOLDER_CARET_CLASS} in step with the selection.
|
|
238
|
+
*
|
|
239
|
+
* Gating on the class is what keeps the caret specific to placeholders: an
|
|
240
|
+
* ordinary selection (`x+1`) must not sprout one. MathLive fires
|
|
241
|
+
* `selection-change` for every caret move, including the one that lands on the
|
|
242
|
+
* placeholder straight after an insert.
|
|
243
|
+
*
|
|
244
|
+
* @param {HTMLElement} mathField
|
|
245
|
+
* @returns {function|undefined} teardown, to call on unmount
|
|
246
|
+
*/
|
|
247
|
+
export const trackPlaceholderCaret = (mathField) => {
|
|
248
|
+
if (!mathField || typeof mathField.addEventListener !== 'function') {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const update = () => {
|
|
253
|
+
let selected = '';
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
// A collapsed selection already has a real MathLive caret.
|
|
257
|
+
if (!mathField.selectionIsCollapsed && mathField.selection) {
|
|
258
|
+
selected = mathField.getValue(mathField.selection, 'latex');
|
|
259
|
+
}
|
|
260
|
+
} catch (e) {
|
|
261
|
+
log('could not read the selection: %s', e && e.message);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (mathField.classList) {
|
|
265
|
+
mathField.classList.toggle(PLACEHOLDER_CARET_CLASS, selected === PLACEHOLDER_LATEX);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
mathField.addEventListener('selection-change', update);
|
|
270
|
+
update();
|
|
271
|
+
|
|
272
|
+
return () => mathField.removeEventListener('selection-change', update);
|
|
273
|
+
};
|
|
200
274
|
|
|
201
275
|
/**
|
|
202
276
|
* Apply {@link SHADOW_CSS} inside a mathfield's shadow root.
|
package/src/mf/input.jsx
CHANGED
|
@@ -2,7 +2,13 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { styled } from '@mui/material/styles';
|
|
4
4
|
import debug from 'debug';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
loadMathLive,
|
|
7
|
+
getMacros,
|
|
8
|
+
MATH_MODE_SPACE,
|
|
9
|
+
applyShadowStyles,
|
|
10
|
+
trackPlaceholderCaret,
|
|
11
|
+
} from '../mathlive-instance';
|
|
6
12
|
import { toMathLive, fromMathLive, keyToAction, KEYSTROKES } from '../latex-bridge';
|
|
7
13
|
|
|
8
14
|
const log = debug('pie-lib:math-input-mathlive:input');
|
|
@@ -79,6 +85,9 @@ export class Input extends React.Component {
|
|
|
79
85
|
// stretchy-accent fix has to be injected there directly.
|
|
80
86
|
applyShadowStyles(this.mathField);
|
|
81
87
|
|
|
88
|
+
// A selected `\placeholder{}` gets no MathLive caret; draw one.
|
|
89
|
+
this.untrackCaret = trackPlaceholderCaret(this.mathField);
|
|
90
|
+
|
|
82
91
|
this.mathField.addEventListener('input', this.onInputEdit);
|
|
83
92
|
|
|
84
93
|
// Belt and braces: drop anything a previous mount may have left behind.
|
|
@@ -117,6 +126,11 @@ export class Input extends React.Component {
|
|
|
117
126
|
// append a field into a holder that is going away.
|
|
118
127
|
this.mountGeneration = (this.mountGeneration || 0) + 1;
|
|
119
128
|
|
|
129
|
+
if (this.untrackCaret) {
|
|
130
|
+
this.untrackCaret();
|
|
131
|
+
this.untrackCaret = undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
120
134
|
if (this.mathField) {
|
|
121
135
|
this.mathField.removeEventListener('input', this.onInputEdit);
|
|
122
136
|
this.mathField.remove();
|
package/src/mf/static.jsx
CHANGED
|
@@ -2,7 +2,14 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { styled } from '@mui/material/styles';
|
|
4
4
|
import debug from 'debug';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
loadMathLive,
|
|
7
|
+
getMacros,
|
|
8
|
+
latexToMarkup,
|
|
9
|
+
MATH_MODE_SPACE,
|
|
10
|
+
applyShadowStyles,
|
|
11
|
+
trackPlaceholderCaret,
|
|
12
|
+
} from '../mathlive-instance';
|
|
6
13
|
import { toMathLive, fromMathLive, fieldIds } from '../latex-bridge';
|
|
7
14
|
import { placeholderStyles } from './common-styles';
|
|
8
15
|
|
|
@@ -97,6 +104,10 @@ export default class Static extends React.Component {
|
|
|
97
104
|
// stretchy-accent fix has to be injected there directly.
|
|
98
105
|
applyShadowStyles(this.mathField);
|
|
99
106
|
|
|
107
|
+
// A selected `\placeholder{}` gets no MathLive caret; draw one. Answer
|
|
108
|
+
// blocks are typed into with the same keypad, so they grow placeholders too.
|
|
109
|
+
this.untrackCaret = trackPlaceholderCaret(this.mathField);
|
|
110
|
+
|
|
100
111
|
this.mathField.addEventListener('input', this.onPromptInput);
|
|
101
112
|
this.mathField.addEventListener('focusin', this.onPromptFocus);
|
|
102
113
|
this.mathField.addEventListener('keydown', this.onKeyDown);
|
|
@@ -123,6 +134,11 @@ export default class Static extends React.Component {
|
|
|
123
134
|
// Invalidate any mount still awaiting the MathLive load.
|
|
124
135
|
this.mountGeneration = (this.mountGeneration || 0) + 1;
|
|
125
136
|
|
|
137
|
+
if (this.untrackCaret) {
|
|
138
|
+
this.untrackCaret();
|
|
139
|
+
this.untrackCaret = undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
126
142
|
if (this.mathField) {
|
|
127
143
|
this.mathField.removeEventListener('input', this.onPromptInput);
|
|
128
144
|
this.mathField.removeEventListener('focusin', this.onPromptFocus);
|
|
@@ -254,6 +270,13 @@ export default class Static extends React.Component {
|
|
|
254
270
|
promptHandle(id) {
|
|
255
271
|
return {
|
|
256
272
|
id,
|
|
273
|
+
// MathQuill's inner fields could be focused directly; keep that.
|
|
274
|
+
focus: () => {
|
|
275
|
+
if (this.mathField) {
|
|
276
|
+
this.mathField.focus();
|
|
277
|
+
this.focusPrompt(id);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
257
280
|
latex: (value) => {
|
|
258
281
|
if (!this.mathField) {
|
|
259
282
|
return '';
|
|
@@ -351,8 +374,77 @@ export default class Static extends React.Component {
|
|
|
351
374
|
}
|
|
352
375
|
};
|
|
353
376
|
|
|
377
|
+
/** The id of the prompt whose range contains `position`, if any. */
|
|
378
|
+
promptContaining(position) {
|
|
379
|
+
if (!this.mathField || typeof position !== 'number') {
|
|
380
|
+
return undefined;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return (this.mathField.getPrompts() || []).find((id) => {
|
|
384
|
+
const range = this.mathField.getPromptRange(id);
|
|
385
|
+
|
|
386
|
+
return range && position >= range[0] && position <= range[1];
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Put a blinking caret inside an answer block.
|
|
392
|
+
*
|
|
393
|
+
* MathLive only makes the caret visible while the field element carries the
|
|
394
|
+
* `ML__focused` class, and it adds that class during a *render*, gated on
|
|
395
|
+
* `isSelectionEditable && hasFocus()`. In a read-only field only prompt
|
|
396
|
+
* interiors are editable, so the two things both have to be true:
|
|
397
|
+
*
|
|
398
|
+
* - the selection must sit inside a prompt, and
|
|
399
|
+
* - a render must run afterwards.
|
|
400
|
+
*
|
|
401
|
+
* Assigning `selection` satisfies the first but not the second - it updates
|
|
402
|
+
* the model without re-rendering, so the class stays off and the caret span
|
|
403
|
+
* remains `visibility: hidden`. Executing any command does trigger the
|
|
404
|
+
* render, and `scrollIntoView` is the one with no other effect: it keeps the
|
|
405
|
+
* caret on screen, which the preceding `focus()` already does anyway.
|
|
406
|
+
*
|
|
407
|
+
* @param {string} [id] prompt to focus; defaults to the first one
|
|
408
|
+
*/
|
|
409
|
+
focusPrompt(id) {
|
|
410
|
+
if (!this.mathField) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const ids = this.mathField.getPrompts() || [];
|
|
415
|
+
const target = id && ids.indexOf(id) !== -1 ? id : ids[0];
|
|
416
|
+
|
|
417
|
+
if (!target) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const range = this.mathField.getPromptRange(target);
|
|
422
|
+
|
|
423
|
+
if (!range) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
this.mathField.selection = { ranges: [[range[0], range[0]]] };
|
|
428
|
+
|
|
429
|
+
if (typeof this.mathField.executeCommand === 'function') {
|
|
430
|
+
this.mathField.executeCommand('scrollIntoView');
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
354
434
|
focus() {
|
|
355
|
-
|
|
435
|
+
if (!this.mathField) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
this.mathField.focus();
|
|
440
|
+
|
|
441
|
+
// A bare focus() leaves the selection outside every prompt, which in a
|
|
442
|
+
// read-only field is not editable - the block looked focused but had no
|
|
443
|
+
// cursor. Clicking a prompt already works, because MathLive's own pointer
|
|
444
|
+
// handling moves the selection and re-renders.
|
|
445
|
+
if (!this.promptContaining(this.mathField.position)) {
|
|
446
|
+
this.focusPrompt();
|
|
447
|
+
}
|
|
356
448
|
}
|
|
357
449
|
|
|
358
450
|
blur() {
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
var _react = _interopRequireDefault(require("react"));
|
|
5
|
-
var _react2 = require("@testing-library/react");
|
|
6
|
-
var _mathInput = _interopRequireDefault(require("../math-input"));
|
|
7
|
-
var _horizontalKeypad = _interopRequireDefault(require("../horizontal-keypad"));
|
|
8
|
-
var _input = _interopRequireDefault(require("../mf/input"));
|
|
9
|
-
/**
|
|
10
|
-
* The pieces that sit between the keypad and the field: how a pressed key is
|
|
11
|
-
* routed into the field, and the legacy `{value,type}` shape math-toolbar
|
|
12
|
-
* consumes.
|
|
13
|
-
*/
|
|
14
|
-
describe('MathInput.keypadPress routing', function () {
|
|
15
|
-
var withInput = function withInput() {
|
|
16
|
-
var mi = new _mathInput["default"]({});
|
|
17
|
-
var calls = {
|
|
18
|
-
write: [],
|
|
19
|
-
keystroke: []
|
|
20
|
-
};
|
|
21
|
-
mi.input = {
|
|
22
|
-
write: function write(v) {
|
|
23
|
-
return calls.write.push(v);
|
|
24
|
-
},
|
|
25
|
-
keystroke: function keystroke(v) {
|
|
26
|
-
return calls.keystroke.push(v);
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
return {
|
|
30
|
-
mi: mi,
|
|
31
|
-
calls: calls
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
it('routes an insert action to write()', function () {
|
|
35
|
-
var _withInput = withInput(),
|
|
36
|
-
mi = _withInput.mi,
|
|
37
|
-
calls = _withInput.calls;
|
|
38
|
-
mi.keypadPress({
|
|
39
|
-
latex: '\\pi'
|
|
40
|
-
});
|
|
41
|
-
expect(calls.write).toEqual(['\\pi']);
|
|
42
|
-
expect(calls.keystroke).toEqual([]);
|
|
43
|
-
});
|
|
44
|
-
it('expands an argument-taking command before writing', function () {
|
|
45
|
-
var _withInput2 = withInput(),
|
|
46
|
-
mi = _withInput2.mi,
|
|
47
|
-
calls = _withInput2.calls;
|
|
48
|
-
mi.keypadPress({
|
|
49
|
-
command: '\\frac'
|
|
50
|
-
});
|
|
51
|
-
expect(calls.write).toEqual(['\\frac{#?}{#?}']);
|
|
52
|
-
});
|
|
53
|
-
it('routes a cursor keystroke to keystroke()', function () {
|
|
54
|
-
var _withInput3 = withInput(),
|
|
55
|
-
mi = _withInput3.mi,
|
|
56
|
-
calls = _withInput3.calls;
|
|
57
|
-
mi.keypadPress({
|
|
58
|
-
keystroke: 'Left'
|
|
59
|
-
});
|
|
60
|
-
expect(calls.keystroke).toEqual(['moveToPreviousChar']);
|
|
61
|
-
expect(calls.write).toEqual([]);
|
|
62
|
-
});
|
|
63
|
-
it('ignores keys with no action', function () {
|
|
64
|
-
var _withInput4 = withInput(),
|
|
65
|
-
mi = _withInput4.mi,
|
|
66
|
-
calls = _withInput4.calls;
|
|
67
|
-
mi.keypadPress({});
|
|
68
|
-
mi.keypadPress({
|
|
69
|
-
keystroke: 'Nonsense'
|
|
70
|
-
});
|
|
71
|
-
expect(calls.write).toEqual([]);
|
|
72
|
-
expect(calls.keystroke).toEqual([]);
|
|
73
|
-
});
|
|
74
|
-
it('is a no-op before the field ref exists', function () {
|
|
75
|
-
var mi = new _mathInput["default"]({});
|
|
76
|
-
expect(function () {
|
|
77
|
-
return mi.keypadPress({
|
|
78
|
-
latex: '\\pi'
|
|
79
|
-
});
|
|
80
|
-
}).not.toThrow();
|
|
81
|
-
});
|
|
82
|
-
it('changeLatex only fires onChange when the value differs', function () {
|
|
83
|
-
var onChange = jest.fn();
|
|
84
|
-
var mi = new _mathInput["default"]({
|
|
85
|
-
latex: 'x',
|
|
86
|
-
onChange: onChange
|
|
87
|
-
});
|
|
88
|
-
mi.changeLatex('x');
|
|
89
|
-
expect(onChange).not.toHaveBeenCalled();
|
|
90
|
-
mi.changeLatex('y');
|
|
91
|
-
expect(onChange).toHaveBeenCalledWith('y');
|
|
92
|
-
});
|
|
93
|
-
it('tracks focus state', function () {
|
|
94
|
-
var mi = new _mathInput["default"]({});
|
|
95
|
-
mi.setState = function (s) {
|
|
96
|
-
return Object.assign(mi.state, s);
|
|
97
|
-
};
|
|
98
|
-
mi.inputFocus();
|
|
99
|
-
expect(mi.state.focused).toBe(true);
|
|
100
|
-
mi.inputBlur();
|
|
101
|
-
expect(mi.state.focused).toBe(false);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
describe('HorizontalKeypad legacy {value,type} model', function () {
|
|
105
|
-
var pressed = function pressed(key) {
|
|
106
|
-
var onClick = jest.fn();
|
|
107
|
-
var hk = new _horizontalKeypad["default"]({
|
|
108
|
-
onClick: onClick
|
|
109
|
-
});
|
|
110
|
-
hk.keypadPress(key);
|
|
111
|
-
return onClick.mock.calls[0][0];
|
|
112
|
-
};
|
|
113
|
-
it('maps a command to {value, type: command}', function () {
|
|
114
|
-
expect(pressed({
|
|
115
|
-
command: '\\frac'
|
|
116
|
-
})).toEqual({
|
|
117
|
-
value: '\\frac',
|
|
118
|
-
type: 'command'
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
it('maps a write to {value}', function () {
|
|
122
|
-
expect(pressed({
|
|
123
|
-
write: 'x'
|
|
124
|
-
})).toEqual({
|
|
125
|
-
value: 'x'
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
it('maps a keystroke to {type: cursor}', function () {
|
|
129
|
-
expect(pressed({
|
|
130
|
-
keystroke: 'Left'
|
|
131
|
-
})).toEqual({
|
|
132
|
-
type: 'cursor',
|
|
133
|
-
value: 'Left'
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
it('renders without throwing', function () {
|
|
137
|
-
expect(function () {
|
|
138
|
-
return (0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_horizontalKeypad["default"], {
|
|
139
|
-
onClick: function onClick() {}
|
|
140
|
-
}));
|
|
141
|
-
}).not.toThrow();
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
describe('Input: controlled-value sync and events', function () {
|
|
145
|
-
var withField = function withField() {
|
|
146
|
-
var input = new _input["default"]({});
|
|
147
|
-
input.mathField = {
|
|
148
|
-
value: '',
|
|
149
|
-
getValue: function getValue() {
|
|
150
|
-
return input.mathField.value;
|
|
151
|
-
},
|
|
152
|
-
insert: function insert(v) {
|
|
153
|
-
input.mathField.value += v;
|
|
154
|
-
},
|
|
155
|
-
executeCommand: function executeCommand() {},
|
|
156
|
-
focus: function focus() {},
|
|
157
|
-
blur: function blur() {},
|
|
158
|
-
addEventListener: function addEventListener() {},
|
|
159
|
-
removeEventListener: function removeEventListener() {},
|
|
160
|
-
remove: function remove() {}
|
|
161
|
-
};
|
|
162
|
-
return input;
|
|
163
|
-
};
|
|
164
|
-
it('emits stored-form latex on edit', function () {
|
|
165
|
-
var onChange = jest.fn();
|
|
166
|
-
var input = withField();
|
|
167
|
-
input.props = {
|
|
168
|
-
onChange: onChange
|
|
169
|
-
};
|
|
170
|
-
input.mathField.value = '\\longdiv{\\placeholder{}}';
|
|
171
|
-
input.onInputEdit();
|
|
172
|
-
|
|
173
|
-
// \placeholder is MathLive-internal and must not reach the model
|
|
174
|
-
expect(onChange).toHaveBeenCalledWith('\\longdiv{}');
|
|
175
|
-
expect(input.lastEmitted).toEqual('\\longdiv{}');
|
|
176
|
-
});
|
|
177
|
-
it('does not push a prop echo back into the field', function () {
|
|
178
|
-
var input = withField();
|
|
179
|
-
input.mathField.value = 'x';
|
|
180
|
-
input.lastEmitted = 'x';
|
|
181
|
-
input.props = {
|
|
182
|
-
latex: 'x'
|
|
183
|
-
};
|
|
184
|
-
input.componentDidUpdate({
|
|
185
|
-
latex: ''
|
|
186
|
-
});
|
|
187
|
-
expect(input.mathField.value).toEqual('x');
|
|
188
|
-
});
|
|
189
|
-
it('pushes a genuinely new latex prop into the field', function () {
|
|
190
|
-
var input = withField();
|
|
191
|
-
input.mathField.value = 'x';
|
|
192
|
-
input.lastEmitted = 'x';
|
|
193
|
-
input.props = {
|
|
194
|
-
latex: 'y'
|
|
195
|
-
};
|
|
196
|
-
input.componentDidUpdate({
|
|
197
|
-
latex: 'x'
|
|
198
|
-
});
|
|
199
|
-
expect(input.mathField.value).toEqual('y');
|
|
200
|
-
});
|
|
201
|
-
it('bridges stored latex on the way in', function () {
|
|
202
|
-
var input = withField();
|
|
203
|
-
input.props = {
|
|
204
|
-
latex: '\\longdiv{5}'
|
|
205
|
-
};
|
|
206
|
-
input.componentDidUpdate({
|
|
207
|
-
latex: ''
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
// must become native \enclose so the content stays editable
|
|
211
|
-
expect(input.mathField.value).toEqual('\\enclose{longdiv}{5}');
|
|
212
|
-
});
|
|
213
|
-
it('toggles readOnly', function () {
|
|
214
|
-
var input = withField();
|
|
215
|
-
input.props = {
|
|
216
|
-
readOnly: true
|
|
217
|
-
};
|
|
218
|
-
input.componentDidUpdate({
|
|
219
|
-
readOnly: false
|
|
220
|
-
});
|
|
221
|
-
expect(input.mathField.readOnly).toBe(true);
|
|
222
|
-
});
|
|
223
|
-
it('clear() empties the field', function () {
|
|
224
|
-
var input = withField();
|
|
225
|
-
input.mathField.value = 'abc';
|
|
226
|
-
expect(input.clear()).toEqual('');
|
|
227
|
-
expect(input.mathField.value).toEqual('');
|
|
228
|
-
});
|
|
229
|
-
it('suppresses Enter so it cannot insert a line break', function () {
|
|
230
|
-
var input = withField();
|
|
231
|
-
var preventDefault = jest.fn();
|
|
232
|
-
input.onKeyDown({
|
|
233
|
-
key: 'Enter',
|
|
234
|
-
preventDefault: preventDefault
|
|
235
|
-
});
|
|
236
|
-
expect(preventDefault).toHaveBeenCalled();
|
|
237
|
-
preventDefault.mockClear();
|
|
238
|
-
input.onKeyDown({
|
|
239
|
-
key: 'a',
|
|
240
|
-
preventDefault: preventDefault
|
|
241
|
-
});
|
|
242
|
-
expect(preventDefault).not.toHaveBeenCalled();
|
|
243
|
-
});
|
|
244
|
-
it('componentDidUpdate is safe before the field exists', function () {
|
|
245
|
-
var input = new _input["default"]({
|
|
246
|
-
latex: 'x'
|
|
247
|
-
});
|
|
248
|
-
expect(function () {
|
|
249
|
-
return input.componentDidUpdate({
|
|
250
|
-
latex: ''
|
|
251
|
-
});
|
|
252
|
-
}).not.toThrow();
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
//# sourceMappingURL=composites.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"composites.test.js","names":["_react","_interopRequireDefault","require","_react2","_mathInput","_horizontalKeypad","_input","describe","withInput","mi","MathInput","calls","write","keystroke","input","v","push","it","_withInput","keypadPress","latex","expect","toEqual","_withInput2","command","_withInput3","_withInput4","not","toThrow","onChange","jest","fn","changeLatex","toHaveBeenCalled","toHaveBeenCalledWith","setState","s","Object","assign","state","inputFocus","focused","toBe","inputBlur","pressed","key","onClick","hk","HorizontalKeypad","mock","value","type","render","createElement","withField","Input","mathField","getValue","insert","executeCommand","focus","blur","addEventListener","removeEventListener","remove","props","onInputEdit","lastEmitted","componentDidUpdate","readOnly","clear","preventDefault","onKeyDown","mockClear"],"sources":["../../src/__tests__/composites.test.jsx"],"sourcesContent":["import React from 'react';\nimport { render } from '@testing-library/react';\n\nimport MathInput from '../math-input';\nimport HorizontalKeypad from '../horizontal-keypad';\nimport Input from '../mf/input';\n\n/**\n * The pieces that sit between the keypad and the field: how a pressed key is\n * routed into the field, and the legacy `{value,type}` shape math-toolbar\n * consumes.\n */\ndescribe('MathInput.keypadPress routing', () => {\n const withInput = () => {\n const mi = new MathInput({});\n const calls = { write: [], keystroke: [] };\n\n mi.input = {\n write: (v) => calls.write.push(v),\n keystroke: (v) => calls.keystroke.push(v),\n };\n\n return { mi, calls };\n };\n\n it('routes an insert action to write()', () => {\n const { mi, calls } = withInput();\n\n mi.keypadPress({ latex: '\\\\pi' });\n\n expect(calls.write).toEqual(['\\\\pi']);\n expect(calls.keystroke).toEqual([]);\n });\n\n it('expands an argument-taking command before writing', () => {\n const { mi, calls } = withInput();\n\n mi.keypadPress({ command: '\\\\frac' });\n\n expect(calls.write).toEqual(['\\\\frac{#?}{#?}']);\n });\n\n it('routes a cursor keystroke to keystroke()', () => {\n const { mi, calls } = withInput();\n\n mi.keypadPress({ keystroke: 'Left' });\n\n expect(calls.keystroke).toEqual(['moveToPreviousChar']);\n expect(calls.write).toEqual([]);\n });\n\n it('ignores keys with no action', () => {\n const { mi, calls } = withInput();\n\n mi.keypadPress({});\n mi.keypadPress({ keystroke: 'Nonsense' });\n\n expect(calls.write).toEqual([]);\n expect(calls.keystroke).toEqual([]);\n });\n\n it('is a no-op before the field ref exists', () => {\n const mi = new MathInput({});\n\n expect(() => mi.keypadPress({ latex: '\\\\pi' })).not.toThrow();\n });\n\n it('changeLatex only fires onChange when the value differs', () => {\n const onChange = jest.fn();\n const mi = new MathInput({ latex: 'x', onChange });\n\n mi.changeLatex('x');\n expect(onChange).not.toHaveBeenCalled();\n\n mi.changeLatex('y');\n expect(onChange).toHaveBeenCalledWith('y');\n });\n\n it('tracks focus state', () => {\n const mi = new MathInput({});\n\n mi.setState = (s) => Object.assign(mi.state, s);\n mi.inputFocus();\n expect(mi.state.focused).toBe(true);\n\n mi.inputBlur();\n expect(mi.state.focused).toBe(false);\n });\n});\n\ndescribe('HorizontalKeypad legacy {value,type} model', () => {\n const pressed = (key) => {\n const onClick = jest.fn();\n const hk = new HorizontalKeypad({ onClick });\n\n hk.keypadPress(key);\n\n return onClick.mock.calls[0][0];\n };\n\n it('maps a command to {value, type: command}', () => {\n expect(pressed({ command: '\\\\frac' })).toEqual({ value: '\\\\frac', type: 'command' });\n });\n\n it('maps a write to {value}', () => {\n expect(pressed({ write: 'x' })).toEqual({ value: 'x' });\n });\n\n it('maps a keystroke to {type: cursor}', () => {\n expect(pressed({ keystroke: 'Left' })).toEqual({ type: 'cursor', value: 'Left' });\n });\n\n it('renders without throwing', () => {\n expect(() => render(<HorizontalKeypad onClick={() => {}} />)).not.toThrow();\n });\n});\n\ndescribe('Input: controlled-value sync and events', () => {\n const withField = () => {\n const input = new Input({});\n\n input.mathField = {\n value: '',\n getValue: () => input.mathField.value,\n insert(v) {\n input.mathField.value += v;\n },\n executeCommand() {},\n focus() {},\n blur() {},\n addEventListener() {},\n removeEventListener() {},\n remove() {},\n };\n\n return input;\n };\n\n it('emits stored-form latex on edit', () => {\n const onChange = jest.fn();\n const input = withField();\n\n input.props = { onChange };\n input.mathField.value = '\\\\longdiv{\\\\placeholder{}}';\n input.onInputEdit();\n\n // \\placeholder is MathLive-internal and must not reach the model\n expect(onChange).toHaveBeenCalledWith('\\\\longdiv{}');\n expect(input.lastEmitted).toEqual('\\\\longdiv{}');\n });\n\n it('does not push a prop echo back into the field', () => {\n const input = withField();\n\n input.mathField.value = 'x';\n input.lastEmitted = 'x';\n input.props = { latex: 'x' };\n\n input.componentDidUpdate({ latex: '' });\n\n expect(input.mathField.value).toEqual('x');\n });\n\n it('pushes a genuinely new latex prop into the field', () => {\n const input = withField();\n\n input.mathField.value = 'x';\n input.lastEmitted = 'x';\n input.props = { latex: 'y' };\n\n input.componentDidUpdate({ latex: 'x' });\n\n expect(input.mathField.value).toEqual('y');\n });\n\n it('bridges stored latex on the way in', () => {\n const input = withField();\n\n input.props = { latex: '\\\\longdiv{5}' };\n input.componentDidUpdate({ latex: '' });\n\n // must become native \\enclose so the content stays editable\n expect(input.mathField.value).toEqual('\\\\enclose{longdiv}{5}');\n });\n\n it('toggles readOnly', () => {\n const input = withField();\n\n input.props = { readOnly: true };\n input.componentDidUpdate({ readOnly: false });\n\n expect(input.mathField.readOnly).toBe(true);\n });\n\n it('clear() empties the field', () => {\n const input = withField();\n\n input.mathField.value = 'abc';\n expect(input.clear()).toEqual('');\n expect(input.mathField.value).toEqual('');\n });\n\n it('suppresses Enter so it cannot insert a line break', () => {\n const input = withField();\n const preventDefault = jest.fn();\n\n input.onKeyDown({ key: 'Enter', preventDefault });\n expect(preventDefault).toHaveBeenCalled();\n\n preventDefault.mockClear();\n input.onKeyDown({ key: 'a', preventDefault });\n expect(preventDefault).not.toHaveBeenCalled();\n });\n\n it('componentDidUpdate is safe before the field exists', () => {\n const input = new Input({ latex: 'x' });\n\n expect(() => input.componentDidUpdate({ latex: '' })).not.toThrow();\n });\n});\n"],"mappings":"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","ignoreList":[]}
|