@pie-lib/math-input-mathlive 1.1.4 → 1.1.5-beta.10

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 (50) hide show
  1. package/README.md +14 -5
  2. package/lib/__tests__/composites.test.js +255 -0
  3. package/lib/__tests__/drop-in-compat.test.js +133 -0
  4. package/lib/__tests__/embedded-fonts.test.js +121 -0
  5. package/lib/__tests__/index.test.js +118 -0
  6. package/lib/__tests__/input-imperative.test.js +155 -0
  7. package/lib/__tests__/keypad-label.test.js +231 -0
  8. package/lib/__tests__/keypad-render.test.js +206 -0
  9. package/lib/__tests__/latex-bridge.test.js +386 -0
  10. package/lib/__tests__/mathlive-instance.test.js +419 -0
  11. package/lib/__tests__/mount-race.test.js +218 -0
  12. package/lib/__tests__/static-prompts.test.js +405 -0
  13. package/lib/__tests__/tmp-markup.test.js +26 -0
  14. package/lib/keypad/index.js +50 -28
  15. package/lib/keypad/index.js.map +1 -1
  16. package/lib/keys/geometry.js +7 -4
  17. package/lib/keys/geometry.js.map +1 -1
  18. package/lib/keys/misc.js +9 -2
  19. package/lib/keys/misc.js.map +1 -1
  20. package/lib/latex-bridge.js +207 -7
  21. package/lib/latex-bridge.js.map +1 -1
  22. package/lib/mathlive-instance.js +176 -12
  23. package/lib/mathlive-instance.js.map +1 -1
  24. package/lib/mf/common-styles.js +89 -10
  25. package/lib/mf/common-styles.js.map +1 -1
  26. package/lib/mf/index.js +12 -0
  27. package/lib/mf/index.js.map +1 -1
  28. package/lib/mf/input.js +34 -5
  29. package/lib/mf/input.js.map +1 -1
  30. package/lib/mf/static.js +107 -7
  31. package/lib/mf/static.js.map +1 -1
  32. package/package.json +3 -4
  33. package/src/__tests__/composites.test.jsx +220 -0
  34. package/src/__tests__/keypad-label.test.jsx +229 -2
  35. package/src/__tests__/keypad-render.test.jsx +123 -0
  36. package/src/__tests__/latex-bridge.test.js +159 -0
  37. package/src/__tests__/mathlive-instance.test.js +237 -0
  38. package/src/__tests__/mount-race.test.jsx +142 -0
  39. package/src/__tests__/static-prompts.test.jsx +364 -0
  40. package/src/keypad/index.jsx +33 -17
  41. package/src/keys/geometry.js +7 -2
  42. package/src/keys/misc.js +8 -2
  43. package/src/latex-bridge.js +223 -7
  44. package/src/mathlive-instance.js +196 -11
  45. package/src/mf/common-styles.js +97 -8
  46. package/src/mf/index.js +4 -0
  47. package/src/mf/input.jsx +42 -5
  48. package/src/mf/static.jsx +124 -6
  49. package/CHANGELOG.md +0 -30
  50. package/LICENSE.md +0 -5
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.supsubStyles = exports.placeholderStyles = exports.longdivStyles = exports["default"] = exports.commonMqKeyboardStyles = exports.commonMqFontStyles = exports.commonMathLiveStyles = exports.commonKeyboardStyles = void 0;
7
+ exports.supsubStyles = exports.rootIndexStyles = exports.placeholderStyles = exports.parallelStyles = exports.longdivStyles = exports["default"] = exports.commonMqKeyboardStyles = exports.commonMqFontStyles = exports.commonMathLiveStyles = exports.commonKeyboardStyles = exports.ROOT_INDEX_CSS = exports.PARALLEL_CSS = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
10
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -23,7 +23,9 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
23
23
  * Most are intentionally near-empty: MathLive sizes scripts, radicals and
24
24
  * fences correctly on its own, so the MathQuill-era corrections are not needed.
25
25
  * They stay as documented extension points rather than being deleted, so the
26
- * destructuring above keeps working.
26
+ * destructuring above keeps working. The exception is the radical index, which
27
+ * MathLive sizes to TeX metrics that read too small here - see
28
+ * `rootIndexStyles`.
27
29
  */
28
30
 
29
31
  /**
@@ -50,10 +52,57 @@ var longdivStyles = exports.longdivStyles = {
50
52
  };
51
53
 
52
54
  /**
53
- * Superscript/subscript sizing. MathLive follows TeX metrics, so no overrides
54
- * are required.
55
+ * How the index of a radical is sized.
56
+ *
57
+ * MathLive follows TeX and sets the index of `\sqrt[n]{x}` in scriptscriptstyle,
58
+ * which it emits as an inline `font-size: 50%` on the span wrapping the index's
59
+ * glyphs. At authoring sizes that leaves the index - on the nth-root key, and in
60
+ * any radical the author types - too small to read next to the radicand, so it is
61
+ * scaled up to 80% - 1.6x what MathLive asks for.
62
+ *
63
+ * Only that innermost span is resized. `.ML__sqrt-index` itself keeps its font
64
+ * size on purpose: the vlist inside it tucks the index into the radical's crook
65
+ * with em-based `top`/`height` offsets, and scaling those lifts the index clear
66
+ * of the radical instead of just enlarging it.
67
+ *
68
+ * The child chain is spelled out so that nothing nested deeper inside the index
69
+ * (a fraction's numerator, another radical) is caught by the same rule, and
70
+ * `!important` is required because the 50% is an INLINE style.
55
71
  */
56
- var supsubStyles = exports.supsubStyles = {};
72
+ var ROOT_INDEX_SELECTOR = '.ML__sqrt-index > .ML__vlist-t > .ML__vlist-r > .ML__vlist > span > [style*="font-size"]';
73
+ var ROOT_INDEX_FONT_SIZE = '80%';
74
+ var rootIndexStyles = exports.rootIndexStyles = (0, _defineProperty2["default"])({}, "& ".concat(ROOT_INDEX_SELECTOR), {
75
+ fontSize: "".concat(ROOT_INDEX_FONT_SIZE, " !important")
76
+ });
77
+
78
+ /**
79
+ * The same rule as a CSS string, for a live mathfield's shadow root - see
80
+ * `SHADOW_CSS` in mathlive-instance.js. Static markup is styled by
81
+ * {@link rootIndexStyles}.
82
+ */
83
+ var ROOT_INDEX_CSS = exports.ROOT_INDEX_CSS = "".concat(ROOT_INDEX_SELECTOR, "{font-size:").concat(ROOT_INDEX_FONT_SIZE, " !important}");
84
+
85
+ /**
86
+ * Size of the parallel sign (`\parallel`, tagged `data-pie-macro="parallel"` by
87
+ * `PIE_MACROS`). The legacy editor enlarged it (`updateSpans` set 32px) because
88
+ * the bars read too small next to the letters of `AB ∥ CD`; MathLive draws it at
89
+ * the surrounding size, so it is scaled up here. Not applied to keypad labels.
90
+ */
91
+ var PARALLEL_SELECTOR = '[data-pie-macro="parallel"]';
92
+ var PARALLEL_FONT_SIZE = '1.4em';
93
+ var parallelStyles = exports.parallelStyles = (0, _defineProperty2["default"])({}, "& ".concat(PARALLEL_SELECTOR), {
94
+ fontSize: PARALLEL_FONT_SIZE
95
+ });
96
+
97
+ /** The same rule as a CSS string, for a live mathfield's shadow root. */
98
+ var PARALLEL_CSS = exports.PARALLEL_CSS = "".concat(PARALLEL_SELECTOR, "{font-size:").concat(PARALLEL_FONT_SIZE, "}");
99
+
100
+ /**
101
+ * Superscript/subscript sizing. MathLive follows TeX metrics for scripts, so the
102
+ * MathQuill-era corrections are gone; the radical index is the one place where a
103
+ * TeX-correct size reads too small in the authoring UI.
104
+ */
105
+ var supsubStyles = exports.supsubStyles = _objectSpread(_objectSpread({}, rootIndexStyles), parallelStyles);
57
106
 
58
107
  /** Empty placeholder boxes (answer blocks / open slots). */
