@pie-lib/math-input-mathlive 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/lib/__tests__/index.test.js +118 -0
- package/lib/__tests__/index.test.js.map +1 -0
- package/lib/__tests__/latex-bridge.test.js +186 -0
- package/lib/__tests__/latex-bridge.test.js.map +1 -0
- package/lib/__tests__/mathlive-instance.test.js +137 -0
- package/lib/__tests__/mathlive-instance.test.js.map +1 -0
- package/lib/horizontal-keypad.js +101 -0
- package/lib/horizontal-keypad.js.map +1 -0
- package/lib/index.js +143 -0
- package/lib/index.js.map +1 -0
- package/lib/keypad/index.js +365 -0
- package/lib/keypad/index.js.map +1 -0
- package/lib/keypad/keys-layout.js +22 -0
- package/lib/keypad/keys-layout.js.map +1 -0
- package/lib/keys/basic-operators.js +33 -0
- package/lib/keys/basic-operators.js.map +1 -0
- package/lib/keys/chars.js +12 -0
- package/lib/keys/chars.js.map +1 -0
- package/lib/keys/comparison.js +39 -0
- package/lib/keys/comparison.js.map +1 -0
- package/lib/keys/constants.js +37 -0
- package/lib/keys/constants.js.map +1 -0
- package/lib/keys/digits.js +46 -0
- package/lib/keys/digits.js.map +1 -0
- package/lib/keys/edit.js +14 -0
- package/lib/keys/edit.js.map +1 -0
- package/lib/keys/exponent.js +30 -0
- package/lib/keys/exponent.js.map +1 -0
- package/lib/keys/fractions.js +29 -0
- package/lib/keys/fractions.js.map +1 -0
- package/lib/keys/geometry.js +140 -0
- package/lib/keys/geometry.js.map +1 -0
- package/lib/keys/grades.js +259 -0
- package/lib/keys/grades.js.map +1 -0
- package/lib/keys/index.js +35 -0
- package/lib/keys/index.js.map +1 -0
- package/lib/keys/log.js +27 -0
- package/lib/keys/log.js.map +1 -0
- package/lib/keys/logic.js +19 -0
- package/lib/keys/logic.js.map +1 -0
- package/lib/keys/matrices.js +19 -0
- package/lib/keys/matrices.js.map +1 -0
- package/lib/keys/misc.js +62 -0
- package/lib/keys/misc.js.map +1 -0
- package/lib/keys/navigation.js +20 -0
- package/lib/keys/navigation.js.map +1 -0
- package/lib/keys/operators.js +15 -0
- package/lib/keys/operators.js.map +1 -0
- package/lib/keys/statistics.js +40 -0
- package/lib/keys/statistics.js.map +1 -0
- package/lib/keys/sub-sup.js +19 -0
- package/lib/keys/sub-sup.js.map +1 -0
- package/lib/keys/trigonometry.js +45 -0
- package/lib/keys/trigonometry.js.map +1 -0
- package/lib/keys/utils.js +87 -0
- package/lib/keys/utils.js.map +1 -0
- package/lib/keys/vars.js +24 -0
- package/lib/keys/vars.js.map +1 -0
- package/lib/latex-bridge.js +195 -0
- package/lib/latex-bridge.js.map +1 -0
- package/lib/math-input.js +143 -0
- package/lib/math-input.js.map +1 -0
- package/lib/mathlive-instance.js +319 -0
- package/lib/mathlive-instance.js.map +1 -0
- package/lib/mf/common-styles.js +111 -0
- package/lib/mf/common-styles.js.map +1 -0
- package/lib/mf/index.js +72 -0
- package/lib/mf/index.js.map +1 -0
- package/lib/mf/input.js +266 -0
- package/lib/mf/input.js.map +1 -0
- package/lib/mf/static.js +396 -0
- package/lib/mf/static.js.map +1 -0
- package/package.json +31 -0
- package/src/__tests__/index.test.jsx +109 -0
- package/src/__tests__/latex-bridge.test.js +151 -0
- package/src/__tests__/mathlive-instance.test.js +130 -0
- package/src/horizontal-keypad.jsx +73 -0
- package/src/index.jsx +63 -0
- package/src/keypad/index.jsx +335 -0
- package/src/keypad/keys-layout.js +16 -0
- package/src/keys/basic-operators.js +32 -0
- package/src/keys/chars.js +5 -0
- package/src/keys/comparison.js +28 -0
- package/src/keys/constants.js +35 -0
- package/src/keys/digits.js +40 -0
- package/src/keys/edit.js +3 -0
- package/src/keys/exponent.js +28 -0
- package/src/keys/fractions.js +26 -0
- package/src/keys/geometry.js +144 -0
- package/src/keys/grades.js +367 -0
- package/src/keys/index.js +20 -0
- package/src/keys/log.js +22 -0
- package/src/keys/logic.js +15 -0
- package/src/keys/matrices.js +15 -0
- package/src/keys/misc.js +65 -0
- package/src/keys/navigation.js +8 -0
- package/src/keys/operators.js +10 -0
- package/src/keys/statistics.js +38 -0
- package/src/keys/sub-sup.js +15 -0
- package/src/keys/trigonometry.js +15 -0
- package/src/keys/utils.js +66 -0
- package/src/keys/vars.js +19 -0
- package/src/latex-bridge.js +190 -0
- package/src/math-input.jsx +115 -0
- package/src/mathlive-instance.js +286 -0
- package/src/mf/common-styles.js +108 -0
- package/src/mf/index.js +26 -0
- package/src/mf/input.jsx +223 -0
- package/src/mf/static.jsx +358 -0
package/lib/mf/static.js
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports["default"] = void 0;
|
|
8
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
9
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
10
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
12
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
13
|
+
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
14
|
+
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
15
|
+
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
16
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
17
|
+
var _react = _interopRequireDefault(require("react"));
|
|
18
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
19
|
+
var _styles = require("@mui/material/styles");
|
|
20
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
21
|
+
var _mathliveInstance = require("../mathlive-instance");
|
|
22
|
+
var _latexBridge = require("../latex-bridge");
|
|
23
|
+
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
|
|
24
|
+
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
25
|
+
var log = (0, _debug["default"])('pie-lib:math-input-mathlive:static');
|
|
26
|
+
var Holder = (0, _styles.styled)('span')({
|
|
27
|
+
display: 'inline-block',
|
|
28
|
+
'& math-field': {
|
|
29
|
+
display: 'inline-block',
|
|
30
|
+
border: 'none',
|
|
31
|
+
background: 'transparent'
|
|
32
|
+
},
|
|
33
|
+
'& math-field::part(virtual-keyboard-toggle)': {
|
|
34
|
+
display: 'none'
|
|
35
|
+
},
|
|
36
|
+
'& math-field::part(menu-toggle)': {
|
|
37
|
+
display: 'none'
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Static math. Drop-in replacement for @pie-lib/math-input's `mq.Static`.
|
|
43
|
+
*
|
|
44
|
+
* Two modes, chosen automatically:
|
|
45
|
+
*
|
|
46
|
+
* - **display** (no answer blocks in the latex): rendered with
|
|
47
|
+
* `convertLatexToMarkup`. No mathfield instance, so it is cheap enough for
|
|
48
|
+
* keypad labels - the old implementation created a full MathQuill
|
|
49
|
+
* StaticMath per button.
|
|
50
|
+
*
|
|
51
|
+
* - **interactive** (latex contains `\MathQuillMathField[..]{}` /
|
|
52
|
+
* `\placeholder[..]{}`): a read-only `<math-field>` whose placeholders stay
|
|
53
|
+
* editable. Sub-field values are surfaced through the prompts API, replacing
|
|
54
|
+
* MathQuill's `innerFields`.
|
|
55
|
+
*/
|
|
56
|
+
var Static = exports["default"] = /*#__PURE__*/function (_React$Component) {
|
|
57
|
+
function Static(props) {
|
|
58
|
+
var _this;
|
|
59
|
+
(0, _classCallCheck2["default"])(this, Static);
|
|
60
|
+
_this = _callSuper(this, Static, [props]);
|
|
61
|
+
/**
|
|
62
|
+
* Off-screen aria-live region, ported from @pie-lib/math-input's Static.
|
|
63
|
+
*
|
|
64
|
+
* MathLive has its own accessibility layer, but it does not announce that
|
|
65
|
+
* typed input was converted into a math symbol, which screen-reader users
|
|
66
|
+
* relied on in the MathQuill implementation.
|
|
67
|
+
*/
|
|
68
|
+
(0, _defineProperty2["default"])(_this, "createLiveRegion", function () {
|
|
69
|
+
if (typeof document === 'undefined' || _this.liveRegion) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
_this.liveRegion = document.createElement('div');
|
|
73
|
+
Object.assign(_this.liveRegion.style, {
|
|
74
|
+
position: 'absolute',
|
|
75
|
+
width: '1px',
|
|
76
|
+
height: '1px',
|
|
77
|
+
marginTop: '-1px',
|
|
78
|
+
clip: 'rect(1px, 1px, 1px, 1px)',
|
|
79
|
+
overflow: 'hidden'
|
|
80
|
+
});
|
|
81
|
+
_this.liveRegion.setAttribute('aria-live', 'polite');
|
|
82
|
+
_this.liveRegion.setAttribute('aria-atomic', 'true');
|
|
83
|
+
document.body.appendChild(_this.liveRegion);
|
|
84
|
+
});
|
|
85
|
+
(0, _defineProperty2["default"])(_this, "removeLiveRegion", function () {
|
|
86
|
+
if (_this.liveRegion && _this.liveRegion.parentNode) {
|
|
87
|
+
_this.liveRegion.parentNode.removeChild(_this.liveRegion);
|
|
88
|
+
}
|
|
89
|
+
_this.liveRegion = undefined;
|
|
90
|
+
});
|
|
91
|
+
(0, _defineProperty2["default"])(_this, "announce", function (message) {
|
|
92
|
+
if (!_this.liveRegion) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
_this.liveRegion.textContent = message;
|
|
96
|
+
|
|
97
|
+
// Clear once announced, so the same message can be announced again.
|
|
98
|
+
clearTimeout(_this.announceTimeout);
|
|
99
|
+
_this.announceTimeout = setTimeout(function () {
|
|
100
|
+
if (_this.liveRegion) {
|
|
101
|
+
_this.liveRegion.textContent = '';
|
|
102
|
+
}
|
|
103
|
+
}, 500);
|
|
104
|
+
});
|
|
105
|
+
(0, _defineProperty2["default"])(_this, "onKeyDown", function (event) {
|
|
106
|
+
// Deletions should not be announced as conversions.
|
|
107
|
+
_this.isDeleting = (event === null || event === void 0 ? void 0 : event.key) === 'Backspace' || (event === null || event === void 0 ? void 0 : event.key) === 'Delete';
|
|
108
|
+
});
|
|
109
|
+
/**
|
|
110
|
+
* Announce when typed input became a math symbol. The MathQuill version
|
|
111
|
+
* inferred this by counting braces; here a prompt whose latex grew by more
|
|
112
|
+
* than the single character typed means a command was expanded.
|
|
113
|
+
*/
|
|
114
|
+
(0, _defineProperty2["default"])(_this, "announceConversion", function (next) {
|
|
115
|
+
if (_this.isDeleting) {
|
|
116
|
+
_this.isDeleting = false;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
var converted = Object.keys(next).some(function (id) {
|
|
120
|
+
var before = _this.promptValues[id] || '';
|
|
121
|
+
var after = next[id] || '';
|
|
122
|
+
return after.length > before.length + 1 && /\\/.test(after.slice(before.length));
|
|
123
|
+
});
|
|
124
|
+
if (converted) {
|
|
125
|
+
_this.announce('Converted to math symbol');
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
(0, _defineProperty2["default"])(_this, "onPromptInput", function () {
|
|
129
|
+
var _this$props = _this.props,
|
|
130
|
+
onSubFieldChange = _this$props.onSubFieldChange,
|
|
131
|
+
getFieldName = _this$props.getFieldName;
|
|
132
|
+
if (!_this.mathField) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
var next = _this.values();
|
|
136
|
+
_this.announceConversion(next);
|
|
137
|
+
if (!onSubFieldChange) {
|
|
138
|
+
_this.promptValues = next;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
var fields = _this.innerFields;
|
|
142
|
+
|
|
143
|
+
// Emit only the prompts whose value actually changed, mirroring the
|
|
144
|
+
// per-field granularity of the old onSubFieldChange(name, latex).
|
|
145
|
+
Object.keys(next).forEach(function (id) {
|
|
146
|
+
if (next[id] === _this.promptValues[id]) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
var name = getFieldName(_this.promptHandle(id), fields) || id;
|
|
150
|
+
onSubFieldChange(name, next[id]);
|
|
151
|
+
});
|
|
152
|
+
_this.promptValues = next;
|
|
153
|
+
});
|
|
154
|
+
(0, _defineProperty2["default"])(_this, "onPromptFocus", function () {
|
|
155
|
+
var _this$props2 = _this.props,
|
|
156
|
+
onSubFieldFocus = _this$props2.onSubFieldFocus,
|
|
157
|
+
getFieldName = _this$props2.getFieldName;
|
|
158
|
+
if (!_this.mathField || !onSubFieldFocus) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
var ids = _this.mathField.getPrompts() || [];
|
|
163
|
+
// The focused prompt is the one containing the current selection.
|
|
164
|
+
var focused = ids.find(function (id) {
|
|
165
|
+
var range = _this.mathField.getPromptRange(id);
|
|
166
|
+
var selection = _this.mathField.selection;
|
|
167
|
+
if (!range || !selection || !selection.ranges || !selection.ranges.length) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
var _range = (0, _slicedToArray2["default"])(range, 2),
|
|
171
|
+
start = _range[0],
|
|
172
|
+
end = _range[1];
|
|
173
|
+
var _selection$ranges$ = (0, _slicedToArray2["default"])(selection.ranges[0], 1),
|
|
174
|
+
selStart = _selection$ranges$[0];
|
|
175
|
+
return selStart >= start && selStart <= end;
|
|
176
|
+
});
|
|
177
|
+
if (focused) {
|
|
178
|
+
var handle = _this.promptHandle(focused);
|
|
179
|
+
var name = getFieldName(handle, _this.innerFields) || focused;
|
|
180
|
+
if (_this.props.setInput) {
|
|
181
|
+
_this.props.setInput(handle);
|
|
182
|
+
}
|
|
183
|
+
onSubFieldFocus(name, handle);
|
|
184
|
+
}
|
|
185
|
+
} catch (e) {
|
|
186
|
+
log('error resolving focused prompt: %s', e.message);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
_this.holderRef = /*#__PURE__*/_react["default"].createRef();
|
|
190
|
+
_this.state = {
|
|
191
|
+
markup: ''
|
|
192
|
+
};
|
|
193
|
+
_this.promptValues = {};
|
|
194
|
+
return _this;
|
|
195
|
+
}
|
|
196
|
+
(0, _inherits2["default"])(Static, _React$Component);
|
|
197
|
+
return (0, _createClass2["default"])(Static, [{
|
|
198
|
+
key: "componentDidMount",
|
|
199
|
+
value: function () {
|
|
200
|
+
var _componentDidMount = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee() {
|
|
201
|
+
var ml;
|
|
202
|
+
return _regenerator["default"].wrap(function (_context) {
|
|
203
|
+
while (1) switch (_context.prev = _context.next) {
|
|
204
|
+
case 0:
|
|
205
|
+
if (this.isInteractive()) {
|
|
206
|
+
_context.next = 2;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
_context.next = 1;
|
|
210
|
+
return (0, _mathliveInstance.loadMathLive)();
|
|
211
|
+
case 1:
|
|
212
|
+
this.renderMarkup();
|
|
213
|
+
return _context.abrupt("return");
|
|
214
|
+
case 2:
|
|
215
|
+
_context.next = 3;
|
|
216
|
+
return (0, _mathliveInstance.loadMathLive)();
|
|
217
|
+
case 3:
|
|
218
|
+
ml = _context.sent;
|
|
219
|
+
if (!(!ml || !this.holderRef.current)) {
|
|
220
|
+
_context.next = 4;
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
return _context.abrupt("return");
|
|
224
|
+
case 4:
|
|
225
|
+
this.mathField = new ml.MathfieldElement({
|
|
226
|
+
macros: (0, _mathliveInstance.getMacros)()
|
|
227
|
+
});
|
|
228
|
+
this.mathField.readOnly = true;
|
|
229
|
+
this.mathField.mathVirtualKeyboardPolicy = 'manual';
|
|
230
|
+
this.mathField.value = (0, _latexBridge.toMathLive)(this.props.latex);
|
|
231
|
+
this.mathField.addEventListener('input', this.onPromptInput);
|
|
232
|
+
this.mathField.addEventListener('focusin', this.onPromptFocus);
|
|
233
|
+
this.mathField.addEventListener('keydown', this.onKeyDown);
|
|
234
|
+
this.holderRef.current.appendChild(this.mathField);
|
|
235
|
+
this.createLiveRegion();
|
|
236
|
+
case 5:
|
|
237
|
+
case "end":
|
|
238
|
+
return _context.stop();
|
|
239
|
+
}
|
|
240
|
+
}, _callee, this);
|
|
241
|
+
}));
|
|
242
|
+
function componentDidMount() {
|
|
243
|
+
return _componentDidMount.apply(this, arguments);
|
|
244
|
+
}
|
|
245
|
+
return componentDidMount;
|
|
246
|
+
}()
|
|
247
|
+
}, {
|
|
248
|
+
key: "componentDidUpdate",
|
|
249
|
+
value: function componentDidUpdate(prevProps) {
|
|
250
|
+
if (prevProps.latex === this.props.latex) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (this.mathField) {
|
|
254
|
+
this.mathField.value = (0, _latexBridge.toMathLive)(this.props.latex);
|
|
255
|
+
} else {
|
|
256
|
+
this.renderMarkup();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}, {
|
|
260
|
+
key: "componentWillUnmount",
|
|
261
|
+
value: function componentWillUnmount() {
|
|
262
|
+
if (this.mathField) {
|
|
263
|
+
this.mathField.removeEventListener('input', this.onPromptInput);
|
|
264
|
+
this.mathField.removeEventListener('focusin', this.onPromptFocus);
|
|
265
|
+
this.mathField.removeEventListener('keydown', this.onKeyDown);
|
|
266
|
+
this.mathField.remove();
|
|
267
|
+
this.mathField = undefined;
|
|
268
|
+
}
|
|
269
|
+
this.removeLiveRegion();
|
|
270
|
+
}
|
|
271
|
+
}, {
|
|
272
|
+
key: "isInteractive",
|
|
273
|
+
value: /** Does this latex contain answer blocks? */
|
|
274
|
+
function isInteractive() {
|
|
275
|
+
var latex = this.props.latex || '';
|
|
276
|
+
return (0, _latexBridge.fieldIds)(latex).length > 0 || latex.indexOf('\\placeholder') !== -1;
|
|
277
|
+
}
|
|
278
|
+
}, {
|
|
279
|
+
key: "renderMarkup",
|
|
280
|
+
value: function renderMarkup() {
|
|
281
|
+
var markup = (0, _mathliveInstance.latexToMarkup)(this.props.latex);
|
|
282
|
+
if (markup !== this.state.markup) {
|
|
283
|
+
this.setState({
|
|
284
|
+
markup: markup
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** MathQuill's `innerFields` equivalent, keyed by prompt id. */
|
|
290
|
+
}, {
|
|
291
|
+
key: "values",
|
|
292
|
+
value: function values() {
|
|
293
|
+
var _this2 = this;
|
|
294
|
+
if (!this.mathField) {
|
|
295
|
+
return {};
|
|
296
|
+
}
|
|
297
|
+
var out = {};
|
|
298
|
+
(this.mathField.getPrompts() || []).forEach(function (id) {
|
|
299
|
+
out[id] = (0, _latexBridge.fromMathLive)(_this2.mathField.getPromptValue(id));
|
|
300
|
+
});
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* A MathQuill-inner-field-like handle for a prompt.
|
|
306
|
+
*
|
|
307
|
+
* The old API handed callers a MathQuill field object, and consumers commonly
|
|
308
|
+
* called `field.latex()` on it. There is no equivalent object in MathLive -
|
|
309
|
+
* prompts are addressed by id - so this adapter exposes the parts that were
|
|
310
|
+
* actually used: `id` and a get/set `latex()`.
|
|
311
|
+
*/
|
|
312
|
+
}, {
|
|
313
|
+
key: "promptHandle",
|
|
314
|
+
value: function promptHandle(id) {
|
|
315
|
+
var _this3 = this;
|
|
316
|
+
return {
|
|
317
|
+
id: id,
|
|
318
|
+
latex: function latex(value) {
|
|
319
|
+
if (!_this3.mathField) {
|
|
320
|
+
return '';
|
|
321
|
+
}
|
|
322
|
+
if (value === undefined) {
|
|
323
|
+
return (0, _latexBridge.fromMathLive)(_this3.mathField.getPromptValue(id));
|
|
324
|
+
}
|
|
325
|
+
_this3.mathField.setPromptValue(id, (0, _latexBridge.toMathLive)(value), {});
|
|
326
|
+
return value;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** All prompt handles, the analogue of `mathField.innerFields`. */
|
|
332
|
+
}, {
|
|
333
|
+
key: "innerFields",
|
|
334
|
+
get: function get() {
|
|
335
|
+
var _this4 = this;
|
|
336
|
+
if (!this.mathField) {
|
|
337
|
+
return [];
|
|
338
|
+
}
|
|
339
|
+
return (this.mathField.getPrompts() || []).map(function (id) {
|
|
340
|
+
return _this4.promptHandle(id);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}, {
|
|
344
|
+
key: "focus",
|
|
345
|
+
value: function focus() {
|
|
346
|
+
this.mathField && this.mathField.focus();
|
|
347
|
+
}
|
|
348
|
+
}, {
|
|
349
|
+
key: "blur",
|
|
350
|
+
value: function blur() {
|
|
351
|
+
this.mathField && this.mathField.blur();
|
|
352
|
+
}
|
|
353
|
+
}, {
|
|
354
|
+
key: "render",
|
|
355
|
+
value: function render() {
|
|
356
|
+
var _this$props3 = this.props,
|
|
357
|
+
className = _this$props3.className,
|
|
358
|
+
onFocus = _this$props3.onFocus,
|
|
359
|
+
onBlur = _this$props3.onBlur;
|
|
360
|
+
var markup = this.state.markup;
|
|
361
|
+
if (this.mathField || this.isInteractive()) {
|
|
362
|
+
return /*#__PURE__*/_react["default"].createElement(Holder, {
|
|
363
|
+
className: className,
|
|
364
|
+
onFocus: onFocus,
|
|
365
|
+
onBlur: onBlur,
|
|
366
|
+
ref: this.holderRef
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
return /*#__PURE__*/_react["default"].createElement(Holder, {
|
|
370
|
+
className: className,
|
|
371
|
+
onFocus: onFocus,
|
|
372
|
+
onBlur: onBlur,
|
|
373
|
+
ref: this.holderRef
|
|
374
|
+
// eslint-disable-next-line react/no-danger
|
|
375
|
+
,
|
|
376
|
+
dangerouslySetInnerHTML: {
|
|
377
|
+
__html: markup
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}]);
|
|
382
|
+
}(_react["default"].Component);
|
|
383
|
+
(0, _defineProperty2["default"])(Static, "propTypes", {
|
|
384
|
+
latex: _propTypes["default"].string.isRequired,
|
|
385
|
+
className: _propTypes["default"].string,
|
|
386
|
+
onFocus: _propTypes["default"].func,
|
|
387
|
+
onBlur: _propTypes["default"].func,
|
|
388
|
+
getFieldName: _propTypes["default"].func,
|
|
389
|
+
onSubFieldChange: _propTypes["default"].func,
|
|
390
|
+
onSubFieldFocus: _propTypes["default"].func,
|
|
391
|
+
setInput: _propTypes["default"].func
|
|
392
|
+
});
|
|
393
|
+
(0, _defineProperty2["default"])(Static, "defaultProps", {
|
|
394
|
+
getFieldName: function getFieldName() {}
|
|
395
|
+
});
|
|
396
|
+
//# sourceMappingURL=static.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static.js","names":["_react","_interopRequireDefault","require","_propTypes","_styles","_debug","_mathliveInstance","_latexBridge","_callSuper","t","o","e","_getPrototypeOf2","_possibleConstructorReturn2","_isNativeReflectConstruct","Reflect","construct","constructor","apply","Boolean","prototype","valueOf","call","log","debug","Holder","styled","display","border","background","Static","exports","_React$Component","props","_this","_classCallCheck2","_defineProperty2","document","liveRegion","createElement","Object","assign","style","position","width","height","marginTop","clip","overflow","setAttribute","body","appendChild","parentNode","removeChild","undefined","message","textContent","clearTimeout","announceTimeout","setTimeout","event","isDeleting","key","next","converted","keys","some","id","before","promptValues","after","length","test","slice","announce","_this$props","onSubFieldChange","getFieldName","mathField","values","announceConversion","fields","innerFields","forEach","name","promptHandle","_this$props2","onSubFieldFocus","ids","getPrompts","focused","find","range","getPromptRange","selection","ranges","_range","_slicedToArray2","start","end","_selection$ranges$","selStart","handle","setInput","holderRef","React","createRef","state","markup","_inherits2","_createClass2","value","_componentDidMount","_asyncToGenerator2","_regenerator","mark","_callee","ml","wrap","_context","prev","isInteractive","loadMathLive","renderMarkup","abrupt","sent","current","MathfieldElement","macros","getMacros","readOnly","mathVirtualKeyboardPolicy","toMathLive","latex","addEventListener","onPromptInput","onPromptFocus","onKeyDown","createLiveRegion","stop","componentDidMount","arguments","componentDidUpdate","prevProps","componentWillUnmount","removeEventListener","remove","removeLiveRegion","fieldIds","indexOf","latexToMarkup","setState","_this2","out","fromMathLive","getPromptValue","_this3","setPromptValue","get","_this4","map","focus","blur","render","_this$props3","className","onFocus","onBlur","ref","dangerouslySetInnerHTML","__html","Component","PropTypes","string","isRequired","func"],"sources":["../../src/mf/static.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { styled } from '@mui/material/styles';\nimport debug from 'debug';\nimport { loadMathLive, getMacros, latexToMarkup } from '../mathlive-instance';\nimport { toMathLive, fromMathLive, fieldIds } from '../latex-bridge';\n\nconst log = debug('pie-lib:math-input-mathlive:static');\n\nconst Holder = styled('span')({\n display: 'inline-block',\n '& math-field': {\n display: 'inline-block',\n border: 'none',\n background: 'transparent',\n },\n '& math-field::part(virtual-keyboard-toggle)': {\n display: 'none',\n },\n '& math-field::part(menu-toggle)': {\n display: 'none',\n },\n});\n\n/**\n * Static math. Drop-in replacement for @pie-lib/math-input's `mq.Static`.\n *\n * Two modes, chosen automatically:\n *\n * - **display** (no answer blocks in the latex): rendered with\n * `convertLatexToMarkup`. No mathfield instance, so it is cheap enough for\n * keypad labels - the old implementation created a full MathQuill\n * StaticMath per button.\n *\n * - **interactive** (latex contains `\\MathQuillMathField[..]{}` /\n * `\\placeholder[..]{}`): a read-only `<math-field>` whose placeholders stay\n * editable. Sub-field values are surfaced through the prompts API, replacing\n * MathQuill's `innerFields`.\n */\nexport default class Static extends React.Component {\n static propTypes = {\n latex: PropTypes.string.isRequired,\n className: PropTypes.string,\n onFocus: PropTypes.func,\n onBlur: PropTypes.func,\n getFieldName: PropTypes.func,\n onSubFieldChange: PropTypes.func,\n onSubFieldFocus: PropTypes.func,\n setInput: PropTypes.func,\n };\n\n static defaultProps = {\n getFieldName: () => {},\n };\n\n constructor(props) {\n super(props);\n this.holderRef = React.createRef();\n this.state = { markup: '' };\n this.promptValues = {};\n }\n\n async componentDidMount() {\n if (!this.isInteractive()) {\n await loadMathLive();\n this.renderMarkup();\n return;\n }\n\n const ml = await loadMathLive();\n\n if (!ml || !this.holderRef.current) {\n return;\n }\n\n this.mathField = new ml.MathfieldElement({ macros: getMacros() });\n this.mathField.readOnly = true;\n this.mathField.mathVirtualKeyboardPolicy = 'manual';\n this.mathField.value = toMathLive(this.props.latex);\n\n this.mathField.addEventListener('input', this.onPromptInput);\n this.mathField.addEventListener('focusin', this.onPromptFocus);\n this.mathField.addEventListener('keydown', this.onKeyDown);\n\n this.holderRef.current.appendChild(this.mathField);\n\n this.createLiveRegion();\n }\n\n componentDidUpdate(prevProps) {\n if (prevProps.latex === this.props.latex) {\n return;\n }\n\n if (this.mathField) {\n this.mathField.value = toMathLive(this.props.latex);\n } else {\n this.renderMarkup();\n }\n }\n\n componentWillUnmount() {\n if (this.mathField) {\n this.mathField.removeEventListener('input', this.onPromptInput);\n this.mathField.removeEventListener('focusin', this.onPromptFocus);\n this.mathField.removeEventListener('keydown', this.onKeyDown);\n this.mathField.remove();\n this.mathField = undefined;\n }\n\n this.removeLiveRegion();\n }\n\n /**\n * Off-screen aria-live region, ported from @pie-lib/math-input's Static.\n *\n * MathLive has its own accessibility layer, but it does not announce that\n * typed input was converted into a math symbol, which screen-reader users\n * relied on in the MathQuill implementation.\n */\n createLiveRegion = () => {\n if (typeof document === 'undefined' || this.liveRegion) {\n return;\n }\n\n this.liveRegion = document.createElement('div');\n Object.assign(this.liveRegion.style, {\n position: 'absolute',\n width: '1px',\n height: '1px',\n marginTop: '-1px',\n clip: 'rect(1px, 1px, 1px, 1px)',\n overflow: 'hidden',\n });\n this.liveRegion.setAttribute('aria-live', 'polite');\n this.liveRegion.setAttribute('aria-atomic', 'true');\n\n document.body.appendChild(this.liveRegion);\n };\n\n removeLiveRegion = () => {\n if (this.liveRegion && this.liveRegion.parentNode) {\n this.liveRegion.parentNode.removeChild(this.liveRegion);\n }\n\n this.liveRegion = undefined;\n };\n\n announce = (message) => {\n if (!this.liveRegion) {\n return;\n }\n\n this.liveRegion.textContent = message;\n\n // Clear once announced, so the same message can be announced again.\n clearTimeout(this.announceTimeout);\n this.announceTimeout = setTimeout(() => {\n if (this.liveRegion) {\n this.liveRegion.textContent = '';\n }\n }, 500);\n };\n\n onKeyDown = (event) => {\n // Deletions should not be announced as conversions.\n this.isDeleting = event?.key === 'Backspace' || event?.key === 'Delete';\n };\n\n /**\n * Announce when typed input became a math symbol. The MathQuill version\n * inferred this by counting braces; here a prompt whose latex grew by more\n * than the single character typed means a command was expanded.\n */\n announceConversion = (next) => {\n if (this.isDeleting) {\n this.isDeleting = false;\n return;\n }\n\n const converted = Object.keys(next).some((id) => {\n const before = this.promptValues[id] || '';\n const after = next[id] || '';\n\n return after.length > before.length + 1 && /\\\\/.test(after.slice(before.length));\n });\n\n if (converted) {\n this.announce('Converted to math symbol');\n }\n };\n\n /** Does this latex contain answer blocks? */\n isInteractive() {\n const latex = this.props.latex || '';\n\n return fieldIds(latex).length > 0 || latex.indexOf('\\\\placeholder') !== -1;\n }\n\n renderMarkup() {\n const markup = latexToMarkup(this.props.latex);\n\n if (markup !== this.state.markup) {\n this.setState({ markup });\n }\n }\n\n /** MathQuill's `innerFields` equivalent, keyed by prompt id. */\n values() {\n if (!this.mathField) {\n return {};\n }\n\n const out = {};\n\n (this.mathField.getPrompts() || []).forEach((id) => {\n out[id] = fromMathLive(this.mathField.getPromptValue(id));\n });\n\n return out;\n }\n\n /**\n * A MathQuill-inner-field-like handle for a prompt.\n *\n * The old API handed callers a MathQuill field object, and consumers commonly\n * called `field.latex()` on it. There is no equivalent object in MathLive -\n * prompts are addressed by id - so this adapter exposes the parts that were\n * actually used: `id` and a get/set `latex()`.\n */\n promptHandle(id) {\n return {\n id,\n latex: (value) => {\n if (!this.mathField) {\n return '';\n }\n\n if (value === undefined) {\n return fromMathLive(this.mathField.getPromptValue(id));\n }\n\n this.mathField.setPromptValue(id, toMathLive(value), {});\n\n return value;\n },\n };\n }\n\n /** All prompt handles, the analogue of `mathField.innerFields`. */\n get innerFields() {\n if (!this.mathField) {\n return [];\n }\n\n return (this.mathField.getPrompts() || []).map((id) => this.promptHandle(id));\n }\n\n onPromptInput = () => {\n const { onSubFieldChange, getFieldName } = this.props;\n\n if (!this.mathField) {\n return;\n }\n\n const next = this.values();\n\n this.announceConversion(next);\n\n if (!onSubFieldChange) {\n this.promptValues = next;\n return;\n }\n\n const fields = this.innerFields;\n\n // Emit only the prompts whose value actually changed, mirroring the\n // per-field granularity of the old onSubFieldChange(name, latex).\n Object.keys(next).forEach((id) => {\n if (next[id] === this.promptValues[id]) {\n return;\n }\n\n const name = getFieldName(this.promptHandle(id), fields) || id;\n\n onSubFieldChange(name, next[id]);\n });\n\n this.promptValues = next;\n };\n\n onPromptFocus = () => {\n const { onSubFieldFocus, getFieldName } = this.props;\n\n if (!this.mathField || !onSubFieldFocus) {\n return;\n }\n\n try {\n const ids = this.mathField.getPrompts() || [];\n // The focused prompt is the one containing the current selection.\n const focused = ids.find((id) => {\n const range = this.mathField.getPromptRange(id);\n const selection = this.mathField.selection;\n\n if (!range || !selection || !selection.ranges || !selection.ranges.length) {\n return false;\n }\n\n const [start, end] = range;\n const [selStart] = selection.ranges[0];\n\n return selStart >= start && selStart <= end;\n });\n\n if (focused) {\n const handle = this.promptHandle(focused);\n const name = getFieldName(handle, this.innerFields) || focused;\n\n if (this.props.setInput) {\n this.props.setInput(handle);\n }\n\n onSubFieldFocus(name, handle);\n }\n } catch (e) {\n log('error resolving focused prompt: %s', e.message);\n }\n };\n\n focus() {\n this.mathField && this.mathField.focus();\n }\n\n blur() {\n this.mathField && this.mathField.blur();\n }\n\n render() {\n const { className, onFocus, onBlur } = this.props;\n const { markup } = this.state;\n\n if (this.mathField || this.isInteractive()) {\n return <Holder className={className} onFocus={onFocus} onBlur={onBlur} ref={this.holderRef} />;\n }\n\n return (\n <Holder\n className={className}\n onFocus={onFocus}\n onBlur={onBlur}\n ref={this.holderRef}\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: markup }}\n />\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pie-lib/math-input-mathlive",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "1.0.0",
|
|
7
|
+
"description": "MathLive-based math input (drop-in alternative to @pie-lib/math-input)",
|
|
8
|
+
"main": "lib/index.js",
|
|
9
|
+
"module": "src/index.jsx",
|
|
10
|
+
"repository": "pie-framework/pie-lib",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@emotion/react": "^11.14.0",
|
|
14
|
+
"@emotion/styled": "^11.14.1",
|
|
15
|
+
"@mui/icons-material": "^7.3.4",
|
|
16
|
+
"@mui/material": "^7.3.4",
|
|
17
|
+
"@pie-lib/render-ui": "^6.1.0",
|
|
18
|
+
"debug": "^4.1.1",
|
|
19
|
+
"lodash-es": "^4.17.23",
|
|
20
|
+
"mathlive": "^0.110.0",
|
|
21
|
+
"prop-types": "^15.7.2"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react": "^18.2.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"react": "^18.2.0",
|
|
28
|
+
"react-dom": "^18.2.0"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {}
|
|
31
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
keys,
|
|
6
|
+
keysForGrade,
|
|
7
|
+
addBrackets,
|
|
8
|
+
removeBrackets,
|
|
9
|
+
registerEmbed,
|
|
10
|
+
applyStaticMath,
|
|
11
|
+
updateSpans,
|
|
12
|
+
mf,
|
|
13
|
+
mq,
|
|
14
|
+
MathInput,
|
|
15
|
+
HorizontalKeypad,
|
|
16
|
+
KeyPad,
|
|
17
|
+
} from '../index';
|
|
18
|
+
|
|
19
|
+
describe('math-input-mathlive public API', () => {
|
|
20
|
+
it('mirrors the @pie-lib/math-input export surface', () => {
|
|
21
|
+
expect(typeof keysForGrade).toBe('function');
|
|
22
|
+
expect(typeof addBrackets).toBe('function');
|
|
23
|
+
expect(typeof removeBrackets).toBe('function');
|
|
24
|
+
expect(typeof registerEmbed).toBe('function');
|
|
25
|
+
expect(typeof applyStaticMath).toBe('function');
|
|
26
|
+
expect(typeof updateSpans).toBe('function');
|
|
27
|
+
expect(keys).toBeDefined();
|
|
28
|
+
expect(keys.baseSet).toBeDefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('exports the field wrappers under both mf and mq', () => {
|
|
32
|
+
expect(mf.Input).toBeDefined();
|
|
33
|
+
expect(mf.Static).toBeDefined();
|
|
34
|
+
// `mq` alias lets a consumer swap packages by changing only the import.
|
|
35
|
+
expect(mq).toBe(mf);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('updateSpans is a safe no-op', () => {
|
|
39
|
+
expect(() => updateSpans()).not.toThrow();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('CommonMqStyles keeps the shape consumers destructure', () => {
|
|
43
|
+
// math-toolbar does:
|
|
44
|
+
// const { commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, supsubStyles }
|
|
45
|
+
// = mq.CommonMqStyles;
|
|
46
|
+
const { commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, supsubStyles } = mf.CommonMqStyles;
|
|
47
|
+
|
|
48
|
+
[commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, supsubStyles].forEach((s) => {
|
|
49
|
+
expect(s).toBeDefined();
|
|
50
|
+
expect(typeof s).toBe('object');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('bracket helpers round-trip', () => {
|
|
55
|
+
expect(addBrackets('x')).toEqual('\\(x\\)');
|
|
56
|
+
expect(removeBrackets('\\(x\\)')).toEqual('x');
|
|
57
|
+
expect(removeBrackets(addBrackets('\\frac{1}{2}'))).toEqual('\\frac{1}{2}');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('keysForGrade returns a 5-row keyset', () => {
|
|
61
|
+
const set = keysForGrade('geometry');
|
|
62
|
+
|
|
63
|
+
expect(Array.isArray(set)).toBe(true);
|
|
64
|
+
expect(set.length).toBe(5);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('rendering', () => {
|
|
69
|
+
// MathLive is a browser-only custom element; loadMathLive() resolves async and
|
|
70
|
+
// is a no-op-ish under jsdom. These assert the components mount without
|
|
71
|
+
// throwing, which is what regressed most often in the MathQuill version.
|
|
72
|
+
it('KeyPad renders without a live MathLive instance', () => {
|
|
73
|
+
const { container } = render(<KeyPad onPress={() => {}} />);
|
|
74
|
+
|
|
75
|
+
expect(container.querySelectorAll('button').length).toBeGreaterThan(0);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('KeyPad falls back to raw latex for labels before MathLive loads', () => {
|
|
79
|
+
const { container } = render(
|
|
80
|
+
<KeyPad onPress={() => {}} baseSet={[[{ name: 'pi', latex: '\\pi', category: 'constants' }]]} />,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(container.textContent).toContain('\\pi');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('KeyPad fires onPress with the key definition', () => {
|
|
87
|
+
const onPress = jest.fn();
|
|
88
|
+
const key = { name: 'x', label: 'x', write: 'x', category: 'vars' };
|
|
89
|
+
const { container } = render(<KeyPad onPress={onPress} baseSet={[[key]]} />);
|
|
90
|
+
|
|
91
|
+
container.querySelector('button').click();
|
|
92
|
+
|
|
93
|
+
expect(onPress).toHaveBeenCalledWith(key);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('MathInput mounts', () => {
|
|
97
|
+
expect(() => render(<MathInput latex="\\frac{1}{2}" onChange={() => {}} />)).not.toThrow();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('HorizontalKeypad mounts and reports the legacy {value,type} model', () => {
|
|
101
|
+
const onClick = jest.fn();
|
|
102
|
+
|
|
103
|
+
expect(() => render(<HorizontalKeypad onClick={onClick} />)).not.toThrow();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('Static renders display-mode latex without a mathfield', () => {
|
|
107
|
+
expect(() => render(<mf.Static latex="\\frac{1}{2}" />)).not.toThrow();
|
|
108
|
+
});
|
|
109
|
+
});
|