@pie-lib/math-input-mathlive 1.1.5-beta.8 → 2.0.1-next.20261107131445
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -109
- package/dist/_virtual/_rolldown/runtime.js +11 -0
- package/dist/horizontal-keypad.d.ts +22 -0
- package/dist/horizontal-keypad.js +54 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +12 -0
- package/dist/keypad/index.d.ts +40 -0
- package/dist/keypad/index.js +245 -0
- package/dist/keypad/keys-layout.d.ts +7 -0
- package/dist/keypad/keys-layout.js +5 -0
- package/dist/keys/basic-operators.d.ts +5 -0
- package/dist/keys/basic-operators.js +30 -0
- package/dist/keys/chars.d.ts +5 -0
- package/dist/keys/comparison.d.ts +4 -0
- package/dist/keys/comparison.js +32 -0
- package/dist/keys/constants.d.ts +4 -0
- package/dist/keys/constants.js +35 -0
- package/dist/keys/digits.d.ts +15 -0
- package/dist/keys/digits.js +34 -0
- package/dist/keys/edit.d.ts +6 -0
- package/dist/keys/edit.js +9 -0
- package/dist/keys/exponent.d.ts +4 -0
- package/dist/keys/exponent.js +28 -0
- package/dist/keys/fractions.d.ts +3 -0
- package/dist/keys/fractions.js +27 -0
- package/dist/keys/geometry.d.ts +23 -0
- package/dist/keys/geometry.js +127 -0
- package/dist/keys/grades.d.ts +9 -0
- package/dist/keys/grades.js +414 -0
- package/dist/keys/index.d.ts +6 -0
- package/dist/keys/index.js +50 -0
- package/dist/keys/log.d.ts +3 -0
- package/dist/keys/log.js +25 -0
- package/dist/keys/logic.d.ts +2 -0
- package/dist/keys/logic.js +13 -0
- package/dist/keys/matrices.d.ts +2 -0
- package/dist/keys/matrices.js +17 -0
- package/dist/keys/misc.d.ts +10 -0
- package/dist/keys/misc.js +60 -0
- package/dist/keys/navigation.d.ts +2 -0
- package/dist/keys/navigation.js +13 -0
- package/dist/keys/operators.d.ts +1 -0
- package/dist/keys/operators.js +11 -0
- package/dist/keys/statistics.d.ts +5 -0
- package/dist/keys/statistics.js +38 -0
- package/dist/keys/sub-sup.d.ts +2 -0
- package/dist/keys/sub-sup.js +17 -0
- package/dist/keys/trigonometry.d.ts +6 -0
- package/dist/keys/trigonometry.js +43 -0
- package/dist/keys/utils.d.ts +5 -0
- package/dist/keys/utils.js +24 -0
- package/dist/keys/vars.d.ts +3 -0
- package/dist/keys/vars.js +22 -0
- package/dist/latex-bridge.d.ts +197 -0
- package/dist/latex-bridge.js +210 -0
- package/dist/longdiv.d.ts +24 -0
- package/dist/longdiv.js +43 -0
- package/dist/math-input.d.ts +26 -0
- package/dist/math-input.js +74 -0
- package/dist/mathlive-instance.d.ts +221 -0
- package/dist/mathlive-instance.js +159 -0
- package/dist/mf/common-styles.d.ts +594 -0
- package/dist/mf/common-styles.js +80 -0
- package/dist/mf/field-label.d.ts +16 -0
- package/dist/mf/field-label.js +13 -0
- package/dist/mf/index.d.ts +4 -0
- package/dist/mf/index.js +21 -0
- package/dist/mf/input.d.ts +94 -0
- package/dist/mf/input.js +127 -0
- package/dist/mf/static.d.ts +143 -0
- package/dist/mf/static.js +230 -0
- package/dist/selection.d.ts +43 -0
- package/dist/selection.js +39 -0
- package/package.json +32 -18
- package/lib/__tests__/composites.test.js +0 -255
- package/lib/__tests__/drop-in-compat.test.js +0 -133
- package/lib/__tests__/embedded-fonts.test.js +0 -121
- package/lib/__tests__/index.test.js +0 -118
- package/lib/__tests__/input-imperative.test.js +0 -155
- package/lib/__tests__/input-selection.test.js +0 -103
- package/lib/__tests__/keypad-label.test.js +0 -231
- package/lib/__tests__/keypad-render.test.js +0 -206
- package/lib/__tests__/latex-bridge.test.js +0 -386
- package/lib/__tests__/mathlive-instance.test.js +0 -419
- package/lib/__tests__/mount-race.test.js +0 -218
- package/lib/__tests__/selection.test.js +0 -195
- package/lib/__tests__/static-prompts.test.js +0 -405
- package/lib/__tests__/tmp-markup.test.js +0 -26
- package/lib/horizontal-keypad.js +0 -101
- package/lib/horizontal-keypad.js.map +0 -1
- package/lib/index.js +0 -143
- package/lib/index.js.map +0 -1
- package/lib/keypad/index.js +0 -431
- package/lib/keypad/index.js.map +0 -1
- package/lib/keypad/keys-layout.js +0 -22
- package/lib/keypad/keys-layout.js.map +0 -1
- package/lib/keys/basic-operators.js +0 -33
- package/lib/keys/basic-operators.js.map +0 -1
- package/lib/keys/chars.js +0 -12
- package/lib/keys/chars.js.map +0 -1
- package/lib/keys/comparison.js +0 -39
- package/lib/keys/comparison.js.map +0 -1
- package/lib/keys/constants.js +0 -37
- package/lib/keys/constants.js.map +0 -1
- package/lib/keys/digits.js +0 -46
- package/lib/keys/digits.js.map +0 -1
- package/lib/keys/edit.js +0 -14
- package/lib/keys/edit.js.map +0 -1
- package/lib/keys/exponent.js +0 -30
- package/lib/keys/exponent.js.map +0 -1
- package/lib/keys/fractions.js +0 -29
- package/lib/keys/fractions.js.map +0 -1
- package/lib/keys/geometry.js +0 -143
- package/lib/keys/geometry.js.map +0 -1
- package/lib/keys/grades.js +0 -259
- package/lib/keys/grades.js.map +0 -1
- package/lib/keys/index.js +0 -35
- package/lib/keys/index.js.map +0 -1
- package/lib/keys/log.js +0 -27
- package/lib/keys/log.js.map +0 -1
- package/lib/keys/logic.js +0 -19
- package/lib/keys/logic.js.map +0 -1
- package/lib/keys/matrices.js +0 -19
- package/lib/keys/matrices.js.map +0 -1
- package/lib/keys/misc.js +0 -69
- package/lib/keys/misc.js.map +0 -1
- package/lib/keys/navigation.js +0 -20
- package/lib/keys/navigation.js.map +0 -1
- package/lib/keys/operators.js +0 -15
- package/lib/keys/operators.js.map +0 -1
- package/lib/keys/statistics.js +0 -40
- package/lib/keys/statistics.js.map +0 -1
- package/lib/keys/sub-sup.js +0 -19
- package/lib/keys/sub-sup.js.map +0 -1
- package/lib/keys/trigonometry.js +0 -45
- package/lib/keys/trigonometry.js.map +0 -1
- package/lib/keys/utils.js +0 -87
- package/lib/keys/utils.js.map +0 -1
- package/lib/keys/vars.js +0 -24
- package/lib/keys/vars.js.map +0 -1
- package/lib/latex-bridge.js +0 -445
- package/lib/latex-bridge.js.map +0 -1
- package/lib/math-input.js +0 -143
- package/lib/math-input.js.map +0 -1
- package/lib/mathlive-instance.js +0 -585
- package/lib/mathlive-instance.js.map +0 -1
- package/lib/mf/common-styles.js +0 -203
- package/lib/mf/common-styles.js.map +0 -1
- package/lib/mf/index.js +0 -84
- package/lib/mf/index.js.map +0 -1
- package/lib/mf/input.js +0 -372
- package/lib/mf/input.js.map +0 -1
- package/lib/mf/static.js +0 -500
- package/lib/mf/static.js.map +0 -1
- package/lib/selection.js +0 -148
- package/lib/selection.js.map +0 -1
- package/src/__tests__/composites.test.jsx +0 -220
- package/src/__tests__/drop-in-compat.test.jsx +0 -112
- package/src/__tests__/index.test.jsx +0 -109
- package/src/__tests__/input-imperative.test.jsx +0 -144
- package/src/__tests__/input-selection.test.jsx +0 -64
- package/src/__tests__/keypad-label.test.jsx +0 -283
- package/src/__tests__/keypad-render.test.jsx +0 -123
- package/src/__tests__/latex-bridge.test.js +0 -359
- package/src/__tests__/mathlive-instance.test.js +0 -418
- package/src/__tests__/mount-race.test.jsx +0 -142
- package/src/__tests__/selection.test.js +0 -212
- package/src/__tests__/static-prompts.test.jsx +0 -364
- package/src/horizontal-keypad.jsx +0 -73
- package/src/index.jsx +0 -63
- package/src/keypad/index.jsx +0 -386
- package/src/keypad/keys-layout.js +0 -16
- package/src/keys/basic-operators.js +0 -32
- package/src/keys/chars.js +0 -5
- package/src/keys/comparison.js +0 -28
- package/src/keys/constants.js +0 -35
- package/src/keys/digits.js +0 -40
- package/src/keys/edit.js +0 -3
- package/src/keys/exponent.js +0 -28
- package/src/keys/fractions.js +0 -26
- package/src/keys/geometry.js +0 -149
- package/src/keys/grades.js +0 -367
- package/src/keys/index.js +0 -20
- package/src/keys/log.js +0 -22
- package/src/keys/logic.js +0 -15
- package/src/keys/matrices.js +0 -15
- package/src/keys/misc.js +0 -71
- package/src/keys/navigation.js +0 -8
- package/src/keys/operators.js +0 -10
- package/src/keys/statistics.js +0 -38
- package/src/keys/sub-sup.js +0 -15
- package/src/keys/trigonometry.js +0 -15
- package/src/keys/utils.js +0 -66
- package/src/keys/vars.js +0 -19
- package/src/latex-bridge.js +0 -449
- package/src/math-input.jsx +0 -115
- package/src/mathlive-instance.js +0 -582
- package/src/mf/common-styles.js +0 -210
- package/src/mf/index.js +0 -30
- package/src/mf/input.jsx +0 -328
- package/src/mf/static.jsx +0 -479
- package/src/selection.js +0 -146
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import Input from './input.js';
|
|
2
|
+
import Static from './static.js';
|
|
3
|
+
import CommonMqStyles, { commonMathLiveStyles, commonKeyboardStyles, commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, rootIndexStyles, parallelStyles, supsubStyles, placeholderStyles } from './common-styles.js';
|
|
4
|
+
export { Input, Static, CommonMqStyles, commonMathLiveStyles, commonKeyboardStyles, commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, rootIndexStyles, parallelStyles, supsubStyles, placeholderStyles, };
|
package/dist/mf/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { __exportAll as e } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import t, { commonKeyboardStyles as n, commonMathLiveStyles as r, commonMqFontStyles as i, commonMqKeyboardStyles as a, longdivStyles as o, parallelStyles as s, placeholderStyles as c, rootIndexStyles as l, supsubStyles as u } from "./common-styles.js";
|
|
3
|
+
import { Input as d } from "./input.js";
|
|
4
|
+
import f from "./static.js";
|
|
5
|
+
//#region src/mf/index.ts
|
|
6
|
+
var p = /* @__PURE__ */ e({
|
|
7
|
+
CommonMqStyles: () => t,
|
|
8
|
+
Input: () => d,
|
|
9
|
+
Static: () => f,
|
|
10
|
+
commonKeyboardStyles: () => n,
|
|
11
|
+
commonMathLiveStyles: () => r,
|
|
12
|
+
commonMqFontStyles: () => i,
|
|
13
|
+
commonMqKeyboardStyles: () => a,
|
|
14
|
+
longdivStyles: () => o,
|
|
15
|
+
parallelStyles: () => s,
|
|
16
|
+
placeholderStyles: () => c,
|
|
17
|
+
rootIndexStyles: () => l,
|
|
18
|
+
supsubStyles: () => u
|
|
19
|
+
});
|
|
20
|
+
//#endregion
|
|
21
|
+
export { t as CommonMqStyles, d as Input, f as Static, n as commonKeyboardStyles, r as commonMathLiveStyles, i as commonMqFontStyles, a as commonMqKeyboardStyles, o as longdivStyles, p as mf_exports, s as parallelStyles, c as placeholderStyles, l as rootIndexStyles, u as supsubStyles };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
/**
|
|
4
|
+
* Editable math field. Drop-in replacement for @pie-lib/math-input's `mq.Input`.
|
|
5
|
+
*
|
|
6
|
+
* Keeps the same imperative surface used by MathInput's keypad
|
|
7
|
+
* (`write`, `command`, `keystroke`, `clear`, `focus`, `blur`) so callers do not
|
|
8
|
+
* change, and the same `latex` / `onChange` props.
|
|
9
|
+
*/
|
|
10
|
+
export declare class Input extends React.Component {
|
|
11
|
+
static propTypes: {
|
|
12
|
+
className: PropTypes.Requireable<string>;
|
|
13
|
+
latex: PropTypes.Requireable<string>;
|
|
14
|
+
onChange: PropTypes.Requireable<(...args: any[]) => any>;
|
|
15
|
+
onClick: PropTypes.Requireable<(...args: any[]) => any>;
|
|
16
|
+
onFocus: PropTypes.Requireable<(...args: any[]) => any>;
|
|
17
|
+
onBlur: PropTypes.Requireable<(...args: any[]) => any>;
|
|
18
|
+
language: PropTypes.Requireable<string>;
|
|
19
|
+
ariaDescribedBy: PropTypes.Requireable<string>;
|
|
20
|
+
readOnly: PropTypes.Requireable<boolean>;
|
|
21
|
+
innerRef: PropTypes.Requireable<(...args: any[]) => any>;
|
|
22
|
+
};
|
|
23
|
+
constructor(props: any);
|
|
24
|
+
componentDidMount(): Promise<void>;
|
|
25
|
+
componentDidUpdate(prevProps: any): void;
|
|
26
|
+
componentWillUnmount(): void;
|
|
27
|
+
onInputEdit: () => void;
|
|
28
|
+
/** Current latex, in stored (MathQuill-compatible) form. */
|
|
29
|
+
latex(): any;
|
|
30
|
+
/**
|
|
31
|
+
* The underlying `<math-field>` element, or undefined until MathLive has
|
|
32
|
+
* finished loading. Exposed for callers that need the real element.
|
|
33
|
+
*
|
|
34
|
+
* NOTE: this is NOT a MathQuill field. Code written against
|
|
35
|
+
* `@pie-lib/math-input` often did `input.mathField.latex()`; that shape is
|
|
36
|
+
* provided by `mqCompat` below, and `latex()` on this component is the
|
|
37
|
+
* supported replacement.
|
|
38
|
+
*/
|
|
39
|
+
get element(): any;
|
|
40
|
+
/**
|
|
41
|
+
* MathQuill-shaped facade, so existing `input.mathField.latex()` /
|
|
42
|
+
* `.el()` call sites keep working instead of throwing. Only the members that
|
|
43
|
+
* consumers actually used are provided; MathQuill internals such as
|
|
44
|
+
* `__controller` have no MathLive equivalent and are deliberately absent.
|
|
45
|
+
*/
|
|
46
|
+
get mqCompat(): {
|
|
47
|
+
latex: (v: any) => any;
|
|
48
|
+
el: () => any;
|
|
49
|
+
focus: () => void;
|
|
50
|
+
blur: () => void;
|
|
51
|
+
};
|
|
52
|
+
/** Programmatically replace the content. */
|
|
53
|
+
setLatex(v: any): void;
|
|
54
|
+
clear(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Join a mixed number that was typed with a space (PD-1858).
|
|
57
|
+
*
|
|
58
|
+
* Typing `1`, space, `2`, `/` gives `1\ \frac{2}{}`: `/` takes only the digits
|
|
59
|
+
* after the space as the numerator. The whole number belongs right next to
|
|
60
|
+
* the fraction, so the space is removed, keeping the caret in the empty
|
|
61
|
+
* denominator.
|
|
62
|
+
*
|
|
63
|
+
* @returns {boolean} whether the latex changed
|
|
64
|
+
*/
|
|
65
|
+
joinMixedNumber(): boolean;
|
|
66
|
+
blur(): void;
|
|
67
|
+
focus(): void;
|
|
68
|
+
/**
|
|
69
|
+
* MathQuill `cmd()` equivalent.
|
|
70
|
+
*
|
|
71
|
+
* Callers pass MathQuill command names (`'\\frac'`, `'\\sqrt'`, `'^'`, or an
|
|
72
|
+
* array of them). Those must be expanded into latex with `#?` placeholders,
|
|
73
|
+
* otherwise inserting a bare `\frac` produces no editable slots.
|
|
74
|
+
*/
|
|
75
|
+
command(v: any): any;
|
|
76
|
+
/**
|
|
77
|
+
* MathQuill `keystroke()` equivalent.
|
|
78
|
+
*
|
|
79
|
+
* Accepts MathQuill keystroke names (`'Left'`, `'Right'`, `'Backspace'`) as
|
|
80
|
+
* the keypad emits them, and passes anything else through as a MathLive
|
|
81
|
+
* selector.
|
|
82
|
+
*/
|
|
83
|
+
keystroke(v: any): any;
|
|
84
|
+
/** MathQuill `write()` equivalent. Accepts an array, as `cmd()` did. */
|
|
85
|
+
write(v: any): any;
|
|
86
|
+
/**
|
|
87
|
+
* Enter must not insert a line break: math input is single-expression, and
|
|
88
|
+
* the MathQuill version swallowed charCode 13 for the same reason. Newlines
|
|
89
|
+
* are authored explicitly through the newLine embed, not the Enter key.
|
|
90
|
+
*/
|
|
91
|
+
onKeyDown: (event: any) => void;
|
|
92
|
+
render(): React.JSX.Element;
|
|
93
|
+
}
|
|
94
|
+
export default Input;
|
package/dist/mf/input.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { KEYSTROKES as e, fromMathLive as t, keyToAction as n, toMathLive as r } from "../latex-bridge.js";
|
|
2
|
+
import { trackLongDivision as i } from "../longdiv.js";
|
|
3
|
+
import { applyShadowStyles as a, createMathField as o, loadMathLive as s, trackPlaceholderCaret as c } from "../mathlive-instance.js";
|
|
4
|
+
import { describeMathField as l, labelMathField as u } from "./field-label.js";
|
|
5
|
+
import { trackWholeAtomSelection as d } from "../selection.js";
|
|
6
|
+
import f from "react";
|
|
7
|
+
import p from "prop-types";
|
|
8
|
+
import { styled as m } from "@mui/material/styles";
|
|
9
|
+
import h from "debug";
|
|
10
|
+
import { jsx as g } from "react/jsx-runtime";
|
|
11
|
+
//#region src/mf/input.tsx
|
|
12
|
+
var _ = h("pie-lib:math-input-mathlive:input"), v = /([0-9])\\ (\\frac\{[^{}]*\}\{(?:\\placeholder\{\})?\})/, y = m("span")({
|
|
13
|
+
display: "inline-block",
|
|
14
|
+
"& math-field": {
|
|
15
|
+
display: "block",
|
|
16
|
+
width: "100%"
|
|
17
|
+
},
|
|
18
|
+
"& math-field::part(virtual-keyboard-toggle)": { display: "none" },
|
|
19
|
+
"& math-field::part(menu-toggle)": { display: "none" }
|
|
20
|
+
}), b = class extends f.Component {
|
|
21
|
+
static propTypes = {
|
|
22
|
+
className: p.string,
|
|
23
|
+
latex: p.string,
|
|
24
|
+
onChange: p.func,
|
|
25
|
+
onClick: p.func,
|
|
26
|
+
onFocus: p.func,
|
|
27
|
+
onBlur: p.func,
|
|
28
|
+
language: p.string,
|
|
29
|
+
ariaDescribedBy: p.string,
|
|
30
|
+
readOnly: p.bool,
|
|
31
|
+
innerRef: p.func
|
|
32
|
+
};
|
|
33
|
+
constructor(e) {
|
|
34
|
+
super(e), this.holderRef = f.createRef(), this.lastEmitted = void 0;
|
|
35
|
+
}
|
|
36
|
+
async componentDidMount() {
|
|
37
|
+
let e = this.mountGeneration = (this.mountGeneration || 0) + 1, t = await s();
|
|
38
|
+
e === this.mountGeneration && t?.MathfieldElement && this.holderRef.current && !this.mathField && (this.mathField = o(t), u(this.mathField, this.props.language), l(this.mathField, this.props.ariaDescribedBy), this.mathField.value = r(this.props.latex || ""), this.props.readOnly && (this.mathField.readOnly = !0), this.mathField.mathVirtualKeyboardPolicy = "manual", this.mathField.mathModeSpace = "\\ ", this.mathField.smartSuperscript = !1, a(this.mathField), this.untrackCaret = c(this.mathField), this.untrackSelection = d(this.mathField), this.untrackLongDivision = i(this.mathField), this.mathField.addEventListener("input", this.onInputEdit), this.holderRef.current.replaceChildren(this.mathField), u(this.mathField, this.props.language), this.props.innerRef && this.props.innerRef(this), this.pendingFocus && (this.pendingFocus = !1, this.mathField.focus()));
|
|
39
|
+
}
|
|
40
|
+
componentDidUpdate(e) {
|
|
41
|
+
if (!this.mathField) return;
|
|
42
|
+
let { latex: t, readOnly: n, language: i } = this.props;
|
|
43
|
+
if (i !== e.language && u(this.mathField, i), this.props.ariaDescribedBy !== e.ariaDescribedBy && l(this.mathField, this.props.ariaDescribedBy), n !== e.readOnly && (this.mathField.readOnly = !!n), t != null && t !== this.lastEmitted) {
|
|
44
|
+
let e = r(t);
|
|
45
|
+
e !== this.mathField.value && (this.mathField.value = e);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
componentWillUnmount() {
|
|
49
|
+
this.mountGeneration = (this.mountGeneration || 0) + 1, this.untrackCaret &&= (this.untrackCaret(), void 0), this.untrackSelection &&= (this.untrackSelection(), void 0), this.untrackLongDivision &&= (this.untrackLongDivision(), void 0), this.mathField &&= (this.mathField.removeEventListener("input", this.onInputEdit), this.mathField.remove(), void 0), this.props.innerRef && this.props.innerRef(null);
|
|
50
|
+
}
|
|
51
|
+
onInputEdit = () => {
|
|
52
|
+
let { onChange: e } = this.props;
|
|
53
|
+
if (!this.mathField) return;
|
|
54
|
+
let n = t(this.mathField.getValue("latex"));
|
|
55
|
+
this.lastEmitted = n, e && e(n);
|
|
56
|
+
};
|
|
57
|
+
latex() {
|
|
58
|
+
return this.mathField ? t(this.mathField.getValue("latex")) : "";
|
|
59
|
+
}
|
|
60
|
+
get element() {
|
|
61
|
+
return this.mathField;
|
|
62
|
+
}
|
|
63
|
+
get mqCompat() {
|
|
64
|
+
return {
|
|
65
|
+
latex: (e) => e === void 0 ? this.latex() : (this.setLatex(e), e),
|
|
66
|
+
el: () => this.mathField,
|
|
67
|
+
focus: () => this.focus(),
|
|
68
|
+
blur: () => this.blur()
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
setLatex(e) {
|
|
72
|
+
this.mathField && (this.mathField.value = r(e || ""));
|
|
73
|
+
}
|
|
74
|
+
clear() {
|
|
75
|
+
return this.mathField && (this.mathField.value = "", this.onInputEdit()), "";
|
|
76
|
+
}
|
|
77
|
+
joinMixedNumber() {
|
|
78
|
+
if (!this.mathField) return !1;
|
|
79
|
+
let e = this.mathField.getValue("latex"), t = e.replace(v, "$1$2");
|
|
80
|
+
if (t === e) return !1;
|
|
81
|
+
let { ranges: n, direction: r } = this.mathField.selection;
|
|
82
|
+
return this.mathField.value = t, this.mathField.selection = {
|
|
83
|
+
ranges: n.map(([e, t]) => [e - 1, t - 1]),
|
|
84
|
+
direction: r
|
|
85
|
+
}, this.onInputEdit(), !0;
|
|
86
|
+
}
|
|
87
|
+
blur() {
|
|
88
|
+
_("blur mathfield"), this.pendingFocus = !1, this.mathField && this.mathField.blur();
|
|
89
|
+
}
|
|
90
|
+
focus() {
|
|
91
|
+
_("focus mathfield..."), this.mathField ? this.mathField.focus() : this.pendingFocus = !0;
|
|
92
|
+
}
|
|
93
|
+
command(e) {
|
|
94
|
+
if (_("command: ", e), !this.mathField) return "";
|
|
95
|
+
let t = n({ command: e });
|
|
96
|
+
return t && this.mathField.insert(t.value, { focus: !0 }), this.mathField.focus(), this.latex();
|
|
97
|
+
}
|
|
98
|
+
keystroke(t) {
|
|
99
|
+
if (_("keystroke: ", t), !this.mathField) return "";
|
|
100
|
+
let n = e[t] || t;
|
|
101
|
+
try {
|
|
102
|
+
this.mathField.executeCommand(n);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
_("unknown keystroke/selector \"%s\": %s", t, e && e.message);
|
|
105
|
+
}
|
|
106
|
+
return this.mathField.focus(), this.latex();
|
|
107
|
+
}
|
|
108
|
+
write(e) {
|
|
109
|
+
return _("write: ", e), this.mathField ? ((Array.isArray(e) ? e : [e]).forEach((e) => this.mathField.insert(e, { focus: !0 })), this.mathField.focus(), this.latex()) : "";
|
|
110
|
+
}
|
|
111
|
+
onKeyDown = (e) => {
|
|
112
|
+
e.key === "Enter" && e.preventDefault();
|
|
113
|
+
};
|
|
114
|
+
render() {
|
|
115
|
+
let { className: e, onFocus: t, onBlur: n, onClick: r } = this.props;
|
|
116
|
+
return /* @__PURE__ */ g(y, {
|
|
117
|
+
className: e,
|
|
118
|
+
onFocus: t,
|
|
119
|
+
onBlur: n,
|
|
120
|
+
onClick: r,
|
|
121
|
+
onKeyDown: this.onKeyDown,
|
|
122
|
+
ref: this.holderRef
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
//#endregion
|
|
127
|
+
export { b as Input, b as default };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
/**
|
|
4
|
+
* Static math. Drop-in replacement for @pie-lib/math-input's `mq.Static`.
|
|
5
|
+
*
|
|
6
|
+
* Two modes, chosen automatically:
|
|
7
|
+
*
|
|
8
|
+
* - **display** (no answer blocks in the latex): rendered with
|
|
9
|
+
* `convertLatexToMarkup`. No mathfield instance, so it is cheap enough for
|
|
10
|
+
* keypad labels - the old implementation created a full MathQuill
|
|
11
|
+
* StaticMath per button.
|
|
12
|
+
*
|
|
13
|
+
* - **interactive** (latex contains `\MathQuillMathField[..]{}` /
|
|
14
|
+
* `\placeholder[..]{}`): a read-only `<math-field>` whose placeholders stay
|
|
15
|
+
* editable. Sub-field values are surfaced through the prompts API, replacing
|
|
16
|
+
* MathQuill's `innerFields`.
|
|
17
|
+
*/
|
|
18
|
+
export default class Static extends React.Component {
|
|
19
|
+
static propTypes: {
|
|
20
|
+
latex: PropTypes.Validator<string>;
|
|
21
|
+
className: PropTypes.Requireable<string>;
|
|
22
|
+
onFocus: PropTypes.Requireable<(...args: any[]) => any>;
|
|
23
|
+
onBlur: PropTypes.Requireable<(...args: any[]) => any>;
|
|
24
|
+
language: PropTypes.Requireable<string>;
|
|
25
|
+
ariaDescribedBy: PropTypes.Requireable<string>;
|
|
26
|
+
getFieldName: PropTypes.Requireable<(...args: any[]) => any>;
|
|
27
|
+
onSubFieldChange: PropTypes.Requireable<(...args: any[]) => any>;
|
|
28
|
+
onSubFieldFocus: PropTypes.Requireable<(...args: any[]) => any>;
|
|
29
|
+
setInput: PropTypes.Requireable<(...args: any[]) => any>;
|
|
30
|
+
};
|
|
31
|
+
static defaultProps: {
|
|
32
|
+
getFieldName: () => void;
|
|
33
|
+
};
|
|
34
|
+
constructor(props: any);
|
|
35
|
+
componentDidMount(): void;
|
|
36
|
+
/** Render display markup, or mount a live field when the latex has answer blocks. */
|
|
37
|
+
mount(): Promise<void>;
|
|
38
|
+
componentDidUpdate(prevProps: any, prevState: any): void;
|
|
39
|
+
/**
|
|
40
|
+
* Put the caret at the start of the first answer block, without focusing.
|
|
41
|
+
*
|
|
42
|
+
* Setting `value` leaves the caret at the end, after every block. When the field
|
|
43
|
+
* then takes focus from Tab, MathLive looks for the next block after the caret,
|
|
44
|
+
* finds none, and moves focus on to the next element on the page: Tab skipped
|
|
45
|
+
* the field. With the caret in a block, MathLive leaves focus where it is.
|
|
46
|
+
*/
|
|
47
|
+
parkCaret(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Put answers from the latex prop into their prompts, leaving alone any the
|
|
50
|
+
* field reported itself: the prop is usually the parent echoing the last
|
|
51
|
+
* `onSubFieldChange`, and reassigning the field moves the caret out of the
|
|
52
|
+
* prompt, so the next keys typed would be lost.
|
|
53
|
+
*/
|
|
54
|
+
syncPrompts(): void;
|
|
55
|
+
componentWillUnmount(): void;
|
|
56
|
+
/** Remove the live field, if any, and invalidate any mount still awaiting the MathLive load. */
|
|
57
|
+
unmountField(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Off-screen aria-live region, ported from @pie-lib/math-input's Static.
|
|
60
|
+
*
|
|
61
|
+
* MathLive has its own accessibility layer, but it does not announce that
|
|
62
|
+
* typed input was converted into a math symbol, which screen-reader users
|
|
63
|
+
* relied on in the MathQuill implementation.
|
|
64
|
+
*/
|
|
65
|
+
createLiveRegion: () => void;
|
|
66
|
+
removeLiveRegion: () => void;
|
|
67
|
+
announce: (message: any) => void;
|
|
68
|
+
onKeyDown: (event: any) => void;
|
|
69
|
+
/**
|
|
70
|
+
* Announce when typed input became a math symbol. The MathQuill version
|
|
71
|
+
* inferred this by counting braces; here a prompt whose latex grew by more
|
|
72
|
+
* than the single character typed means a command was expanded.
|
|
73
|
+
*/
|
|
74
|
+
announceConversion: (next: any) => void;
|
|
75
|
+
/** Does this latex contain answer blocks? */
|
|
76
|
+
isInteractive(): boolean;
|
|
77
|
+
renderMarkup(): void;
|
|
78
|
+
/** MathQuill's `innerFields` equivalent, keyed by prompt id. */
|
|
79
|
+
values(): {};
|
|
80
|
+
/** The whole field's latex, in stored form. MathQuill's `mathField.latex()`. */
|
|
81
|
+
latex(): string;
|
|
82
|
+
/** Put the selection inside prompt `id`, unless it is there already, so edits land in it. */
|
|
83
|
+
selectPrompt(id: any): void;
|
|
84
|
+
/**
|
|
85
|
+
* A MathQuill-inner-field-like handle for a prompt.
|
|
86
|
+
*
|
|
87
|
+
* The old API handed callers a MathQuill field object: consumers called
|
|
88
|
+
* `field.latex()` on it, and drove it from a keypad with `write()`, `cmd()`,
|
|
89
|
+
* `keystroke()` and `clear()`. There is no equivalent object in MathLive -
|
|
90
|
+
* prompts are addressed by id - so this adapter exposes those parts. Edits go
|
|
91
|
+
* through the field, which reports them with its `input` event as typing does.
|
|
92
|
+
*/
|
|
93
|
+
promptHandle(id: any): {
|
|
94
|
+
id: any;
|
|
95
|
+
write: (value: any) => void;
|
|
96
|
+
cmd: (value: any) => void;
|
|
97
|
+
keystroke: (value: any) => void;
|
|
98
|
+
clear: () => void;
|
|
99
|
+
focus: () => void;
|
|
100
|
+
el: () => any;
|
|
101
|
+
latex: (value: any) => any;
|
|
102
|
+
};
|
|
103
|
+
/** All prompt handles, the analogue of `mathField.innerFields`. */
|
|
104
|
+
get innerFields(): any;
|
|
105
|
+
onPromptInput: () => void;
|
|
106
|
+
onPointerDown: () => void;
|
|
107
|
+
onPromptFocus: () => void;
|
|
108
|
+
onSelectionChange: () => void;
|
|
109
|
+
/**
|
|
110
|
+
* Tell the parent which answer block has the caret, through `setInput` and
|
|
111
|
+
* `onSubFieldFocus`, so keypad input goes to that block.
|
|
112
|
+
*
|
|
113
|
+
* @param {boolean} always report even when it is the block reported last
|
|
114
|
+
*/
|
|
115
|
+
reportFocusedPrompt(always: any): void;
|
|
116
|
+
/** Where the selection starts, which is the caret when nothing is selected. */
|
|
117
|
+
caretOffset(): any;
|
|
118
|
+
/** The id of the prompt whose range contains `position`, if any. */
|
|
119
|
+
promptContaining(position: any): any;
|
|
120
|
+
/**
|
|
121
|
+
* Put a blinking caret inside an answer block.
|
|
122
|
+
*
|
|
123
|
+
* MathLive only makes the caret visible while the field element carries the
|
|
124
|
+
* `ML__focused` class, and it adds that class during a *render*, gated on
|
|
125
|
+
* `isSelectionEditable && hasFocus()`. In a read-only field only prompt
|
|
126
|
+
* interiors are editable, so the two things both have to be true:
|
|
127
|
+
*
|
|
128
|
+
* - the selection must sit inside a prompt, and
|
|
129
|
+
* - a render must run afterwards.
|
|
130
|
+
*
|
|
131
|
+
* Assigning `selection` satisfies the first but not the second - it updates
|
|
132
|
+
* the model without re-rendering, so the class stays off and the caret span
|
|
133
|
+
* remains `visibility: hidden`. Executing any command does trigger the
|
|
134
|
+
* render, and `scrollIntoView` is the one with no other effect: it keeps the
|
|
135
|
+
* caret on screen, which the preceding `focus()` already does anyway.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} [id] prompt to focus; defaults to the first one
|
|
138
|
+
*/
|
|
139
|
+
focusPrompt(id: any): void;
|
|
140
|
+
focus(): void;
|
|
141
|
+
blur(): void;
|
|
142
|
+
render(): React.JSX.Element;
|
|
143
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { KEYSTROKES as e, fieldIds as t, fieldTemplate as n, fieldValues as r, fillFields as i, fromMathLive as a, keyToAction as o, toMathLive as s } from "../latex-bridge.js";
|
|
2
|
+
import { parallelStyles as c, placeholderStyles as l, rootIndexStyles as u } from "./common-styles.js";
|
|
3
|
+
import { fixLongDivisionWhenReady as d, trackLongDivision as f } from "../longdiv.js";
|
|
4
|
+
import { applyShadowStyles as p, createMathField as m, latexToMarkup as h, latexToMathMl as g, loadMathLive as _, trackPlaceholderCaret as v } from "../mathlive-instance.js";
|
|
5
|
+
import { describeMathField as y, labelMathField as b } from "./field-label.js";
|
|
6
|
+
import x from "react";
|
|
7
|
+
import S from "prop-types";
|
|
8
|
+
import { styled as C } from "@mui/material/styles";
|
|
9
|
+
import w from "debug";
|
|
10
|
+
import { jsx as T } from "react/jsx-runtime";
|
|
11
|
+
//#region src/mf/static.tsx
|
|
12
|
+
var E = w("pie-lib:math-input-mathlive:static"), D = "position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0", O = C("span")({
|
|
13
|
+
display: "inline-block",
|
|
14
|
+
...l,
|
|
15
|
+
...u,
|
|
16
|
+
...c,
|
|
17
|
+
"& math-field": {
|
|
18
|
+
display: "inline-block",
|
|
19
|
+
border: "none",
|
|
20
|
+
background: "transparent"
|
|
21
|
+
},
|
|
22
|
+
"& math-field::part(virtual-keyboard-toggle)": { display: "none" },
|
|
23
|
+
"& math-field::part(menu-toggle)": { display: "none" }
|
|
24
|
+
}), k = class extends x.Component {
|
|
25
|
+
static propTypes = {
|
|
26
|
+
latex: S.string.isRequired,
|
|
27
|
+
className: S.string,
|
|
28
|
+
onFocus: S.func,
|
|
29
|
+
onBlur: S.func,
|
|
30
|
+
language: S.string,
|
|
31
|
+
ariaDescribedBy: S.string,
|
|
32
|
+
getFieldName: S.func,
|
|
33
|
+
onSubFieldChange: S.func,
|
|
34
|
+
onSubFieldFocus: S.func,
|
|
35
|
+
setInput: S.func
|
|
36
|
+
};
|
|
37
|
+
static defaultProps = { getFieldName: () => {} };
|
|
38
|
+
constructor(e) {
|
|
39
|
+
super(e), this.holderRef = x.createRef(), this.state = { markup: "" }, this.promptValues = {};
|
|
40
|
+
}
|
|
41
|
+
componentDidMount() {
|
|
42
|
+
this.mount();
|
|
43
|
+
}
|
|
44
|
+
async mount() {
|
|
45
|
+
let e = this.mountGeneration = (this.mountGeneration || 0) + 1;
|
|
46
|
+
if (this.interactive = this.isInteractive(), !this.interactive) {
|
|
47
|
+
await _(), e === this.mountGeneration && this.renderMarkup();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let t = await _();
|
|
51
|
+
e === this.mountGeneration && t?.MathfieldElement && this.holderRef.current && !this.mathField && (this.mathField = m(t), b(this.mathField, this.props.language), y(this.mathField, this.props.ariaDescribedBy), this.mathField.readOnly = !0, this.mathField.mathVirtualKeyboardPolicy = "manual", this.mathField.mathModeSpace = "\\ ", this.mathField.smartSuperscript = !1, this.mathField.value = s(this.props.latex), p(this.mathField), this.untrackCaret = v(this.mathField), this.untrackLongDivision = f(this.mathField), this.mathField.addEventListener("input", this.onPromptInput), this.mathField.addEventListener("pointerdown", this.onPointerDown, !0), this.mathField.addEventListener("focusin", this.onPromptFocus), this.mathField.addEventListener("selection-change", this.onSelectionChange), this.mathField.addEventListener("keydown", this.onKeyDown), this.holderRef.current.replaceChildren(this.mathField), b(this.mathField, this.props.language), this.parkCaret(), this.createLiveRegion());
|
|
52
|
+
}
|
|
53
|
+
componentDidUpdate(e, t) {
|
|
54
|
+
!this.mathField && this.state.markup !== (t && t.markup) && d(this.holderRef.current), this.mathField && e.language !== this.props.language && b(this.mathField, this.props.language), this.mathField && e.ariaDescribedBy !== this.props.ariaDescribedBy && y(this.mathField, this.props.ariaDescribedBy), e.latex !== this.props.latex && (this.isInteractive() === this.interactive ? this.mathField ? n(this.props.latex) === n(e.latex) ? this.syncPrompts() : (this.mathField.value = s(this.props.latex), this.parkCaret()) : this.renderMarkup() : (this.unmountField(), this.setState({ markup: "" }), this.mount()));
|
|
55
|
+
}
|
|
56
|
+
parkCaret() {
|
|
57
|
+
if (!this.mathField || this.mathField.hasFocus?.()) return;
|
|
58
|
+
let [e] = this.mathField.getPrompts?.() || [], t = e && this.mathField.getPromptRange(e);
|
|
59
|
+
t && (this.mathField.selection = { ranges: [[t[0], t[0]]] });
|
|
60
|
+
}
|
|
61
|
+
syncPrompts() {
|
|
62
|
+
let e = r(this.props.latex);
|
|
63
|
+
Object.keys(e).forEach((t) => {
|
|
64
|
+
let n = e[t];
|
|
65
|
+
n !== this.promptValues[t] && n !== a(this.mathField.getPromptValue(t)) && (this.mathField.setPromptValue(t, s(n), {}), this.promptValues[t] = n);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
componentWillUnmount() {
|
|
69
|
+
this.unmountField(), this.removeLiveRegion();
|
|
70
|
+
}
|
|
71
|
+
unmountField() {
|
|
72
|
+
this.mountGeneration = (this.mountGeneration || 0) + 1, this.untrackCaret &&= (this.untrackCaret(), void 0), this.untrackLongDivision &&= (this.untrackLongDivision(), void 0), this.mathField &&= (this.mathField.removeEventListener("input", this.onPromptInput), this.mathField.removeEventListener("pointerdown", this.onPointerDown, !0), this.mathField.removeEventListener("focusin", this.onPromptFocus), this.mathField.removeEventListener("selection-change", this.onSelectionChange), this.mathField.removeEventListener("keydown", this.onKeyDown), this.mathField.remove(), void 0), this.promptValues = {}, this.focusedPrompt = void 0;
|
|
73
|
+
}
|
|
74
|
+
createLiveRegion = () => {
|
|
75
|
+
typeof document > "u" || this.liveRegion || (this.liveRegion = document.createElement("div"), Object.assign(this.liveRegion.style, {
|
|
76
|
+
position: "absolute",
|
|
77
|
+
width: "1px",
|
|
78
|
+
height: "1px",
|
|
79
|
+
marginTop: "-1px",
|
|
80
|
+
clip: "rect(1px, 1px, 1px, 1px)",
|
|
81
|
+
overflow: "hidden"
|
|
82
|
+
}), this.liveRegion.setAttribute("aria-live", "polite"), this.liveRegion.setAttribute("aria-atomic", "true"), document.body.appendChild(this.liveRegion));
|
|
83
|
+
};
|
|
84
|
+
removeLiveRegion = () => {
|
|
85
|
+
this.liveRegion && this.liveRegion.parentNode && this.liveRegion.parentNode.removeChild(this.liveRegion), this.liveRegion = void 0;
|
|
86
|
+
};
|
|
87
|
+
announce = (e) => {
|
|
88
|
+
this.liveRegion && (this.liveRegion.textContent = e, clearTimeout(this.announceTimeout), this.announceTimeout = setTimeout(() => {
|
|
89
|
+
this.liveRegion && (this.liveRegion.textContent = "");
|
|
90
|
+
}, 500));
|
|
91
|
+
};
|
|
92
|
+
onKeyDown = (e) => {
|
|
93
|
+
this.isDeleting = e?.key === "Backspace" || e?.key === "Delete";
|
|
94
|
+
};
|
|
95
|
+
announceConversion = (e) => {
|
|
96
|
+
this.isDeleting ? this.isDeleting = !1 : Object.keys(e).some((t) => {
|
|
97
|
+
let n = this.promptValues[t] || "", r = e[t] || "";
|
|
98
|
+
return r.length > n.length + 1 && /\\/.test(r.slice(n.length));
|
|
99
|
+
}) && this.announce("Converted to math symbol");
|
|
100
|
+
};
|
|
101
|
+
isInteractive() {
|
|
102
|
+
let e = this.props.latex || "";
|
|
103
|
+
return t(e).length > 0 || e.indexOf("\\placeholder") !== -1;
|
|
104
|
+
}
|
|
105
|
+
renderMarkup() {
|
|
106
|
+
let e = h(this.props.latex), t = e && g(this.props.latex), n = t ? `<span aria-hidden="true">${e}</span><span style="${D}">${t}</span>` : e;
|
|
107
|
+
n !== this.state.markup && this.setState({ markup: n });
|
|
108
|
+
}
|
|
109
|
+
values() {
|
|
110
|
+
if (!this.mathField) return {};
|
|
111
|
+
let e = {};
|
|
112
|
+
return (this.mathField.getPrompts() || []).forEach((t) => {
|
|
113
|
+
e[t] = a(this.mathField.getPromptValue(t));
|
|
114
|
+
}), e;
|
|
115
|
+
}
|
|
116
|
+
latex() {
|
|
117
|
+
return this.mathField ? i(this.props.latex, this.values()) : "";
|
|
118
|
+
}
|
|
119
|
+
selectPrompt(e) {
|
|
120
|
+
this.promptContaining(this.mathField.position) !== e && this.focusPrompt(e);
|
|
121
|
+
}
|
|
122
|
+
promptHandle(t) {
|
|
123
|
+
let n = (e) => {
|
|
124
|
+
this.mathField && (this.selectPrompt(t), e(this.mathField));
|
|
125
|
+
};
|
|
126
|
+
return {
|
|
127
|
+
id: t,
|
|
128
|
+
write: (e) => n((t) => (Array.isArray(e) ? e : [e]).forEach((e) => t.insert(e, { focus: !0 }))),
|
|
129
|
+
cmd: (e) => n((t) => {
|
|
130
|
+
let n = o({ command: e });
|
|
131
|
+
n && t.insert(n.value, { focus: !0 });
|
|
132
|
+
}),
|
|
133
|
+
keystroke: (t) => n((n) => {
|
|
134
|
+
try {
|
|
135
|
+
n.executeCommand(e[t] || t);
|
|
136
|
+
} catch (e) {
|
|
137
|
+
E("unknown keystroke/selector \"%s\": %s", t, e && e.message);
|
|
138
|
+
}
|
|
139
|
+
}),
|
|
140
|
+
clear: () => n((e) => {
|
|
141
|
+
e.setPromptValue(t, "", {}), this.onPromptInput();
|
|
142
|
+
}),
|
|
143
|
+
focus: () => {
|
|
144
|
+
this.mathField && (this.mathField.focus(), this.selectPrompt(t));
|
|
145
|
+
},
|
|
146
|
+
el: () => this.mathField,
|
|
147
|
+
latex: (e) => this.mathField ? e === void 0 ? a(this.mathField.getPromptValue(t)) : (this.mathField.setPromptValue(t, s(e), {}), e) : ""
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
get innerFields() {
|
|
151
|
+
return this.mathField ? (this.mathField.getPrompts() || []).map((e) => this.promptHandle(e)) : [];
|
|
152
|
+
}
|
|
153
|
+
onPromptInput = () => {
|
|
154
|
+
let { onSubFieldChange: e, getFieldName: t } = this.props;
|
|
155
|
+
if (!this.mathField) return;
|
|
156
|
+
let n = this.values();
|
|
157
|
+
if (this.announceConversion(n), !e) {
|
|
158
|
+
this.promptValues = n;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
let r = this.innerFields;
|
|
162
|
+
Object.keys(n).forEach((i) => {
|
|
163
|
+
if (n[i] === this.promptValues[i]) return;
|
|
164
|
+
let a = t(this.promptHandle(i), r) || i;
|
|
165
|
+
e(a, n[i]);
|
|
166
|
+
}), this.promptValues = n;
|
|
167
|
+
};
|
|
168
|
+
onPointerDown = () => {
|
|
169
|
+
this.pointerFocus = !0;
|
|
170
|
+
};
|
|
171
|
+
onPromptFocus = () => {
|
|
172
|
+
let e = this.pointerFocus;
|
|
173
|
+
this.pointerFocus = !1, this.mathField && (!e && !this.promptContaining(this.caretOffset()) && this.focusPrompt(), this.reportFocusedPrompt(!0));
|
|
174
|
+
};
|
|
175
|
+
onSelectionChange = () => {
|
|
176
|
+
this.mathField?.hasFocus?.() && this.reportFocusedPrompt(!1);
|
|
177
|
+
};
|
|
178
|
+
reportFocusedPrompt(e) {
|
|
179
|
+
let { onSubFieldFocus: t, getFieldName: n } = this.props;
|
|
180
|
+
if (this.mathField && t) try {
|
|
181
|
+
let r = this.promptContaining(this.caretOffset());
|
|
182
|
+
if (!r || !e && r === this.focusedPrompt) return;
|
|
183
|
+
this.focusedPrompt = r;
|
|
184
|
+
let i = this.promptHandle(r), a = n(i, this.innerFields) || r;
|
|
185
|
+
this.props.setInput && this.props.setInput(i), t(a, i);
|
|
186
|
+
} catch (e) {
|
|
187
|
+
E("error resolving focused prompt: %s", e.message);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
caretOffset() {
|
|
191
|
+
let e = this.mathField?.selection;
|
|
192
|
+
return e?.ranges?.length ? e.ranges[0][0] : this.mathField?.position;
|
|
193
|
+
}
|
|
194
|
+
promptContaining(e) {
|
|
195
|
+
if (this.mathField && typeof e == "number") return (this.mathField.getPrompts() || []).find((t) => {
|
|
196
|
+
let n = this.mathField.getPromptRange(t);
|
|
197
|
+
return n && e >= n[0] && e <= n[1];
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
focusPrompt(e) {
|
|
201
|
+
if (!this.mathField) return;
|
|
202
|
+
let t = this.mathField.getPrompts() || [], n = e && t.indexOf(e) !== -1 ? e : t[0];
|
|
203
|
+
if (!n) return;
|
|
204
|
+
let r = this.mathField.getPromptRange(n);
|
|
205
|
+
r && (this.mathField.selection = { ranges: [[r[0], r[0]]] }, typeof this.mathField.executeCommand == "function" && this.mathField.executeCommand("scrollIntoView"));
|
|
206
|
+
}
|
|
207
|
+
focus() {
|
|
208
|
+
this.mathField && (this.mathField.focus(), this.promptContaining(this.mathField.position) || this.focusPrompt());
|
|
209
|
+
}
|
|
210
|
+
blur() {
|
|
211
|
+
this.mathField && this.mathField.blur();
|
|
212
|
+
}
|
|
213
|
+
render() {
|
|
214
|
+
let { className: e, onFocus: t, onBlur: n } = this.props, { markup: r } = this.state;
|
|
215
|
+
return this.mathField || this.isInteractive() ? /* @__PURE__ */ T(O, {
|
|
216
|
+
className: e,
|
|
217
|
+
onFocus: t,
|
|
218
|
+
onBlur: n,
|
|
219
|
+
ref: this.holderRef
|
|
220
|
+
}) : /* @__PURE__ */ T(O, {
|
|
221
|
+
className: e,
|
|
222
|
+
onFocus: t,
|
|
223
|
+
onBlur: n,
|
|
224
|
+
ref: this.holderRef,
|
|
225
|
+
dangerouslySetInnerHTML: { __html: r }
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
//#endregion
|
|
230
|
+
export { k as default };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widen a selection so it covers whole atoms of a single parent.
|
|
3
|
+
*
|
|
4
|
+
* MathLive extends a selection over *flat offsets*, so Shift+Arrow walks into
|
|
5
|
+
* a fraction instead of over it: from before `2x` in `5x^2+2x+\frac{\pi}{2}-4`,
|
|
6
|
+
* five presses select `2x+` plus the `\pi` of the numerator, and copying gives
|
|
7
|
+
* `2x+\pi`. MathQuill treated a fraction (root, superscript...) as one unit,
|
|
8
|
+
* which is what authors expect.
|
|
9
|
+
*
|
|
10
|
+
* The tree is recovered from MathLive's public `getElementInfo(offset)`, where
|
|
11
|
+
* offset `i` describes the atom ending at caret position `i`:
|
|
12
|
+
*
|
|
13
|
+
* - a composite atom (fraction, root, script) owns the offset right *after*
|
|
14
|
+
* its children; the children are one level deeper;
|
|
15
|
+
* - each branch (numerator, denominator, radicand) opens with an empty-latex
|
|
16
|
+
* "start" atom.
|
|
17
|
+
*
|
|
18
|
+
* The rule: find the shallowest depth the selection touches, counting the caret
|
|
19
|
+
* it starts from. If the range crosses into a sibling branch at that depth, the
|
|
20
|
+
* real common parent is one level up. Then push both ends out of anything
|
|
21
|
+
* deeper. A script atom (`^2`) is kept with its base, since MathLive stores
|
|
22
|
+
* `x^2` as `x` followed by a separate `^2` atom.
|
|
23
|
+
*
|
|
24
|
+
* Pure, so it can be tested without a browser.
|
|
25
|
+
*
|
|
26
|
+
* @param {number} start
|
|
27
|
+
* @param {number} end
|
|
28
|
+
* @param {function(number): {depth?: number, latex?: string}} info
|
|
29
|
+
* @param {number} lastOffset
|
|
30
|
+
* @returns {[number, number]} the widened range, start <= end
|
|
31
|
+
*/
|
|
32
|
+
export declare const expandRange: (start: any, end: any, info: any, lastOffset: any) => any[];
|
|
33
|
+
/**
|
|
34
|
+
* Keep a mathfield's selection snapped to whole atoms (see {@link expandRange}).
|
|
35
|
+
*
|
|
36
|
+
* This fixes both what the user sees highlighted and what copy/cut put on the
|
|
37
|
+
* clipboard, since both come from the selection. The selection direction is
|
|
38
|
+
* preserved, so further Shift+Arrow presses keep extending the same end.
|
|
39
|
+
*
|
|
40
|
+
* @param {HTMLElement} mathField a MathLive `<math-field>`
|
|
41
|
+
* @returns {function|undefined} teardown, to call on unmount
|
|
42
|
+
*/
|
|
43
|
+
export declare const trackWholeAtomSelection: (mathField: any) => (() => any) | undefined;
|