59
108
  var placeholderStyles = exports.placeholderStyles = {
@@ -67,12 +116,41 @@ var placeholderStyles = exports.placeholderStyles = {
67
116
  '& [data-pie-empty]': {
68
117
  opacity: 0.5
69
118
  },
70
- // Stretchy accents render an <svg>; mathlive-static.css positions it
71
- // absolutely at width:100%. Repeated here so static math cannot blow out its
72
- // container if that stylesheet is missing.
73
- '& svg': {
119
+ // Stretchy accents (\overarc, \overleftrightarrow, \overrightarrow) render an
120
+ // <svg width="100%" preserveAspectRatio="none"> inside a `.ML__stretchy`. That
121
+ // span is absolutely positioned, so its immediate wrapper computes to 0px and
122
+ // the width has to resolve against a *positioned* ancestor. Pin that to
123
+ // `.ML__base`, whose width already equals the accent's content (measured:
124
+ // 9.85px for a 0.56em slot), so the arc spans exactly its content.
125
+ //
126
+ // Do NOT write a bare `& svg` rule instead: MathLive's own rule is
127
+ // descendant-scoped (`.ML__latex .ML__stretchy svg`), and a global one
128
+ // re-parents every svg in the subtree.
129
+ '& .ML__base': {
130
+ position: 'relative'
131
+ },
132
+ '& .ML__stretchy': {
74
133
  position: 'absolute',
134
+ left: 0,
75
135
  width: '100%'
136
+ },
137
+ // MathLive centres an accent by shifting it right half the content width -
138
+ // `margin-left: 0.28em` for a 0.56em slot - which assumes a glyph with its own
139
+ // side bearings. Over a synthetic empty slot it just pushes the arc right.
140
+ //
141
+ // `!important` is required: MathLive writes this as an INLINE style
142
+ // (`style="top:-3.4em;margin-left:0.28em"`), which a class cannot override.
143
+ //
144
+ // It also fixes the width. `.ML__center` is the stretchy's containing block
145
+ // (MathLive gives `.ML__vlist > span` position:relative), and its width is the
146
+ // base minus that margin - measured 9.85px - 4.93px = 4.93px, exactly half,
147
+ // which is why the arc came out half-width AND offset right.
148
+ //
149
+ // Scoped with `:has(.ML__stretchy)`: only stretchy accents are affected.
150
+ // A single-glyph accent (`\hat{x}`, `\vec{x}`) genuinely needs its centring
151
+ // offset, and must keep it.
152
+ '& .ML__center:has(.ML__stretchy)': {
153
+ marginLeft: '0 !important'
76
154
  }
77
155
  };
78
156
 
@@ -80,7 +158,7 @@ var placeholderStyles = exports.placeholderStyles = {
80
158
  * Styling for the on-screen keyboard and any container rendering math labels.
81
159
  * Also hides MathLive's own affordances, since pie supplies its own keypad.
82
160
  */
83
- var commonMqKeyboardStyles = exports.commonMqKeyboardStyles = _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, commonMqFontStyles), longdivStyles), placeholderStyles), {}, {
161
+ var commonMqKeyboardStyles = exports.commonMqKeyboardStyles = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, commonMqFontStyles), longdivStyles), rootIndexStyles), placeholderStyles), {}, {
84
162
  touchAction: 'manipulation',
85
163
  '& math-field': {
86
164
  fontSize: 'inherit',
@@ -116,6 +194,7 @@ var commonKeyboardStyles = exports.commonKeyboardStyles = commonMqKeyboardStyles
116
194
  var _default = exports["default"] = {
117
195
  commonMqFontStyles: commonMqFontStyles,
118
196
  longdivStyles: longdivStyles,
197
+ rootIndexStyles: rootIndexStyles,
119
198
  supsubStyles: supsubStyles,
120
199
  commonMqKeyboardStyles: commonMqKeyboardStyles,
121
200
  placeholderStyles: placeholderStyles,
@@ -1 +1 @@
1
- {"version":3,"file":"common-styles.js","names":["commonMqFontStyles","exports","fontFamily","longdivStyles","display","supsubStyles","placeholderStyles","borderBottom","minWidth","opacity","position","width","commonMqKeyboardStyles","_objectSpread","touchAction","fontSize","outline","commonMathLiveStyles","commonKeyboardStyles","_default"],"sources":["../../src/mf/common-styles.js"],"sourcesContent":["/**\n * Shared MathLive styling.\n *\n * Replaces @pie-lib/math-input's `common-mq-styles.js`. That file was built\n * around MathQuill's `.mq-*` class names, none of which exist in MathLive\n * output, so the selectors here target MathLive's own structure instead.\n *\n * The four named groups are kept because consumers destructure them:\n *\n * const { commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, supsubStyles }\n * = mq.CommonMqStyles; // math-toolbar/src/editor-and-pad.jsx, math-preview.jsx\n *\n * Most are intentionally near-empty: MathLive sizes scripts, radicals and\n * fences correctly on its own, so the MathQuill-era corrections are not needed.\n * They stay as documented extension points rather than being deleted, so the\n * destructuring above keeps working.\n */\n\n/**\n * Font styling. MathQuill needed explicit MathJax font families to match the\n * static renderer; MathLive ships the KaTeX fonts it renders with, so this only\n * smooths rendering and lets the host override the family.\n */\nexport const commonMqFontStyles = {\n '-webkit-font-smoothing': 'antialiased',\n '& math-field': {\n fontFamily: 'inherit',\n },\n};\n\n/**\n * Long division. The MathQuill fork drew this with nested `.mq-longdiv-*`\n * elements that needed manual offsets; here it comes from the `\\longdiv` macro\n * (see `PIE_MACROS`), tagged with `data-pie-macro=\"longdiv\"`.\n */\nexport const longdivStyles = {\n '& [data-pie-macro=\"longdiv\"]': {\n display: 'inline-flex',\n },\n};\n\n/**\n * Superscript/subscript sizing. MathLive follows TeX metrics, so no overrides\n * are required.\n */\nexport const supsubStyles = {};\n\n/** Empty placeholder boxes (answer blocks / open slots). */\nexport const placeholderStyles = {\n '& .ML__placeholder': {\n borderBottom: '1px solid currentColor',\n minWidth: '1em',\n },\n // Stand-in glyph for an empty argument slot in STATIC math (see\n // `withVisibleEmptySlots`). Muted so it reads as \"a slot goes here\" rather\n // than as part of the symbol, matching how MathQuill shaded `.mq-empty`.\n '& [data-pie-empty]': {\n opacity: 0.5,\n },\n // Stretchy accents render an <svg>; mathlive-static.css positions it\n // absolutely at width:100%. Repeated here so static math cannot blow out its\n // container if that stylesheet is missing.\n '& svg': {\n position: 'absolute',\n width: '100%',\n },\n};\n\n/**\n * Styling for the on-screen keyboard and any container rendering math labels.\n * Also hides MathLive's own affordances, since pie supplies its own keypad.\n */\nexport const commonMqKeyboardStyles = {\n ...commonMqFontStyles,\n ...longdivStyles,\n ...placeholderStyles,\n touchAction: 'manipulation',\n '& math-field': {\n fontSize: 'inherit',\n outline: 'none',\n },\n '& math-field::part(virtual-keyboard-toggle)': {\n display: 'none',\n },\n '& math-field::part(menu-toggle)': {\n display: 'none',\n },\n};\n\n/** Everything combined - the common case for a container of math. */\nexport const commonMathLiveStyles = {\n ...commonMqFontStyles,\n ...longdivStyles,\n ...supsubStyles,\n ...placeholderStyles,\n '& math-field': {\n fontSize: 'inherit',\n outline: 'none',\n },\n '& math-field::part(virtual-keyboard-toggle)': {\n display: 'none',\n },\n '& math-field::part(menu-toggle)': {\n display: 'none',\n },\n};\n\nexport const commonKeyboardStyles = commonMqKeyboardStyles;\n\n/**\n * Default export mirrors @pie-lib/math-input's `CommonMqStyles` object so\n * existing destructuring keeps working.\n */\nexport default {\n commonMqFontStyles,\n longdivStyles,\n supsubStyles,\n commonMqKeyboardStyles,\n placeholderStyles,\n commonMathLiveStyles,\n};\n"],"mappings":";;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACO,IAAMA,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAAG;EAChC,wBAAwB,EAAE,aAAa;EACvC,cAAc,EAAE;IACdE,UAAU,EAAE;EACd;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACO,IAAMC,aAAa,GAAAF,OAAA,CAAAE,aAAA,GAAG;EAC3B,8BAA8B,EAAE;IAC9BC,OAAO,EAAE;EACX;AACF,CAAC;;AAED;AACA;AACA;AACA;AACO,IAAMC,YAAY,GAAAJ,OAAA,CAAAI,YAAA,GAAG,CAAC,CAAC;;AAE9B;AACO,IAAMC,iBAAiB,GAAAL,OAAA,CAAAK,iBAAA,GAAG;EAC/B,oBAAoB,EAAE;IACpBC,YAAY,EAAE,wBAAwB;IACtCC,QAAQ,EAAE;EACZ,CAAC;EACD;EACA;EACA;EACA,oBAAoB,EAAE;IACpBC,OAAO,EAAE;EACX,CAAC;EACD;EACA;EACA;EACA,OAAO,EAAE;IACPC,QAAQ,EAAE,UAAU;IACpBC,KAAK,EAAE;EACT;AACF,CAAC;;AAED;AACA;AACA;AACA;AACO,IAAMC,sBAAsB,GAAAX,OAAA,CAAAW,sBAAA,GAAAC,aAAA,CAAAA,aAAA,CAAAA,aAAA,CAAAA,aAAA,KAC9Bb,kBAAkB,GAClBG,aAAa,GACbG,iBAAiB;EACpBQ,WAAW,EAAE,cAAc;EAC3B,cAAc,EAAE;IACdC,QAAQ,EAAE,SAAS;IACnBC,OAAO,EAAE;EACX,CAAC;EACD,6CAA6C,EAAE;IAC7CZ,OAAO,EAAE;EACX,CAAC;EACD,iCAAiC,EAAE;IACjCA,OAAO,EAAE;EACX;AAAC,EACF;;AAED;AACO,IAAMa,oBAAoB,GAAAhB,OAAA,CAAAgB,oBAAA,GAAAJ,aAAA,CAAAA,aAAA,CAAAA,aAAA,CAAAA,aAAA,CAAAA,aAAA,KAC5Bb,kBAAkB,GAClBG,aAAa,GACbE,YAAY,GACZC,iBAAiB;EACpB,cAAc,EAAE;IACdS,QAAQ,EAAE,SAAS;IACnBC,OAAO,EAAE;EACX,CAAC;EACD,6CAA6C,EAAE;IAC7CZ,OAAO,EAAE;EACX,CAAC;EACD,iCAAiC,EAAE;IACjCA,OAAO,EAAE;EACX;AAAC,EACF;AAEM,IAAMc,oBAAoB,GAAAjB,OAAA,CAAAiB,oBAAA,GAAGN,sBAAsB;;AAE1D;AACA;AACA;AACA;AAHA,IAAAO,QAAA,GAAAlB,OAAA,cAIe;EACbD,kBAAkB,EAAlBA,kBAAkB;EAClBG,aAAa,EAAbA,aAAa;EACbE,YAAY,EAAZA,YAAY;EACZO,sBAAsB,EAAtBA,sBAAsB;EACtBN,iBAAiB,EAAjBA,iBAAiB;EACjBW,oBAAoB,EAApBA;AACF,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"common-styles.js","names":["commonMqFontStyles","exports","fontFamily","longdivStyles","display","ROOT_INDEX_SELECTOR","ROOT_INDEX_FONT_SIZE","rootIndexStyles","_defineProperty2","concat","fontSize","ROOT_INDEX_CSS","PARALLEL_SELECTOR","PARALLEL_FONT_SIZE","parallelStyles","PARALLEL_CSS","supsubStyles","_objectSpread","placeholderStyles","borderBottom","minWidth","opacity","position","left","width","marginLeft","commonMqKeyboardStyles","touchAction","outline","commonMathLiveStyles","commonKeyboardStyles","_default"],"sources":["../../src/mf/common-styles.js"],"sourcesContent":["/**\n * Shared MathLive styling.\n *\n * Replaces @pie-lib/math-input's `common-mq-styles.js`. That file was built\n * around MathQuill's `.mq-*` class names, none of which exist in MathLive\n * output, so the selectors here target MathLive's own structure instead.\n *\n * The four named groups are kept because consumers destructure them:\n *\n * const { commonMqFontStyles, commonMqKeyboardStyles, longdivStyles, supsubStyles }\n * = mq.CommonMqStyles; // math-toolbar/src/editor-and-pad.jsx, math-preview.jsx\n *\n * Most are intentionally near-empty: MathLive sizes scripts, radicals and\n * fences correctly on its own, so the MathQuill-era corrections are not needed.\n * They stay as documented extension points rather than being deleted, so the\n * destructuring above keeps working. The exception is the radical index, which\n * MathLive sizes to TeX metrics that read too small here - see\n * `rootIndexStyles`.\n */\n\n/**\n * Font styling. MathQuill needed explicit MathJax font families to match the\n * static renderer; MathLive ships the KaTeX fonts it renders with, so this only\n * smooths rendering and lets the host override the family.\n */\nexport const commonMqFontStyles = {\n '-webkit-font-smoothing': 'antialiased',\n '& math-field': {\n fontFamily: 'inherit',\n },\n};\n\n/**\n * Long division. The MathQuill fork drew this with nested `.mq-longdiv-*`\n * elements that needed manual offsets; here it comes from the `\\longdiv` macro\n * (see `PIE_MACROS`), tagged with `data-pie-macro=\"longdiv\"`.\n */\nexport const longdivStyles = {\n '& [data-pie-macro=\"longdiv\"]': {\n display: 'inline-flex',\n },\n};\n\n/**\n * How the index of a radical is sized.\n *\n * MathLive follows TeX and sets the index of `\\sqrt[n]{x}` in scriptscriptstyle,\n * which it emits as an inline `font-size: 50%` on the span wrapping the index's\n * glyphs. At authoring sizes that leaves the index - on the nth-root key, and in\n * any radical the author types - too small to read next to the radicand, so it is\n * scaled up to 80% - 1.6x what MathLive asks for.\n *\n * Only that innermost span is resized. `.ML__sqrt-index` itself keeps its font\n * size on purpose: the vlist inside it tucks the index into the radical's crook\n * with em-based `top`/`height` offsets, and scaling those lifts the index clear\n * of the radical instead of just enlarging it.\n *\n * The child chain is spelled out so that nothing nested deeper inside the index\n * (a fraction's numerator, another radical) is caught by the same rule, and\n * `!important` is required because the 50% is an INLINE style.\n */\nconst ROOT_INDEX_SELECTOR = '.ML__sqrt-index > .ML__vlist-t > .ML__vlist-r > .ML__vlist > span > [style*=\"font-size\"]';\nconst ROOT_INDEX_FONT_SIZE = '80%';\n\nexport const rootIndexStyles = {\n [`& ${ROOT_INDEX_SELECTOR}`]: {\n fontSize: `${ROOT_INDEX_FONT_SIZE} !important`,\n },\n};\n\n/**\n * The same rule as a CSS string, for a live mathfield's shadow root - see\n * `SHADOW_CSS` in mathlive-instance.js. Static markup is styled by\n * {@link rootIndexStyles}.\n */\nexport const ROOT_INDEX_CSS = `${ROOT_INDEX_SELECTOR}{font-size:${ROOT_INDEX_FONT_SIZE} !important}`;\n\n/**\n * Size of the parallel sign (`\\parallel`, tagged `data-pie-macro=\"parallel\"` by\n * `PIE_MACROS`). The legacy editor enlarged it (`updateSpans` set 32px) because\n * the bars read too small next to the letters of `AB ∥ CD`; MathLive draws it at\n * the surrounding size, so it is scaled up here. Not applied to keypad labels.\n */\nconst PARALLEL_SELECTOR = '[data-pie-macro=\"parallel\"]';\nconst PARALLEL_FONT_SIZE = '1.4em';\n\nexport const parallelStyles = {\n [`& ${PARALLEL_SELECTOR}`]: {\n fontSize: PARALLEL_FONT_SIZE,\n },\n};\n\n/** The same rule as a CSS string, for a live mathfield's shadow root. */\nexport const PARALLEL_CSS = `${PARALLEL_SELECTOR}{font-size:${PARALLEL_FONT_SIZE}}`;\n\n/**\n * Superscript/subscript sizing. MathLive follows TeX metrics for scripts, so the\n * MathQuill-era corrections are gone; the radical index is the one place where a\n * TeX-correct size reads too small in the authoring UI.\n */\nexport const supsubStyles = {\n ...rootIndexStyles,\n ...parallelStyles,\n};\n\n/** Empty placeholder boxes (answer blocks / open slots). */\nexport const placeholderStyles = {\n '& .ML__placeholder': {\n borderBottom: '1px solid currentColor',\n minWidth: '1em',\n },\n // Stand-in glyph for an empty argument slot in STATIC math (see\n // `withVisibleEmptySlots`). Muted so it reads as \"a slot goes here\" rather\n // than as part of the symbol, matching how MathQuill shaded `.mq-empty`.\n '& [data-pie-empty]': {\n opacity: 0.5,\n },\n // Stretchy accents (\\overarc, \\overleftrightarrow, \\overrightarrow) render an\n // <svg width=\"100%\" preserveAspectRatio=\"none\"> inside a `.ML__stretchy`. That\n // span is absolutely positioned, so its immediate wrapper computes to 0px and\n // the width has to resolve against a *positioned* ancestor. Pin that to\n // `.ML__base`, whose width already equals the accent's content (measured:\n // 9.85px for a 0.56em slot), so the arc spans exactly its content.\n //\n // Do NOT write a bare `& svg` rule instead: MathLive's own rule is\n // descendant-scoped (`.ML__latex .ML__stretchy svg`), and a global one\n // re-parents every svg in the subtree.\n '& .ML__base': {\n position: 'relative',\n },\n '& .ML__stretchy': {\n position: 'absolute',\n left: 0,\n width: '100%',\n },\n // MathLive centres an accent by shifting it right half the content width -\n // `margin-left: 0.28em` for a 0.56em slot - which assumes a glyph with its own\n // side bearings. Over a synthetic empty slot it just pushes the arc right.\n //\n // `!important` is required: MathLive writes this as an INLINE style\n // (`style=\"top:-3.4em;margin-left:0.28em\"`), which a class cannot override.\n //\n // It also fixes the width. `.ML__center` is the stretchy's containing block\n // (MathLive gives `.ML__vlist > span` position:relative), and its width is the\n // base minus that margin - measured 9.85px - 4.93px = 4.93px, exactly half,\n // which is why the arc came out half-width AND offset right.\n //\n // Scoped with `:has(.ML__stretchy)`: only stretchy accents are affected.\n // A single-glyph accent (`\\hat{x}`, `\\vec{x}`) genuinely needs its centring\n // offset, and must keep it.\n '& .ML__center:has(.ML__stretchy)': {\n marginLeft: '0 !important',\n },\n};\n\n/**\n * Styling for the on-screen keyboard and any container rendering math labels.\n * Also hides MathLive's own affordances, since pie supplies its own keypad.\n */\nexport const commonMqKeyboardStyles = {\n ...commonMqFontStyles,\n ...longdivStyles,\n ...rootIndexStyles,\n ...placeholderStyles,\n touchAction: 'manipulation',\n '& math-field': {\n fontSize: 'inherit',\n outline: 'none',\n },\n '& math-field::part(virtual-keyboard-toggle)': {\n display: 'none',\n },\n '& math-field::part(menu-toggle)': {\n display: 'none',\n },\n};\n\n/** Everything combined - the common case for a container of math. */\nexport const commonMathLiveStyles = {\n ...commonMqFontStyles,\n ...longdivStyles,\n ...supsubStyles,\n ...placeholderStyles,\n '& math-field': {\n fontSize: 'inherit',\n outline: 'none',\n },\n '& math-field::part(virtual-keyboard-toggle)': {\n display: 'none',\n },\n '& math-field::part(menu-toggle)': {\n display: 'none',\n },\n};\n\nexport const commonKeyboardStyles = commonMqKeyboardStyles;\n\n/**\n * Default export mirrors @pie-lib/math-input's `CommonMqStyles` object so\n * existing destructuring keeps working.\n */\nexport default {\n commonMqFontStyles,\n longdivStyles,\n rootIndexStyles,\n supsubStyles,\n commonMqKeyboardStyles,\n placeholderStyles,\n commonMathLiveStyles,\n};\n"],"mappings":"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","ignoreList":[]}
package/lib/mf/index.js CHANGED
@@ -53,12 +53,24 @@ Object.defineProperty(exports, "longdivStyles", {
53
53
  return _commonStyles.longdivStyles;
54
54
  }
55
55
  });
56
+ Object.defineProperty(exports, "parallelStyles", {
57
+ enumerable: true,
58
+ get: function get() {
59
+ return _commonStyles.parallelStyles;
60
+ }
61
+ });
56
62
  Object.defineProperty(exports, "placeholderStyles", {
57
63
  enumerable: true,
58
64
  get: function get() {
59
65
  return _commonStyles.placeholderStyles;
60
66
  }
61
67
  });
68
+ Object.defineProperty(exports, "rootIndexStyles", {
69
+ enumerable: true,
70
+ get: function get() {
71
+ return _commonStyles.rootIndexStyles;
72
+ }
73
+ });
62
74
  Object.defineProperty(exports, "supsubStyles", {
63
75
  enumerable: true,
64
76
  get: function get() {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_input","_interopRequireDefault","require","_static","_commonStyles","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","_typeof","has","get","set","_t","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor"],"sources":["../../src/mf/index.js"],"sourcesContent":["import Input from './input';\nimport Static from './static';\nimport CommonMqStyles, {\n commonMathLiveStyles,\n commonKeyboardStyles,\n commonMqFontStyles,\n commonMqKeyboardStyles,\n longdivStyles,\n supsubStyles,\n placeholderStyles,\n} from './common-styles';\n\nexport {\n Input,\n Static,\n // Same object shape as @pie-lib/math-input's `mq.CommonMqStyles`, so\n // `const { commonMqFontStyles, ... } = mq.CommonMqStyles` keeps working.\n CommonMqStyles,\n commonMathLiveStyles,\n commonKeyboardStyles,\n commonMqFontStyles,\n commonMqKeyboardStyles,\n longdivStyles,\n supsubStyles,\n placeholderStyles,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,OAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,aAAA,GAAAC,uBAAA,CAAAH,OAAA;AAQyB,SAAAG,wBAAAC,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAH,uBAAA,YAAAA,wBAAAC,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,mBAAAT,CAAA,iBAAAA,CAAA,gBAAAU,OAAA,CAAAV,CAAA,0BAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,cAAAM,EAAA,IAAAd,CAAA,gBAAAc,EAAA,OAAAC,cAAA,CAAAC,IAAA,CAAAhB,CAAA,EAAAc,EAAA,OAAAP,CAAA,IAAAD,CAAA,GAAAW,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAnB,CAAA,EAAAc,EAAA,OAAAP,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAM,EAAA,EAAAP,CAAA,IAAAC,CAAA,CAAAM,EAAA,IAAAd,CAAA,CAAAc,EAAA,WAAAN,CAAA,KAAAR,CAAA,EAAAC,CAAA","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["_input","_interopRequireDefault","require","_static","_commonStyles","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","_typeof","has","get","set","_t","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor"],"sources":["../../src/mf/index.js"],"sourcesContent":["import Input from './input';\nimport Static from './static';\nimport CommonMqStyles, {\n commonMathLiveStyles,\n commonKeyboardStyles,\n commonMqFontStyles,\n commonMqKeyboardStyles,\n longdivStyles,\n rootIndexStyles,\n parallelStyles,\n supsubStyles,\n placeholderStyles,\n} from './common-styles';\n\nexport {\n Input,\n Static,\n // Same object shape as @pie-lib/math-input's `mq.CommonMqStyles`, so\n // `const { commonMqFontStyles, ... } = mq.CommonMqStyles` keeps working.\n CommonMqStyles,\n commonMathLiveStyles,\n commonKeyboardStyles,\n commonMqFontStyles,\n commonMqKeyboardStyles,\n longdivStyles,\n rootIndexStyles,\n parallelStyles,\n supsubStyles,\n placeholderStyles,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,OAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,aAAA,GAAAC,uBAAA,CAAAH,OAAA;AAUyB,SAAAG,wBAAAC,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAH,uBAAA,YAAAA,wBAAAC,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,mBAAAT,CAAA,iBAAAA,CAAA,gBAAAU,OAAA,CAAAV,CAAA,0BAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,cAAAM,EAAA,IAAAd,CAAA,gBAAAc,EAAA,OAAAC,cAAA,CAAAC,IAAA,CAAAhB,CAAA,EAAAc,EAAA,OAAAP,CAAA,IAAAD,CAAA,GAAAW,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAnB,CAAA,EAAAc,EAAA,OAAAP,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAM,EAAA,EAAAP,CAAA,IAAAC,CAAA,CAAAM,EAAA,IAAAd,CAAA,CAAAc,EAAA,WAAAN,CAAA,KAAAR,CAAA,EAAAC,CAAA","ignoreList":[]}
package/lib/mf/input.js CHANGED
@@ -80,16 +80,22 @@ var Input = exports.Input = /*#__PURE__*/function (_React$Component) {
80
80
  key: "componentDidMount",
81
81
  value: function () {
82
82
  var _componentDidMount = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee() {
83
- var _this$setState;
84
- var ml;
83
+ var generation, ml;
85
84
  return _regenerator["default"].wrap(function (_context) {
86
85
  while (1) switch (_context.prev = _context.next) {
87
86
  case 0:
87
+ // MathLive loads asynchronously, so this method resumes after an await and
88
+ // has to know whether it is still the current mount. React StrictMode calls
89
+ // mount -> unmount -> mount on the SAME instance in dev, so a boolean
90
+ // "unmounted" flag would latch and block the remount from ever creating a
91
+ // field. A generation counter identifies the live mount instead: only the
92
+ // newest one proceeds, and a real unmount invalidates all pending ones.
93
+ generation = this.mountGeneration = (this.mountGeneration || 0) + 1;
88
94
  _context.next = 1;
89
95
  return (0, _mathliveInstance.loadMathLive)();
90
96
  case 1:
91
97
  ml = _context.sent;
92
- if (!(!ml || !this.holderRef.current)) {
98
+ if (!(generation !== this.mountGeneration || !ml || !this.holderRef.current || this.mathField)) {
93
99
  _context.next = 2;
94
100
  break;
95
101
  }
@@ -105,12 +111,28 @@ var Input = exports.Input = /*#__PURE__*/function (_React$Component) {
105
111
 
106
112
  // pie drives input through its own keypad, so suppress MathLive's.
107
113
  this.mathField.mathVirtualKeyboardPolicy = 'manual';
114
+ // Without this the spacebar does nothing: MathLive's mathModeSpace
115
+ // defaults to an empty string.
116
+ this.mathField.mathModeSpace = _mathliveInstance.MATH_MODE_SPACE;
117
+ // After the exponent key the cursor must stay in the exponent until it is moved
118
+ // MathLive's `smartSuperscript` (on by
119
+ // default) jumps out of an empty superscript after a single digit, which breaks
120
+ // typing x^23 or 10^6 and is inconsistent with non-digit exponents.
121
+ this.mathField.smartSuperscript = false;
122
+
123
+ // The mathfield renders in shadow DOM, so page CSS cannot reach it - the
124
+ // stretchy-accent fix has to be injected there directly.
125
+ (0, _mathliveInstance.applyShadowStyles)(this.mathField);
126
+
127
+ // A selected `\placeholder{}` gets no MathLive caret; draw one.
128
+ this.untrackCaret = (0, _mathliveInstance.trackPlaceholderCaret)(this.mathField);
108
129
  this.mathField.addEventListener('input', this.onInputEdit);
109
- this.holderRef.current.appendChild(this.mathField);
130
+
131
+ // Belt and braces: drop anything a previous mount may have left behind.
132
+ this.holderRef.current.replaceChildren(this.mathField);
110
133
  if (this.props.innerRef) {
111
134
  this.props.innerRef(this);
112
135
  }
113
- (_this$setState = this.setState) === null || _this$setState === void 0 || _this$setState.call(this, {});
114
136
  case 3:
115
137
  case "end":
116
138
  return _context.stop();
@@ -148,6 +170,13 @@ var Input = exports.Input = /*#__PURE__*/function (_React$Component) {
148
170
  }, {
149
171
  key: "componentWillUnmount",
150
172
  value: function componentWillUnmount() {
173
+ // Invalidate any mount still awaiting the MathLive load, so it does not
174
+ // append a field into a holder that is going away.
175
+ this.mountGeneration = (this.mountGeneration || 0) + 1;
176
+ if (this.untrackCaret) {
177
+ this.untrackCaret();
178
+ this.untrackCaret = undefined;
179
+ }
151
180
  if (this.mathField) {
152
181
  this.mathField.removeEventListener('input', this.onInputEdit);
153
182
  this.mathField.remove();
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","names":["_react","_interopRequireDefault","require","_propTypes","_styles","_debug","_mathliveInstance","_latexBridge","_callSuper","t","o","e","_getPrototypeOf2","_possibleConstructorReturn2","_isNativeReflectConstruct","Reflect","construct","constructor","apply","Boolean","prototype","valueOf","call","log","debug","Holder","styled","display","width","Input","exports","_React$Component","props","_this","_classCallCheck2","_defineProperty2","onChange","mathField","latex","fromMathLive","getValue","lastEmitted","event","key","preventDefault","holderRef","React","createRef","undefined","_inherits2","_createClass2","value","_componentDidMount","_asyncToGenerator2","_regenerator","mark","_callee","_this$setState","ml","wrap","_context","prev","next","loadMathLive","sent","current","abrupt","MathfieldElement","macros","getMacros","toMathLive","readOnly","mathVirtualKeyboardPolicy","addEventListener","onInputEdit","appendChild","innerRef","setState","stop","componentDidMount","arguments","componentDidUpdate","prevProps","_this$props","componentWillUnmount","removeEventListener","remove","get","_this2","v","setLatex","el","focus","blur","clear","command","action","keyToAction","insert","keystroke","selector","KEYSTROKES","executeCommand","message","write","_this3","values","Array","isArray","forEach","vv","render","_this$props2","className","onFocus","onBlur","onClick","createElement","onKeyDown","ref","Component","PropTypes","string","func","bool","_default"],"sources":["../../src/mf/input.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { styled } from '@mui/material/styles';\nimport debug from 'debug';\nimport { loadMathLive, getMacros } from '../mathlive-instance';\nimport { toMathLive, fromMathLive, keyToAction, KEYSTROKES } from '../latex-bridge';\n\nconst log = debug('pie-lib:math-input-mathlive:input');\n\nconst Holder = styled('span')({\n display: 'inline-block',\n '& math-field': {\n display: 'block',\n width: '100%',\n },\n // MathLive ships its own virtual keyboard toggle; pie supplies its own keypad.\n '& math-field::part(virtual-keyboard-toggle)': {\n display: 'none',\n },\n '& math-field::part(menu-toggle)': {\n display: 'none',\n },\n});\n\n/**\n * Editable math field. Drop-in replacement for @pie-lib/math-input's `mq.Input`.\n *\n * Keeps the same imperative surface used by MathInput's keypad\n * (`write`, `command`, `keystroke`, `clear`, `focus`, `blur`) so callers do not\n * change, and the same `latex` / `onChange` props.\n */\nexport class Input extends React.Component {\n static propTypes = {\n className: PropTypes.string,\n latex: PropTypes.string,\n onChange: PropTypes.func,\n onClick: PropTypes.func,\n onFocus: PropTypes.func,\n onBlur: PropTypes.func,\n readOnly: PropTypes.bool,\n innerRef: PropTypes.func,\n };\n\n constructor(props) {\n super(props);\n this.holderRef = React.createRef();\n // Tracks the last latex we emitted, so prop echoes don't reset the cursor.\n this.lastEmitted = undefined;\n }\n\n async componentDidMount() {\n const ml = await loadMathLive();\n\n if (!ml || !this.holderRef.current) {\n return;\n }\n\n this.mathField = new ml.MathfieldElement({ macros: getMacros() });\n this.mathField.value = toMathLive(this.props.latex || '');\n\n if (this.props.readOnly) {\n this.mathField.readOnly = true;\n }\n\n // pie drives input through its own keypad, so suppress MathLive's.\n this.mathField.mathVirtualKeyboardPolicy = 'manual';\n\n this.mathField.addEventListener('input', this.onInputEdit);\n this.holderRef.current.appendChild(this.mathField);\n\n if (this.props.innerRef) {\n this.props.innerRef(this);\n }\n\n this.setState?.({});\n }\n\n componentDidUpdate(prevProps) {\n if (!this.mathField) {\n return;\n }\n\n const { latex, readOnly } = this.props;\n\n if (readOnly !== prevProps.readOnly) {\n this.mathField.readOnly = !!readOnly;\n }\n\n // Only push the prop back into the field when it genuinely differs from\n // what the field already holds. This is the analogue of the old\n // shouldComponentUpdate latex-equality guard and prevents cursor thrash.\n if (latex !== undefined && latex !== null && latex !== this.lastEmitted) {\n const next = toMathLive(latex);\n\n if (next !== this.mathField.value) {\n this.mathField.value = next;\n }\n }\n }\n\n componentWillUnmount() {\n if (this.mathField) {\n this.mathField.removeEventListener('input', this.onInputEdit);\n this.mathField.remove();\n this.mathField = undefined;\n }\n\n if (this.props.innerRef) {\n this.props.innerRef(null);\n }\n }\n\n onInputEdit = () => {\n const { onChange } = this.props;\n\n if (!this.mathField) {\n return;\n }\n\n const latex = fromMathLive(this.mathField.getValue('latex'));\n\n this.lastEmitted = latex;\n\n if (onChange) {\n onChange(latex);\n }\n };\n\n /** Current latex, in stored (MathQuill-compatible) form. */\n latex() {\n return this.mathField ? fromMathLive(this.mathField.getValue('latex')) : '';\n }\n\n /**\n * The underlying `<math-field>` element, or undefined until MathLive has\n * finished loading. Exposed for callers that need the real element.\n *\n * NOTE: this is NOT a MathQuill field. Code written against\n * `@pie-lib/math-input` often did `input.mathField.latex()`; that shape is\n * provided by `mqCompat` below, and `latex()` on this component is the\n * supported replacement.\n */\n get element() {\n return this.mathField;\n }\n\n /**\n * MathQuill-shaped facade, so existing `input.mathField.latex()` /\n * `.el()` call sites keep working instead of throwing. Only the members that\n * consumers actually used are provided; MathQuill internals such as\n * `__controller` have no MathLive equivalent and are deliberately absent.\n */\n get mqCompat() {\n return {\n latex: (v) => (v === undefined ? this.latex() : (this.setLatex(v), v)),\n el: () => this.mathField,\n focus: () => this.focus(),\n blur: () => this.blur(),\n };\n }\n\n /** Programmatically replace the content. */\n setLatex(v) {\n if (this.mathField) {\n this.mathField.value = toMathLive(v || '');\n }\n }\n\n clear() {\n if (this.mathField) {\n this.mathField.value = '';\n }\n\n return '';\n }\n\n blur() {\n log('blur mathfield');\n this.mathField && this.mathField.blur();\n }\n\n focus() {\n log('focus mathfield...');\n this.mathField && this.mathField.focus();\n }\n\n /**\n * MathQuill `cmd()` equivalent.\n *\n * Callers pass MathQuill command names (`'\\\\frac'`, `'\\\\sqrt'`, `'^'`, or an\n * array of them). Those must be expanded into latex with `#?` placeholders,\n * otherwise inserting a bare `\\frac` produces no editable slots.\n */\n command(v) {\n log('command: ', v);\n\n if (!this.mathField) {\n return '';\n }\n\n const action = keyToAction({ command: v });\n\n if (action) {\n this.mathField.insert(action.value, { focus: true });\n }\n\n this.mathField.focus();\n\n return this.latex();\n }\n\n /**\n * MathQuill `keystroke()` equivalent.\n *\n * Accepts MathQuill keystroke names (`'Left'`, `'Right'`, `'Backspace'`) as\n * the keypad emits them, and passes anything else through as a MathLive\n * selector.\n */\n keystroke(v) {\n log('keystroke: ', v);\n\n if (!this.mathField) {\n return '';\n }\n\n const selector = KEYSTROKES[v] || v;\n\n try {\n this.mathField.executeCommand(selector);\n } catch (e) {\n log('unknown keystroke/selector \"%s\": %s', v, e && e.message);\n }\n\n this.mathField.focus();\n\n return this.latex();\n }\n\n /** MathQuill `write()` equivalent. Accepts an array, as `cmd()` did. */\n write(v) {\n log('write: ', v);\n\n if (!this.mathField) {\n return '';\n }\n\n const values = Array.isArray(v) ? v : [v];\n\n values.forEach((vv) => this.mathField.insert(vv, { focus: true }));\n this.mathField.focus();\n\n return this.latex();\n }\n\n /**\n * Enter must not insert a line break: math input is single-expression, and\n * the MathQuill version swallowed charCode 13 for the same reason. Newlines\n * are authored explicitly through the newLine embed, not the Enter key.\n */\n onKeyDown = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n }\n };\n\n render() {\n const { className, onFocus, onBlur, onClick } = this.props;\n\n return (\n <Holder\n className={className}\n onFocus={onFocus}\n onBlur={onBlur}\n onClick={onClick}\n onKeyDown={this.onKeyDown}\n ref={this.holderRef}\n />\n );\n }\n}\n\nexport default Input;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"input.js","names":["_react","_interopRequireDefault","require","_propTypes","_styles","_debug","_mathliveInstance","_latexBridge","_callSuper","t","o","e","_getPrototypeOf2","_possibleConstructorReturn2","_isNativeReflectConstruct","Reflect","construct","constructor","apply","Boolean","prototype","valueOf","call","log","debug","Holder","styled","display","width","Input","exports","_React$Component","props","_this","_classCallCheck2","_defineProperty2","onChange","mathField","latex","fromMathLive","getValue","lastEmitted","event","key","preventDefault","holderRef","React","createRef","undefined","_inherits2","_createClass2","value","_componentDidMount","_asyncToGenerator2","_regenerator","mark","_callee","generation","ml","wrap","_context","prev","next","mountGeneration","loadMathLive","sent","current","abrupt","MathfieldElement","macros","getMacros","toMathLive","readOnly","mathVirtualKeyboardPolicy","mathModeSpace","MATH_MODE_SPACE","smartSuperscript","applyShadowStyles","untrackCaret","trackPlaceholderCaret","addEventListener","onInputEdit","replaceChildren","innerRef","stop","componentDidMount","arguments","componentDidUpdate","prevProps","_this$props","componentWillUnmount","removeEventListener","remove","get","_this2","v","setLatex","el","focus","blur","clear","command","action","keyToAction","insert","keystroke","selector","KEYSTROKES","executeCommand","message","write","_this3","values","Array","isArray","forEach","vv","render","_this$props2","className","onFocus","onBlur","onClick","createElement","onKeyDown","ref","Component","PropTypes","string","func","bool","_default"],"sources":["../../src/mf/input.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { styled } from '@mui/material/styles';\nimport debug from 'debug';\nimport {\n loadMathLive,\n getMacros,\n MATH_MODE_SPACE,\n applyShadowStyles,\n trackPlaceholderCaret,\n} from '../mathlive-instance';\nimport { toMathLive, fromMathLive, keyToAction, KEYSTROKES } from '../latex-bridge';\n\nconst log = debug('pie-lib:math-input-mathlive:input');\n\nconst Holder = styled('span')({\n display: 'inline-block',\n '& math-field': {\n display: 'block',\n width: '100%',\n },\n // MathLive ships its own virtual keyboard toggle; pie supplies its own keypad.\n '& math-field::part(virtual-keyboard-toggle)': {\n display: 'none',\n },\n '& math-field::part(menu-toggle)': {\n display: 'none',\n },\n});\n\n/**\n * Editable math field. Drop-in replacement for @pie-lib/math-input's `mq.Input`.\n *\n * Keeps the same imperative surface used by MathInput's keypad\n * (`write`, `command`, `keystroke`, `clear`, `focus`, `blur`) so callers do not\n * change, and the same `latex` / `onChange` props.\n */\nexport class Input extends React.Component {\n static propTypes = {\n className: PropTypes.string,\n latex: PropTypes.string,\n onChange: PropTypes.func,\n onClick: PropTypes.func,\n onFocus: PropTypes.func,\n onBlur: PropTypes.func,\n readOnly: PropTypes.bool,\n innerRef: PropTypes.func,\n };\n\n constructor(props) {\n super(props);\n this.holderRef = React.createRef();\n // Tracks the last latex we emitted, so prop echoes don't reset the cursor.\n this.lastEmitted = undefined;\n }\n\n async componentDidMount() {\n // MathLive loads asynchronously, so this method resumes after an await and\n // has to know whether it is still the current mount. React StrictMode calls\n // mount -> unmount -> mount on the SAME instance in dev, so a boolean\n // \"unmounted\" flag would latch and block the remount from ever creating a\n // field. A generation counter identifies the live mount instead: only the\n // newest one proceeds, and a real unmount invalidates all pending ones.\n const generation = (this.mountGeneration = (this.mountGeneration || 0) + 1);\n const ml = await loadMathLive();\n\n if (generation !== this.mountGeneration || !ml || !this.holderRef.current || this.mathField) {\n return;\n }\n\n this.mathField = new ml.MathfieldElement({ macros: getMacros() });\n this.mathField.value = toMathLive(this.props.latex || '');\n\n if (this.props.readOnly) {\n this.mathField.readOnly = true;\n }\n\n // pie drives input through its own keypad, so suppress MathLive's.\n this.mathField.mathVirtualKeyboardPolicy = 'manual';\n // Without this the spacebar does nothing: MathLive's mathModeSpace\n // defaults to an empty string.\n this.mathField.mathModeSpace = MATH_MODE_SPACE;\n // After the exponent key the cursor must stay in the exponent until it is moved\n // MathLive's `smartSuperscript` (on by\n // default) jumps out of an empty superscript after a single digit, which breaks\n // typing x^23 or 10^6 and is inconsistent with non-digit exponents.\n this.mathField.smartSuperscript = false;\n\n // The mathfield renders in shadow DOM, so page CSS cannot reach it - the\n // stretchy-accent fix has to be injected there directly.\n applyShadowStyles(this.mathField);\n\n // A selected `\\placeholder{}` gets no MathLive caret; draw one.\n this.untrackCaret = trackPlaceholderCaret(this.mathField);\n\n this.mathField.addEventListener('input', this.onInputEdit);\n\n // Belt and braces: drop anything a previous mount may have left behind.\n this.holderRef.current.replaceChildren(this.mathField);\n\n if (this.props.innerRef) {\n this.props.innerRef(this);\n }\n }\n\n componentDidUpdate(prevProps) {\n if (!this.mathField) {\n return;\n }\n\n const { latex, readOnly } = this.props;\n\n if (readOnly !== prevProps.readOnly) {\n this.mathField.readOnly = !!readOnly;\n }\n\n // Only push the prop back into the field when it genuinely differs from\n // what the field already holds. This is the analogue of the old\n // shouldComponentUpdate latex-equality guard and prevents cursor thrash.\n if (latex !== undefined && latex !== null && latex !== this.lastEmitted) {\n const next = toMathLive(latex);\n\n if (next !== this.mathField.value) {\n this.mathField.value = next;\n }\n }\n }\n\n componentWillUnmount() {\n // Invalidate any mount still awaiting the MathLive load, so it does not\n // append a field into a holder that is going away.\n this.mountGeneration = (this.mountGeneration || 0) + 1;\n\n if (this.untrackCaret) {\n this.untrackCaret();\n this.untrackCaret = undefined;\n }\n\n if (this.mathField) {\n this.mathField.removeEventListener('input', this.onInputEdit);\n this.mathField.remove();\n this.mathField = undefined;\n }\n\n if (this.props.innerRef) {\n this.props.innerRef(null);\n }\n }\n\n onInputEdit = () => {\n const { onChange } = this.props;\n\n if (!this.mathField) {\n return;\n }\n\n const latex = fromMathLive(this.mathField.getValue('latex'));\n\n this.lastEmitted = latex;\n\n if (onChange) {\n onChange(latex);\n }\n };\n\n /** Current latex, in stored (MathQuill-compatible) form. */\n latex() {\n return this.mathField ? fromMathLive(this.mathField.getValue('latex')) : '';\n }\n\n /**\n * The underlying `<math-field>` element, or undefined until MathLive has\n * finished loading. Exposed for callers that need the real element.\n *\n * NOTE: this is NOT a MathQuill field. Code written against\n * `@pie-lib/math-input` often did `input.mathField.latex()`; that shape is\n * provided by `mqCompat` below, and `latex()` on this component is the\n * supported replacement.\n */\n get element() {\n return this.mathField;\n }\n\n /**\n * MathQuill-shaped facade, so existing `input.mathField.latex()` /\n * `.el()` call sites keep working instead of throwing. Only the members that\n * consumers actually used are provided; MathQuill internals such as\n * `__controller` have no MathLive equivalent and are deliberately absent.\n */\n get mqCompat() {\n return {\n latex: (v) => (v === undefined ? this.latex() : (this.setLatex(v), v)),\n el: () => this.mathField,\n focus: () => this.focus(),\n blur: () => this.blur(),\n };\n }\n\n /** Programmatically replace the content. */\n setLatex(v) {\n if (this.mathField) {\n this.mathField.value = toMathLive(v || '');\n }\n }\n\n clear() {\n if (this.mathField) {\n this.mathField.value = '';\n }\n\n return '';\n }\n\n blur() {\n log('blur mathfield');\n this.mathField && this.mathField.blur();\n }\n\n focus() {\n log('focus mathfield...');\n this.mathField && this.mathField.focus();\n }\n\n /**\n * MathQuill `cmd()` equivalent.\n *\n * Callers pass MathQuill command names (`'\\\\frac'`, `'\\\\sqrt'`, `'^'`, or an\n * array of them). Those must be expanded into latex with `#?` placeholders,\n * otherwise inserting a bare `\\frac` produces no editable slots.\n */\n command(v) {\n log('command: ', v);\n\n if (!this.mathField) {\n return '';\n }\n\n const action = keyToAction({ command: v });\n\n if (action) {\n this.mathField.insert(action.value, { focus: true });\n }\n\n this.mathField.focus();\n\n return this.latex();\n }\n\n /**\n * MathQuill `keystroke()` equivalent.\n *\n * Accepts MathQuill keystroke names (`'Left'`, `'Right'`, `'Backspace'`) as\n * the keypad emits them, and passes anything else through as a MathLive\n * selector.\n */\n keystroke(v) {\n log('keystroke: ', v);\n\n if (!this.mathField) {\n return '';\n }\n\n const selector = KEYSTROKES[v] || v;\n\n try {\n this.mathField.executeCommand(selector);\n } catch (e) {\n log('unknown keystroke/selector \"%s\": %s', v, e && e.message);\n }\n\n this.mathField.focus();\n\n return this.latex();\n }\n\n /** MathQuill `write()` equivalent. Accepts an array, as `cmd()` did. */\n write(v) {\n log('write: ', v);\n\n if (!this.mathField) {\n return '';\n }\n\n const values = Array.isArray(v) ? v : [v];\n\n values.forEach((vv) => this.mathField.insert(vv, { focus: true }));\n this.mathField.focus();\n\n return this.latex();\n }\n\n /**\n * Enter must not insert a line break: math input is single-expression, and\n * the MathQuill version swallowed charCode 13 for the same reason. Newlines\n * are authored explicitly through the newLine embed, not the Enter key.\n */\n onKeyDown = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n }\n };\n\n render() {\n const { className, onFocus, onBlur, onClick } = this.props;\n\n return (\n <Holder\n className={className}\n onFocus={onFocus}\n onBlur={onBlur}\n onClick={onClick}\n onKeyDown={this.onKeyDown}\n ref={this.holderRef}\n />\n );\n }\n}\n\nexport default Input;\n"],"mappings":"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","ignoreList":[]}
package/lib/mf/static.js CHANGED
@@ -26,9 +26,9 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
26
26
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
27
27
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
28
28
  var log = (0, _debug["default"])('pie-lib:math-input-mathlive:static');
29
- var Holder = (0, _styles.styled)('span')(_objectSpread(_objectSpread({
29
+ var Holder = (0, _styles.styled)('span')(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
30
30
  display: 'inline-block'
31
- }, _commonStyles.placeholderStyles), {}, {
31
+ }, _commonStyles.placeholderStyles), _commonStyles.rootIndexStyles), _commonStyles.parallelStyles), {}, {
32
32
  '& math-field': {
33
33
  display: 'inline-block',
34
34
  border: 'none',
@@ -202,10 +202,14 @@ var Static = exports["default"] = /*#__PURE__*/function (_React$Component) {
202
202
  key: "componentDidMount",
203
203
  value: function () {
204
204
  var _componentDidMount = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee() {
205
- var ml;
205
+ var generation, ml;
206
206
  return _regenerator["default"].wrap(function (_context) {
207
207
  while (1) switch (_context.prev = _context.next) {
208
208
  case 0:
209
+ // See the note in mf/input.jsx: a generation counter, not a boolean, so a
210
+ // StrictMode mount -> unmount -> mount on the same instance still ends up
211
+ // with exactly one field.
212
+ generation = this.mountGeneration = (this.mountGeneration || 0) + 1;
209
213
  if (this.isInteractive()) {
210
214
  _context.next = 2;
211
215
  break;
@@ -213,14 +217,16 @@ var Static = exports["default"] = /*#__PURE__*/function (_React$Component) {
213
217
  _context.next = 1;
214
218
  return (0, _mathliveInstance.loadMathLive)();
215
219
  case 1:
216
- this.renderMarkup();
220
+ if (generation === this.mountGeneration) {
221
+ this.renderMarkup();
222
+ }
217
223
  return _context.abrupt("return");
218
224
  case 2:
219
225
  _context.next = 3;
220
226
  return (0, _mathliveInstance.loadMathLive)();
221
227
  case 3:
222
228
  ml = _context.sent;
223
- if (!(!ml || !this.holderRef.current)) {
229
+ if (!(generation !== this.mountGeneration || !ml || !this.holderRef.current || this.mathField)) {
224
230
  _context.next = 4;
225
231
  break;
226
232
  }
@@ -231,11 +237,26 @@ var Static = exports["default"] = /*#__PURE__*/function (_React$Component) {
231
237
  });
232
238
  this.mathField.readOnly = true;
233
239
  this.mathField.mathVirtualKeyboardPolicy = 'manual';
240
+ // Without this the spacebar does nothing: MathLive's mathModeSpace
241
+ // defaults to an empty string.
242
+ this.mathField.mathModeSpace = _mathliveInstance.MATH_MODE_SPACE;
243
+ // Same as the editor: stay in the exponent after a digit (see mf/input.jsx).
244
+ this.mathField.smartSuperscript = false;
234
245
  this.mathField.value = (0, _latexBridge.toMathLive)(this.props.latex);
246
+
247
+ // The mathfield renders in shadow DOM, so page CSS cannot reach it - the
248
+ // stretchy-accent fix has to be injected there directly.
249
+ (0, _mathliveInstance.applyShadowStyles)(this.mathField);
250
+
251
+ // A selected `\placeholder{}` gets no MathLive caret; draw one. Answer
252
+ // blocks are typed into with the same keypad, so they grow placeholders too.
253
+ this.untrackCaret = (0, _mathliveInstance.trackPlaceholderCaret)(this.mathField);
235
254
  this.mathField.addEventListener('input', this.onPromptInput);
236
255
  this.mathField.addEventListener('focusin', this.onPromptFocus);
237
256
  this.mathField.addEventListener('keydown', this.onKeyDown);
238
- this.holderRef.current.appendChild(this.mathField);
257
+
258
+ // Belt and braces: drop anything a previous mount may have left behind.
259
+ this.holderRef.current.replaceChildren(this.mathField);
239
260
  this.createLiveRegion();
240
261
  case 5:
241
262
  case "end":
@@ -263,6 +284,12 @@ var Static = exports["default"] = /*#__PURE__*/function (_React$Component) {
263
284
  }, {
264
285
  key: "componentWillUnmount",
265
286
  value: function componentWillUnmount() {
287
+ // Invalidate any mount still awaiting the MathLive load.
288
+ this.mountGeneration = (this.mountGeneration || 0) + 1;
289
+ if (this.untrackCaret) {
290
+ this.untrackCaret();
291
+ this.untrackCaret = undefined;
292
+ }
266
293
  if (this.mathField) {
267
294
  this.mathField.removeEventListener('input', this.onPromptInput);
268
295
  this.mathField.removeEventListener('focusin', this.onPromptFocus);
@@ -319,6 +346,13 @@ var Static = exports["default"] = /*#__PURE__*/function (_React$Component) {
319
346
  var _this3 = this;
320
347
  return {
321
348
  id: id,
349
+ // MathQuill's inner fields could be focused directly; keep that.
350
+ focus: function focus() {
351
+ if (_this3.mathField) {
352
+ _this3.mathField.focus();
353
+ _this3.focusPrompt(id);
354
+ }
355
+ },
322
356
  latex: function latex(value) {
323
357
  if (!_this3.mathField) {
324
358
  return '';
@@ -344,10 +378,76 @@ var Static = exports["default"] = /*#__PURE__*/function (_React$Component) {
344
378
  return _this4.promptHandle(id);
345
379
  });
346
380
  }
381
+ }, {
382
+ key: "promptContaining",
383
+ value: /** The id of the prompt whose range contains `position`, if any. */
384
+ function promptContaining(position) {
385
+ var _this5 = this;
386
+ if (!this.mathField || typeof position !== 'number') {
387
+ return undefined;
388
+ }
389
+ return (this.mathField.getPrompts() || []).find(function (id) {
390
+ var range = _this5.mathField.getPromptRange(id);
391
+ return range && position >= range[0] && position <= range[1];
392
+ });
393
+ }
394
+
395
+ /**
396
+ * Put a blinking caret inside an answer block.
397
+ *
398
+ * MathLive only makes the caret visible while the field element carries the
399
+ * `ML__focused` class, and it adds that class during a *render*, gated on
400
+ * `isSelectionEditable && hasFocus()`. In a read-only field only prompt
401
+ * interiors are editable, so the two things both have to be true:
402
+ *
403
+ * - the selection must sit inside a prompt, and
404
+ * - a render must run afterwards.
405
+ *
406
+ * Assigning `selection` satisfies the first but not the second - it updates
407
+ * the model without re-rendering, so the class stays off and the caret span
408
+ * remains `visibility: hidden`. Executing any command does trigger the
409
+ * render, and `scrollIntoView` is the one with no other effect: it keeps the
410
+ * caret on screen, which the preceding `focus()` already does anyway.
411
+ *
412
+ * @param {string} [id] prompt to focus; defaults to the first one
413
+ */
414
+ }, {
415
+ key: "focusPrompt",
416
+ value: function focusPrompt(id) {
417
+ if (!this.mathField) {
418
+ return;
419
+ }
420
+ var ids = this.mathField.getPrompts() || [];
421
+ var target = id && ids.indexOf(id) !== -1 ? id : ids[0];
422
+ if (!target) {
423
+ return;
424
+ }
425
+ var range = this.mathField.getPromptRange(target);
426
+ if (!range) {
427
+ return;
428
+ }
429
+ this.mathField.selection = {
430
+ ranges: [[range[0], range[0]]]
431
+ };
432
+ if (typeof this.mathField.executeCommand === 'function') {
433
+ this.mathField.executeCommand('scrollIntoView');
434
+ }
435
+ }
347
436
  }, {
348
437
  key: "focus",
349
438
  value: function focus() {
350
- this.mathField && this.mathField.focus();
439
+ if (!this.mathField) {
440
+ return;
441
+ }
442
+ this.mathField.focus();
443
+
444
+ // A bare focus() leaves the selection outside every prompt, which in a
445
+ // read-only field is not editable - the block looked focused but had no
446
+ // cursor. Clicking a prompt already works, because MathLive's own pointer
447
+ // handling moves the selection and re-renders.
448
+ if (!this.promptContaining(this.mathField.position)) {
449
+ this.focusPrompt();
450
+ }
351
451
  }
352
452
  }, {
353
453
  key: "blur",