@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.
Files changed (202) hide show
  1. package/README.md +84 -109
  2. package/dist/_virtual/_rolldown/runtime.js +11 -0
  3. package/dist/horizontal-keypad.d.ts +22 -0
  4. package/dist/horizontal-keypad.js +54 -0
  5. package/dist/index.d.ts +20 -0
  6. package/dist/index.js +12 -0
  7. package/dist/keypad/index.d.ts +40 -0
  8. package/dist/keypad/index.js +245 -0
  9. package/dist/keypad/keys-layout.d.ts +7 -0
  10. package/dist/keypad/keys-layout.js +5 -0
  11. package/dist/keys/basic-operators.d.ts +5 -0
  12. package/dist/keys/basic-operators.js +30 -0
  13. package/dist/keys/chars.d.ts +5 -0
  14. package/dist/keys/comparison.d.ts +4 -0
  15. package/dist/keys/comparison.js +32 -0
  16. package/dist/keys/constants.d.ts +4 -0
  17. package/dist/keys/constants.js +35 -0
  18. package/dist/keys/digits.d.ts +15 -0
  19. package/dist/keys/digits.js +34 -0
  20. package/dist/keys/edit.d.ts +6 -0
  21. package/dist/keys/edit.js +9 -0
  22. package/dist/keys/exponent.d.ts +4 -0
  23. package/dist/keys/exponent.js +28 -0
  24. package/dist/keys/fractions.d.ts +3 -0
  25. package/dist/keys/fractions.js +27 -0
  26. package/dist/keys/geometry.d.ts +23 -0
  27. package/dist/keys/geometry.js +127 -0
  28. package/dist/keys/grades.d.ts +9 -0
  29. package/dist/keys/grades.js +414 -0
  30. package/dist/keys/index.d.ts +6 -0
  31. package/dist/keys/index.js +50 -0
  32. package/dist/keys/log.d.ts +3 -0
  33. package/dist/keys/log.js +25 -0
  34. package/dist/keys/logic.d.ts +2 -0
  35. package/dist/keys/logic.js +13 -0
  36. package/dist/keys/matrices.d.ts +2 -0
  37. package/dist/keys/matrices.js +17 -0
  38. package/dist/keys/misc.d.ts +10 -0
  39. package/dist/keys/misc.js +60 -0
  40. package/dist/keys/navigation.d.ts +2 -0
  41. package/dist/keys/navigation.js +13 -0
  42. package/dist/keys/operators.d.ts +1 -0
  43. package/dist/keys/operators.js +11 -0
  44. package/dist/keys/statistics.d.ts +5 -0
  45. package/dist/keys/statistics.js +38 -0
  46. package/dist/keys/sub-sup.d.ts +2 -0
  47. package/dist/keys/sub-sup.js +17 -0
  48. package/dist/keys/trigonometry.d.ts +6 -0
  49. package/dist/keys/trigonometry.js +43 -0
  50. package/dist/keys/utils.d.ts +5 -0
  51. package/dist/keys/utils.js +24 -0
  52. package/dist/keys/vars.d.ts +3 -0
  53. package/dist/keys/vars.js +22 -0
  54. package/dist/latex-bridge.d.ts +197 -0
  55. package/dist/latex-bridge.js +210 -0
  56. package/dist/longdiv.d.ts +24 -0
  57. package/dist/longdiv.js +43 -0
  58. package/dist/math-input.d.ts +26 -0
  59. package/dist/math-input.js +74 -0
  60. package/dist/mathlive-instance.d.ts +221 -0
  61. package/dist/mathlive-instance.js +159 -0
  62. package/dist/mf/common-styles.d.ts +594 -0
  63. package/dist/mf/common-styles.js +80 -0
  64. package/dist/mf/field-label.d.ts +16 -0
  65. package/dist/mf/field-label.js +13 -0
  66. package/dist/mf/index.d.ts +4 -0
  67. package/dist/mf/index.js +21 -0
  68. package/dist/mf/input.d.ts +94 -0
  69. package/dist/mf/input.js +127 -0
  70. package/dist/mf/static.d.ts +143 -0
  71. package/dist/mf/static.js +230 -0
  72. package/dist/selection.d.ts +43 -0
  73. package/dist/selection.js +39 -0
  74. package/package.json +32 -18
  75. package/lib/__tests__/composites.test.js +0 -255
  76. package/lib/__tests__/drop-in-compat.test.js +0 -133
  77. package/lib/__tests__/embedded-fonts.test.js +0 -121
  78. package/lib/__tests__/index.test.js +0 -118
  79. package/lib/__tests__/input-imperative.test.js +0 -155
  80. package/lib/__tests__/input-selection.test.js +0 -103
  81. package/lib/__tests__/keypad-label.test.js +0 -231
  82. package/lib/__tests__/keypad-render.test.js +0 -206
  83. package/lib/__tests__/latex-bridge.test.js +0 -386
  84. package/lib/__tests__/mathlive-instance.test.js +0 -419
  85. package/lib/__tests__/mount-race.test.js +0 -218
  86. package/lib/__tests__/selection.test.js +0 -195
  87. package/lib/__tests__/static-prompts.test.js +0 -405
  88. package/lib/__tests__/tmp-markup.test.js +0 -26
  89. package/lib/horizontal-keypad.js +0 -101
  90. package/lib/horizontal-keypad.js.map +0 -1
  91. package/lib/index.js +0 -143
  92. package/lib/index.js.map +0 -1
  93. package/lib/keypad/index.js +0 -431
  94. package/lib/keypad/index.js.map +0 -1
  95. package/lib/keypad/keys-layout.js +0 -22
  96. package/lib/keypad/keys-layout.js.map +0 -1
  97. package/lib/keys/basic-operators.js +0 -33
  98. package/lib/keys/basic-operators.js.map +0 -1
  99. package/lib/keys/chars.js +0 -12
  100. package/lib/keys/chars.js.map +0 -1
  101. package/lib/keys/comparison.js +0 -39
  102. package/lib/keys/comparison.js.map +0 -1
  103. package/lib/keys/constants.js +0 -37
  104. package/lib/keys/constants.js.map +0 -1
  105. package/lib/keys/digits.js +0 -46
  106. package/lib/keys/digits.js.map +0 -1
  107. package/lib/keys/edit.js +0 -14
  108. package/lib/keys/edit.js.map +0 -1
  109. package/lib/keys/exponent.js +0 -30
  110. package/lib/keys/exponent.js.map +0 -1
  111. package/lib/keys/fractions.js +0 -29
  112. package/lib/keys/fractions.js.map +0 -1
  113. package/lib/keys/geometry.js +0 -143
  114. package/lib/keys/geometry.js.map +0 -1
  115. package/lib/keys/grades.js +0 -259
  116. package/lib/keys/grades.js.map +0 -1
  117. package/lib/keys/index.js +0 -35
  118. package/lib/keys/index.js.map +0 -1
  119. package/lib/keys/log.js +0 -27
  120. package/lib/keys/log.js.map +0 -1
  121. package/lib/keys/logic.js +0 -19
  122. package/lib/keys/logic.js.map +0 -1
  123. package/lib/keys/matrices.js +0 -19
  124. package/lib/keys/matrices.js.map +0 -1
  125. package/lib/keys/misc.js +0 -69
  126. package/lib/keys/misc.js.map +0 -1
  127. package/lib/keys/navigation.js +0 -20
  128. package/lib/keys/navigation.js.map +0 -1
  129. package/lib/keys/operators.js +0 -15
  130. package/lib/keys/operators.js.map +0 -1
  131. package/lib/keys/statistics.js +0 -40
  132. package/lib/keys/statistics.js.map +0 -1
  133. package/lib/keys/sub-sup.js +0 -19
  134. package/lib/keys/sub-sup.js.map +0 -1
  135. package/lib/keys/trigonometry.js +0 -45
  136. package/lib/keys/trigonometry.js.map +0 -1
  137. package/lib/keys/utils.js +0 -87
  138. package/lib/keys/utils.js.map +0 -1
  139. package/lib/keys/vars.js +0 -24
  140. package/lib/keys/vars.js.map +0 -1
  141. package/lib/latex-bridge.js +0 -445
  142. package/lib/latex-bridge.js.map +0 -1
  143. package/lib/math-input.js +0 -143
  144. package/lib/math-input.js.map +0 -1
  145. package/lib/mathlive-instance.js +0 -585
  146. package/lib/mathlive-instance.js.map +0 -1
  147. package/lib/mf/common-styles.js +0 -203
  148. package/lib/mf/common-styles.js.map +0 -1
  149. package/lib/mf/index.js +0 -84
  150. package/lib/mf/index.js.map +0 -1
  151. package/lib/mf/input.js +0 -372
  152. package/lib/mf/input.js.map +0 -1
  153. package/lib/mf/static.js +0 -500
  154. package/lib/mf/static.js.map +0 -1
  155. package/lib/selection.js +0 -148
  156. package/lib/selection.js.map +0 -1
  157. package/src/__tests__/composites.test.jsx +0 -220
  158. package/src/__tests__/drop-in-compat.test.jsx +0 -112
  159. package/src/__tests__/index.test.jsx +0 -109
  160. package/src/__tests__/input-imperative.test.jsx +0 -144
  161. package/src/__tests__/input-selection.test.jsx +0 -64
  162. package/src/__tests__/keypad-label.test.jsx +0 -283
  163. package/src/__tests__/keypad-render.test.jsx +0 -123
  164. package/src/__tests__/latex-bridge.test.js +0 -359
  165. package/src/__tests__/mathlive-instance.test.js +0 -418
  166. package/src/__tests__/mount-race.test.jsx +0 -142
  167. package/src/__tests__/selection.test.js +0 -212
  168. package/src/__tests__/static-prompts.test.jsx +0 -364
  169. package/src/horizontal-keypad.jsx +0 -73
  170. package/src/index.jsx +0 -63
  171. package/src/keypad/index.jsx +0 -386
  172. package/src/keypad/keys-layout.js +0 -16
  173. package/src/keys/basic-operators.js +0 -32
  174. package/src/keys/chars.js +0 -5
  175. package/src/keys/comparison.js +0 -28
  176. package/src/keys/constants.js +0 -35
  177. package/src/keys/digits.js +0 -40
  178. package/src/keys/edit.js +0 -3
  179. package/src/keys/exponent.js +0 -28
  180. package/src/keys/fractions.js +0 -26
  181. package/src/keys/geometry.js +0 -149
  182. package/src/keys/grades.js +0 -367
  183. package/src/keys/index.js +0 -20
  184. package/src/keys/log.js +0 -22
  185. package/src/keys/logic.js +0 -15
  186. package/src/keys/matrices.js +0 -15
  187. package/src/keys/misc.js +0 -71
  188. package/src/keys/navigation.js +0 -8
  189. package/src/keys/operators.js +0 -10
  190. package/src/keys/statistics.js +0 -38
  191. package/src/keys/sub-sup.js +0 -15
  192. package/src/keys/trigonometry.js +0 -15
  193. package/src/keys/utils.js +0 -66
  194. package/src/keys/vars.js +0 -19
  195. package/src/latex-bridge.js +0 -449
  196. package/src/math-input.jsx +0 -115
  197. package/src/mathlive-instance.js +0 -582
  198. package/src/mf/common-styles.js +0 -210
  199. package/src/mf/index.js +0 -30
  200. package/src/mf/input.jsx +0 -328
  201. package/src/mf/static.jsx +0 -479
  202. 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, };
@@ -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;
@@ -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;