@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
@@ -1,210 +0,0 @@
1
- /**
2
- * Shared MathLive styling.
3
- *
4
- * Replaces @pie-lib/math-input's `common-mq-styles.js`. That file was built
5
- * around MathQuill's `.mq-*` class names, none of which exist in MathLive
6
- * output, so the selectors here target MathLive's own structure instead.
7
- *
8
- * The four named groups are kept because consumers destructure them:
9
- *
10
- * const { commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, supsubStyles }
11
- * = mq.CommonMqStyles; // math-toolbar/src/editor-and-pad.jsx, math-preview.jsx
12
- *
13
- * Most are intentionally near-empty: MathLive sizes scripts, radicals and
14
- * fences correctly on its own, so the MathQuill-era corrections are not needed.
15
- * They stay as documented extension points rather than being deleted, so the
16
- * destructuring above keeps working. The exception is the radical index, which
17
- * MathLive sizes to TeX metrics that read too small here - see
18
- * `rootIndexStyles`.
19
- */
20
-
21
- /**
22
- * Font styling. MathQuill needed explicit MathJax font families to match the
23
- * static renderer; MathLive ships the KaTeX fonts it renders with, so this only
24
- * smooths rendering and lets the host override the family.
25
- */
26
- export const commonMqFontStyles = {
27
- '-webkit-font-smoothing': 'antialiased',
28
- '& math-field': {
29
- fontFamily: 'inherit',
30
- },
31
- };
32
-
33
- /**
34
- * Long division. The MathQuill fork drew this with nested `.mq-longdiv-*`
35
- * elements that needed manual offsets; here it comes from the `\longdiv` macro
36
- * (see `PIE_MACROS`), tagged with `data-pie-macro="longdiv"`.
37
- */
38
- export const longdivStyles = {
39
- '& [data-pie-macro="longdiv"]': {
40
- display: 'inline-flex',
41
- },
42
- };
43
-
44
- /**
45
- * How the index of a radical is sized.
46
- *
47
- * MathLive follows TeX and sets the index of `\sqrt[n]{x}` in scriptscriptstyle,
48
- * which it emits as an inline `font-size: 50%` on the span wrapping the index's
49
- * glyphs. At authoring sizes that leaves the index - on the nth-root key, and in
50
- * any radical the author types - too small to read next to the radicand, so it is
51
- * scaled up to 80% - 1.6x what MathLive asks for.
52
- *
53
- * Only that innermost span is resized. `.ML__sqrt-index` itself keeps its font
54
- * size on purpose: the vlist inside it tucks the index into the radical's crook
55
- * with em-based `top`/`height` offsets, and scaling those lifts the index clear
56
- * of the radical instead of just enlarging it.
57
- *
58
- * The child chain is spelled out so that nothing nested deeper inside the index
59
- * (a fraction's numerator, another radical) is caught by the same rule, and
60
- * `!important` is required because the 50% is an INLINE style.
61
- */
62
- const ROOT_INDEX_SELECTOR = '.ML__sqrt-index > .ML__vlist-t > .ML__vlist-r > .ML__vlist > span > [style*="font-size"]';
63
- const ROOT_INDEX_FONT_SIZE = '80%';
64
-
65
- export const rootIndexStyles = {
66
- [`& ${ROOT_INDEX_SELECTOR}`]: {
67
- fontSize: `${ROOT_INDEX_FONT_SIZE} !important`,
68
- },
69
- };
70
-
71
- /**
72
- * The same rule as a CSS string, for a live mathfield's shadow root - see
73
- * `SHADOW_CSS` in mathlive-instance.js. Static markup is styled by
74
- * {@link rootIndexStyles}.
75
- */
76
- export const ROOT_INDEX_CSS = `${ROOT_INDEX_SELECTOR}{font-size:${ROOT_INDEX_FONT_SIZE} !important}`;
77
-
78
- /**
79
- * Size of the parallel sign (`\parallel`, tagged `data-pie-macro="parallel"` by
80
- * `PIE_MACROS`). The legacy editor enlarged it (`updateSpans` set 32px) because
81
- * the bars read too small next to the letters of `AB ∥ CD`; MathLive draws it at
82
- * the surrounding size, so it is scaled up here. Not applied to keypad labels.
83
- */
84
- const PARALLEL_SELECTOR = '[data-pie-macro="parallel"]';
85
- const PARALLEL_FONT_SIZE = '1.4em';
86
-
87
- export const parallelStyles = {
88
- [`& ${PARALLEL_SELECTOR}`]: {
89
- fontSize: PARALLEL_FONT_SIZE,
90
- },
91
- };
92
-
93
- /** The same rule as a CSS string, for a live mathfield's shadow root. */
94
- export const PARALLEL_CSS = `${PARALLEL_SELECTOR}{font-size:${PARALLEL_FONT_SIZE}}`;
95
-
96
- /**
97
- * Superscript/subscript sizing. MathLive follows TeX metrics for scripts, so the
98
- * MathQuill-era corrections are gone; the radical index is the one place where a
99
- * TeX-correct size reads too small in the authoring UI.
100
- */
101
- export const supsubStyles = {
102
- ...rootIndexStyles,
103
- ...parallelStyles,
104
- };
105
-
106
- /** Empty placeholder boxes (answer blocks / open slots). */
107
- export const placeholderStyles = {
108
- '& .ML__placeholder': {
109
- borderBottom: '1px solid currentColor',
110
- minWidth: '1em',
111
- },
112
- // Stand-in glyph for an empty argument slot in STATIC math (see
113
- // `withVisibleEmptySlots`). Muted so it reads as "a slot goes here" rather
114
- // than as part of the symbol, matching how MathQuill shaded `.mq-empty`.
115
- '& [data-pie-empty]': {
116
- opacity: 0.5,
117
- },
118
- // Stretchy accents (\overarc, \overleftrightarrow, \overrightarrow) render an
119
- // <svg width="100%" preserveAspectRatio="none"> inside a `.ML__stretchy`. That
120
- // span is absolutely positioned, so its immediate wrapper computes to 0px and
121
- // the width has to resolve against a *positioned* ancestor. Pin that to
122
- // `.ML__base`, whose width already equals the accent's content (measured:
123
- // 9.85px for a 0.56em slot), so the arc spans exactly its content.
124
- //
125
- // Do NOT write a bare `& svg` rule instead: MathLive's own rule is
126
- // descendant-scoped (`.ML__latex .ML__stretchy svg`), and a global one
127
- // re-parents every svg in the subtree.
128
- '& .ML__base': {
129
- position: 'relative',
130
- },
131
- '& .ML__stretchy': {
132
- position: 'absolute',
133
- left: 0,
134
- width: '100%',
135
- },
136
- // MathLive centres an accent by shifting it right half the content width -
137
- // `margin-left: 0.28em` for a 0.56em slot - which assumes a glyph with its own
138
- // side bearings. Over a synthetic empty slot it just pushes the arc right.
139
- //
140
- // `!important` is required: MathLive writes this as an INLINE style
141
- // (`style="top:-3.4em;margin-left:0.28em"`), which a class cannot override.
142
- //
143
- // It also fixes the width. `.ML__center` is the stretchy's containing block
144
- // (MathLive gives `.ML__vlist > span` position:relative), and its width is the
145
- // base minus that margin - measured 9.85px - 4.93px = 4.93px, exactly half,
146
- // which is why the arc came out half-width AND offset right.
147
- //
148
- // Scoped with `:has(.ML__stretchy)`: only stretchy accents are affected.
149
- // A single-glyph accent (`\hat{x}`, `\vec{x}`) genuinely needs its centring
150
- // offset, and must keep it.
151
- '& .ML__center:has(.ML__stretchy)': {
152
- marginLeft: '0 !important',
153
- },
154
- };
155
-
156
- /**
157
- * Styling for the on-screen keyboard and any container rendering math labels.
158
- * Also hides MathLive's own affordances, since pie supplies its own keypad.
159
- */
160
- export const commonMqKeyboardStyles = {
161
- ...commonMqFontStyles,
162
- ...longdivStyles,
163
- ...rootIndexStyles,
164
- ...placeholderStyles,
165
- touchAction: 'manipulation',
166
- '& math-field': {
167
- fontSize: 'inherit',
168
- outline: 'none',
169
- },
170
- '& math-field::part(virtual-keyboard-toggle)': {
171
- display: 'none',
172
- },
173
- '& math-field::part(menu-toggle)': {
174
- display: 'none',
175
- },
176
- };
177
-
178
- /** Everything combined - the common case for a container of math. */
179
- export const commonMathLiveStyles = {
180
- ...commonMqFontStyles,
181
- ...longdivStyles,
182
- ...supsubStyles,
183
- ...placeholderStyles,
184
- '& math-field': {
185
- fontSize: 'inherit',
186
- outline: 'none',
187
- },
188
- '& math-field::part(virtual-keyboard-toggle)': {
189
- display: 'none',
190
- },
191
- '& math-field::part(menu-toggle)': {
192
- display: 'none',
193
- },
194
- };
195
-
196
- export const commonKeyboardStyles = commonMqKeyboardStyles;
197
-
198
- /**
199
- * Default export mirrors @pie-lib/math-input's `CommonMqStyles` object so
200
- * existing destructuring keeps working.
201
- */
202
- export default {
203
- commonMqFontStyles,
204
- longdivStyles,
205
- rootIndexStyles,
206
- supsubStyles,
207
- commonMqKeyboardStyles,
208
- placeholderStyles,
209
- commonMathLiveStyles,
210
- };
package/src/mf/index.js DELETED
@@ -1,30 +0,0 @@
1
- import Input from './input';
2
- import Static from './static';
3
- import CommonMqStyles, {
4
- commonMathLiveStyles,
5
- commonKeyboardStyles,
6
- commonMqFontStyles,
7
- commonMqKeyboardStyles,
8
- longdivStyles,
9
- rootIndexStyles,
10
- parallelStyles,
11
- supsubStyles,
12
- placeholderStyles,
13
- } from './common-styles';
14
-
15
- export {
16
- Input,
17
- Static,
18
- // Same object shape as @pie-lib/math-input's `mq.CommonMqStyles`, so
19
- // `const { commonMqFontStyles, ... } = mq.CommonMqStyles` keeps working.
20
- CommonMqStyles,
21
- commonMathLiveStyles,
22
- commonKeyboardStyles,
23
- commonMqFontStyles,
24
- commonMqKeyboardStyles,
25
- longdivStyles,
26
- rootIndexStyles,
27
- parallelStyles,
28
- supsubStyles,
29
- placeholderStyles,
30
- };
package/src/mf/input.jsx DELETED
@@ -1,328 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import { styled } from '@mui/material/styles';
4
- import debug from 'debug';
5
- import {
6
- loadMathLive,
7
- getMacros,
8
- MATH_MODE_SPACE,
9
- applyShadowStyles,
10
- trackPlaceholderCaret,
11
- } from '../mathlive-instance';
12
- import { toMathLive, fromMathLive, keyToAction, KEYSTROKES } from '../latex-bridge';
13
- import { trackWholeAtomSelection } from '../selection';
14
-
15
- const log = debug('pie-lib:math-input-mathlive:input');
16
-
17
- const Holder = styled('span')({
18
- display: 'inline-block',
19
- '& math-field': {
20
- display: 'block',
21
- width: '100%',
22
- },
23
- // MathLive ships its own virtual keyboard toggle; pie supplies its own keypad.
24
- '& math-field::part(virtual-keyboard-toggle)': {
25
- display: 'none',
26
- },
27
- '& math-field::part(menu-toggle)': {
28
- display: 'none',
29
- },
30
- });
31
-
32
- /**
33
- * Editable math field. Drop-in replacement for @pie-lib/math-input's `mq.Input`.
34
- *
35
- * Keeps the same imperative surface used by MathInput's keypad
36
- * (`write`, `command`, `keystroke`, `clear`, `focus`, `blur`) so callers do not
37
- * change, and the same `latex` / `onChange` props.
38
- */
39
- export class Input extends React.Component {
40
- static propTypes = {
41
- className: PropTypes.string,
42
- latex: PropTypes.string,
43
- onChange: PropTypes.func,
44
- onClick: PropTypes.func,
45
- onFocus: PropTypes.func,
46
- onBlur: PropTypes.func,
47
- readOnly: PropTypes.bool,
48
- innerRef: PropTypes.func,
49
- };
50
-
51
- constructor(props) {
52
- super(props);
53
- this.holderRef = React.createRef();
54
- // Tracks the last latex we emitted, so prop echoes don't reset the cursor.
55
- this.lastEmitted = undefined;
56
- }
57
-
58
- async componentDidMount() {
59
- // MathLive loads asynchronously, so this method resumes after an await and
60
- // has to know whether it is still the current mount. React StrictMode calls
61
- // mount -> unmount -> mount on the SAME instance in dev, so a boolean
62
- // "unmounted" flag would latch and block the remount from ever creating a
63
- // field. A generation counter identifies the live mount instead: only the
64
- // newest one proceeds, and a real unmount invalidates all pending ones.
65
- const generation = (this.mountGeneration = (this.mountGeneration || 0) + 1);
66
- const ml = await loadMathLive();
67
-
68
- if (generation !== this.mountGeneration || !ml || !this.holderRef.current || this.mathField) {
69
- return;
70
- }
71
-
72
- this.mathField = new ml.MathfieldElement({ macros: getMacros() });
73
- this.mathField.value = toMathLive(this.props.latex || '');
74
-
75
- if (this.props.readOnly) {
76
- this.mathField.readOnly = true;
77
- }
78
-
79
- // pie drives input through its own keypad, so suppress MathLive's.
80
- this.mathField.mathVirtualKeyboardPolicy = 'manual';
81
- // Without this the spacebar does nothing: MathLive's mathModeSpace
82
- // defaults to an empty string.
83
- this.mathField.mathModeSpace = MATH_MODE_SPACE;
84
- // After the exponent key the cursor must stay in the exponent until it is moved
85
- // MathLive's `smartSuperscript` (on by
86
- // default) jumps out of an empty superscript after a single digit, which breaks
87
- // typing x^23 or 10^6 and is inconsistent with non-digit exponents.
88
- this.mathField.smartSuperscript = false;
89
-
90
- // The mathfield renders in shadow DOM, so page CSS cannot reach it - the
91
- // stretchy-accent fix has to be injected there directly.
92
- applyShadowStyles(this.mathField);
93
-
94
- // A selected `\placeholder{}` gets no MathLive caret; draw one.
95
- this.untrackCaret = trackPlaceholderCaret(this.mathField);
96
-
97
- // Shift+Arrow would otherwise select half a fraction; snap to whole atoms.
98
- this.untrackSelection = trackWholeAtomSelection(this.mathField);
99
-
100
- this.mathField.addEventListener('input', this.onInputEdit);
101
-
102
- // Belt and braces: drop anything a previous mount may have left behind.
103
- this.holderRef.current.replaceChildren(this.mathField);
104
-
105
- if (this.props.innerRef) {
106
- this.props.innerRef(this);
107
- }
108
- }
109
-
110
- componentDidUpdate(prevProps) {
111
- if (!this.mathField) {
112
- return;
113
- }
114
-
115
- const { latex, readOnly } = this.props;
116
-
117
- if (readOnly !== prevProps.readOnly) {
118
- this.mathField.readOnly = !!readOnly;
119
- }
120
-
121
- // Only push the prop back into the field when it genuinely differs from
122
- // what the field already holds. This is the analogue of the old
123
- // shouldComponentUpdate latex-equality guard and prevents cursor thrash.
124
- if (latex !== undefined && latex !== null && latex !== this.lastEmitted) {
125
- const next = toMathLive(latex);
126
-
127
- if (next !== this.mathField.value) {
128
- this.mathField.value = next;
129
- }
130
- }
131
- }
132
-
133
- componentWillUnmount() {
134
- // Invalidate any mount still awaiting the MathLive load, so it does not
135
- // append a field into a holder that is going away.
136
- this.mountGeneration = (this.mountGeneration || 0) + 1;
137
-
138
- if (this.untrackCaret) {
139
- this.untrackCaret();
140
- this.untrackCaret = undefined;
141
- }
142
-
143
- if (this.untrackSelection) {
144
- this.untrackSelection();
145
- this.untrackSelection = undefined;
146
- }
147
-
148
- if (this.mathField) {
149
- this.mathField.removeEventListener('input', this.onInputEdit);
150
- this.mathField.remove();
151
- this.mathField = undefined;
152
- }
153
-
154
- if (this.props.innerRef) {
155
- this.props.innerRef(null);
156
- }
157
- }
158
-
159
- onInputEdit = () => {
160
- const { onChange } = this.props;
161
-
162
- if (!this.mathField) {
163
- return;
164
- }
165
-
166
- const latex = fromMathLive(this.mathField.getValue('latex'));
167
-
168
- this.lastEmitted = latex;
169
-
170
- if (onChange) {
171
- onChange(latex);
172
- }
173
- };
174
-
175
- /** Current latex, in stored (MathQuill-compatible) form. */
176
- latex() {
177
- return this.mathField ? fromMathLive(this.mathField.getValue('latex')) : '';
178
- }
179
-
180
- /**
181
- * The underlying `<math-field>` element, or undefined until MathLive has
182
- * finished loading. Exposed for callers that need the real element.
183
- *
184
- * NOTE: this is NOT a MathQuill field. Code written against
185
- * `@pie-lib/math-input` often did `input.mathField.latex()`; that shape is
186
- * provided by `mqCompat` below, and `latex()` on this component is the
187
- * supported replacement.
188
- */
189
- get element() {
190
- return this.mathField;
191
- }
192
-
193
- /**
194
- * MathQuill-shaped facade, so existing `input.mathField.latex()` /
195
- * `.el()` call sites keep working instead of throwing. Only the members that
196
- * consumers actually used are provided; MathQuill internals such as
197
- * `__controller` have no MathLive equivalent and are deliberately absent.
198
- */
199
- get mqCompat() {
200
- return {
201
- latex: (v) => (v === undefined ? this.latex() : (this.setLatex(v), v)),
202
- el: () => this.mathField,
203
- focus: () => this.focus(),
204
- blur: () => this.blur(),
205
- };
206
- }
207
-
208
- /** Programmatically replace the content. */
209
- setLatex(v) {
210
- if (this.mathField) {
211
- this.mathField.value = toMathLive(v || '');
212
- }
213
- }
214
-
215
- clear() {
216
- if (this.mathField) {
217
- this.mathField.value = '';
218
- }
219
-
220
- return '';
221
- }
222
-
223
- blur() {
224
- log('blur mathfield');
225
- this.mathField && this.mathField.blur();
226
- }
227
-
228
- focus() {
229
- log('focus mathfield...');
230
- this.mathField && this.mathField.focus();
231
- }
232
-
233
- /**
234
- * MathQuill `cmd()` equivalent.
235
- *
236
- * Callers pass MathQuill command names (`'\\frac'`, `'\\sqrt'`, `'^'`, or an
237
- * array of them). Those must be expanded into latex with `#?` placeholders,
238
- * otherwise inserting a bare `\frac` produces no editable slots.
239
- */
240
- command(v) {
241
- log('command: ', v);
242
-
243
- if (!this.mathField) {
244
- return '';
245
- }
246
-
247
- const action = keyToAction({ command: v });
248
-
249
- if (action) {
250
- this.mathField.insert(action.value, { focus: true });
251
- }
252
-
253
- this.mathField.focus();
254
-
255
- return this.latex();
256
- }
257
-
258
- /**
259
- * MathQuill `keystroke()` equivalent.
260
- *
261
- * Accepts MathQuill keystroke names (`'Left'`, `'Right'`, `'Backspace'`) as
262
- * the keypad emits them, and passes anything else through as a MathLive
263
- * selector.
264
- */
265
- keystroke(v) {
266
- log('keystroke: ', v);
267
-
268
- if (!this.mathField) {
269
- return '';
270
- }
271
-
272
- const selector = KEYSTROKES[v] || v;
273
-
274
- try {
275
- this.mathField.executeCommand(selector);
276
- } catch (e) {
277
- log('unknown keystroke/selector "%s": %s', v, e && e.message);
278
- }
279
-
280
- this.mathField.focus();
281
-
282
- return this.latex();
283
- }
284
-
285
- /** MathQuill `write()` equivalent. Accepts an array, as `cmd()` did. */
286
- write(v) {
287
- log('write: ', v);
288
-
289
- if (!this.mathField) {
290
- return '';
291
- }
292
-
293
- const values = Array.isArray(v) ? v : [v];
294
-
295
- values.forEach((vv) => this.mathField.insert(vv, { focus: true }));
296
- this.mathField.focus();
297
-
298
- return this.latex();
299
- }
300
-
301
- /**
302
- * Enter must not insert a line break: math input is single-expression, and
303
- * the MathQuill version swallowed charCode 13 for the same reason. Newlines
304
- * are authored explicitly through the newLine embed, not the Enter key.
305
- */
306
- onKeyDown = (event) => {
307
- if (event.key === 'Enter') {
308
- event.preventDefault();
309
- }
310
- };
311
-
312
- render() {
313
- const { className, onFocus, onBlur, onClick } = this.props;
314
-
315
- return (
316
- <Holder
317
- className={className}
318
- onFocus={onFocus}
319
- onBlur={onBlur}
320
- onClick={onClick}
321
- onKeyDown={this.onKeyDown}
322
- ref={this.holderRef}
323
- />
324
- );
325
- }
326
- }
327
-
328
- export default Input;