@pie-lib/math-input-mathlive 1.1.5-beta.1 → 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/lib/__tests__/composites.test.js +255 -0
  2. package/lib/__tests__/drop-in-compat.test.js +133 -0
  3. package/lib/__tests__/embedded-fonts.test.js +121 -0
  4. package/lib/__tests__/index.test.js +118 -0
  5. package/lib/__tests__/input-imperative.test.js +155 -0
  6. package/lib/__tests__/keypad-label.test.js +231 -0
  7. package/lib/__tests__/keypad-render.test.js +206 -0
  8. package/lib/__tests__/latex-bridge.test.js +386 -0
  9. package/lib/__tests__/mathlive-instance.test.js +419 -0
  10. package/lib/__tests__/mount-race.test.js +218 -0
  11. package/lib/__tests__/static-prompts.test.js +405 -0
  12. package/lib/__tests__/tmp-markup.test.js +26 -0
  13. package/lib/keypad/index.js +36 -12
  14. package/lib/keypad/index.js.map +1 -1
  15. package/lib/latex-bridge.js +159 -4
  16. package/lib/latex-bridge.js.map +1 -1
  17. package/lib/mathlive-instance.js +21 -28
  18. package/lib/mathlive-instance.js.map +1 -1
  19. package/lib/mf/common-styles.js +17 -2
  20. package/lib/mf/common-styles.js.map +1 -1
  21. package/lib/mf/index.js +6 -0
  22. package/lib/mf/index.js.map +1 -1
  23. package/lib/mf/input.js +5 -0
  24. package/lib/mf/input.js.map +1 -1
  25. package/lib/mf/static.js +4 -2
  26. package/lib/mf/static.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/__tests__/composites.test.jsx +220 -0
  29. package/src/__tests__/drop-in-compat.test.jsx +112 -0
  30. package/src/__tests__/index.test.jsx +109 -0
  31. package/src/__tests__/input-imperative.test.jsx +144 -0
  32. package/src/__tests__/keypad-label.test.jsx +284 -0
  33. package/src/__tests__/keypad-render.test.jsx +123 -0
  34. package/src/__tests__/latex-bridge.test.js +389 -0
  35. package/src/__tests__/mathlive-instance.test.js +418 -0
  36. package/src/__tests__/mount-race.test.jsx +142 -0
  37. package/src/__tests__/static-prompts.test.jsx +364 -0
  38. package/src/keypad/index.jsx +18 -3
  39. package/src/latex-bridge.js +171 -4
  40. package/src/mathlive-instance.js +27 -29
  41. package/src/mf/common-styles.js +19 -0
  42. package/src/mf/index.js +2 -0
  43. package/src/mf/input.jsx +5 -0
  44. package/src/mf/static.jsx +4 -1
  45. package/lib/fonts/embedded.js +0 -120
  46. package/lib/fonts/index.js +0 -81
  47. package/lib/fonts/index.js.map +0 -1
  48. package/scripts/generate-embedded-fonts.js +0 -94
  49. package/src/fonts/embedded.js +0 -116
  50. package/src/fonts/index.js +0 -71
@@ -1,7 +1,6 @@
1
1
  import debug from 'debug';
2
2
  import { NEWLINE_EMBED, toMathLive, withVisibleEmptySlots } from './latex-bridge';
3
- import { registerEmbeddedFonts } from './fonts';
4
- import { ROOT_INDEX_CSS } from './mf/common-styles';
3
+ import { ROOT_INDEX_CSS, PARALLEL_CSS } from './mf/common-styles';
5
4
 
6
5
  const log = debug('pie-lib:math-input-mathlive:instance');
7
6
 
@@ -49,7 +48,7 @@ const absoluteFontsDirectory = (dir) => {
49
48
  };
50
49
 
51
50
  /**
52
- * Last-resort CDN for the KaTeX fonts.
51
+ * Version-pinned CDN fallback for the KaTeX fonts.
53
52
  *
54
53
  * Some symbols are composed from Private Use Area glyphs that exist only in
55
54
  * those fonts: `\\neq` is U+E020 (a negation slash) overlapped on `=`, and
@@ -57,10 +56,9 @@ const absoluteFontsDirectory = (dir) => {
57
56
  * an arbitrary glyph for U+E020, so those keys render as garbage rather than
58
57
  * simply falling back to a plainer face.
59
58
  *
60
- * The fonts normally come from inside this package (see `./fonts`), so this URL
61
- * is only reached on a browser without the FontFace API, where MathLive has to
62
- * fetch the woff2 files itself. The version comes from MathLive, so the fonts
63
- * always match the engine.
59
+ * The version comes from MathLive itself, so the fonts always match the engine.
60
+ * Hosts that would rather not depend on a third party should serve the fonts and
61
+ * call `configureFonts('/their/path')`, or pass `null` to opt out.
64
62
  */
65
63
  const FALLBACK_MATHLIVE_VERSION = '0.110.0';
66
64
 
@@ -74,17 +72,15 @@ const cdnFontsDirectory = () => {
74
72
  /**
75
73
  * Tell the package where the MathLive fonts are served from.
76
74
  *
77
- * Optional: by default the fonts come from inside this package (see `./fonts`),
78
- * so nothing has to be served or configured. Call this before `loadMathLive()`
79
- * to point MathLive at your own copy instead - worth doing if the host already
80
- * serves the KaTeX woff2 files and would rather not carry them twice.
75
+ * Call before `loadMathLive()`.
81
76
  *
82
- * - a path/URL: served by you; the embedded fonts are not registered
83
- * - `null`: skip font loading entirely; note `\\neq`, `\\nsim` and `\\ncong`
84
- * then render incorrectly, being built from Private Use Area
85
- * glyphs that only these fonts have
86
- * - not called: the embedded fonts, with the CDN as a fallback for browsers
87
- * without the FontFace API
77
+ * - a path/URL: served by you, no third-party request
78
+ * - `null`: skip font loading; note `\\neq`, `\\nsim` and `\\ncong` then
79
+ * render incorrectly, being built from Private Use Area glyphs
80
+ * - not called: falls back to a version-pinned CDN
81
+ *
82
+ * The fonts ship inside the `mathlive` package (`node_modules/mathlive/fonts`)
83
+ * ready to copy into whatever the host app serves statically.
88
84
  *
89
85
  * @param {string|null} [dir]
90
86
  */
@@ -120,6 +116,9 @@ export const PIE_MACROS = {
120
116
  // Argument-less symbols. Atomic is correct here: backspace should remove the
121
117
  // whole glyph, and there is nothing to type into.
122
118
  parallelogram: '\\htmlData{pie-macro=parallelogram}{\\unicode{"25B1}}',
119
+ // Same glyph as the built-in `\\parallel` (U+2225), tagged so it can be sized -
120
+ // see `parallelStyles`.
121
+ parallel: '\\htmlData{pie-macro=parallel}{\\unicode{"2225}}',
123
122
  napprox: '\\not\\approx',
124
123
  nsim: '\\not\\sim',
125
124
  ncong: '\\not\\cong',
@@ -167,22 +166,18 @@ let loadWarned = false;
167
166
 
168
167
  /** Apply post-load configuration exactly once. */
169
168
  const configureLoaded = () => {
170
- // No host path configured: use the fonts that ship inside this package. Once
171
- // they are in `document.fonts`, MathLive's own loader short-circuits and never
172
- // requests a woff2 - so math renders offline and under a CSP that allows no
173
- // font origin at all.
174
- if (fontsDirectory === undefined && !registerEmbeddedFonts()) {
169
+ // Always replace MathLive's relative `'./fonts/'` default: it throws
170
+ // "Invalid base URL" when bundled. Use the host's copy if one was configured,
171
+ // otherwise the version-pinned CDN.
172
+ if (fontsDirectory === undefined) {
175
173
  log(
176
- 'embedded fonts unavailable (no FontFace API) - falling back to the CDN (%s). ' +
177
- 'Serve the fonts yourself and call configureFonts("/path/to/fonts") to avoid the network request.',
174
+ 'no fontsDirectory configured - falling back to the CDN (%s). ' +
175
+ 'Serve the fonts yourself and call configureFonts("/path/to/fonts") to avoid the network request, ' +
176
+ 'or configureFonts(null) to opt out.',
178
177
  cdnFontsDirectory(),
179
178
  );
180
179
  }
181
180
 
182
- // Always replace MathLive's relative `'./fonts/'` default: it throws
183
- // "Invalid base URL" when bundled. The host's copy if one was configured,
184
- // otherwise the CDN, which is now only reached if the embedded fonts could not
185
- // be registered.
186
181
  mathlive.MathfieldElement.fontsDirectory =
187
182
  fontsDirectory === undefined ? cdnFontsDirectory() : absoluteFontsDirectory(fontsDirectory);
188
183
 
@@ -244,7 +239,10 @@ const PLACEHOLDER_CARET_CSS = [
244
239
  // written for static markup in the host page, which cannot cross the shadow
245
240
  // boundary.
246
241
  const SHADOW_CSS =
247
- '.ML__latex .ML__center:has(.ML__stretchy){margin-left:0 !important}' + ROOT_INDEX_CSS + PLACEHOLDER_CARET_CSS;
242
+ '.ML__latex .ML__center:has(.ML__stretchy){margin-left:0 !important}' +
243
+ ROOT_INDEX_CSS +
244
+ PARALLEL_CSS +
245
+ PLACEHOLDER_CARET_CSS;
248
246
 
249
247
  /**
250
248
  * Keep {@link PLACEHOLDER_CARET_CLASS} in step with the selection.
@@ -75,6 +75,24 @@ export const rootIndexStyles = {
75
75
  */
76
76
  export const ROOT_INDEX_CSS = `${ROOT_INDEX_SELECTOR}{font-size:${ROOT_INDEX_FONT_SIZE} !important}`;
77
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
+
78
96
  /**
79
97
  * Superscript/subscript sizing. MathLive follows TeX metrics for scripts, so the
80
98
  * MathQuill-era corrections are gone; the radical index is the one place where a
@@ -82,6 +100,7 @@ export const ROOT_INDEX_CSS = `${ROOT_INDEX_SELECTOR}{font-size:${ROOT_INDEX_FON
82
100
  */
83
101
  export const supsubStyles = {
84
102
  ...rootIndexStyles,
103
+ ...parallelStyles,
85
104
  };
86
105
 
87
106
  /** Empty placeholder boxes (answer blocks / open slots). */
package/src/mf/index.js CHANGED
@@ -7,6 +7,7 @@ import CommonMqStyles, {
7
7
  commonMqKeyboardStyles,
8
8
  longdivStyles,
9
9
  rootIndexStyles,
10
+ parallelStyles,
10
11
  supsubStyles,
11
12
  placeholderStyles,
12
13
  } from './common-styles';
@@ -23,6 +24,7 @@ export {
23
24
  commonMqKeyboardStyles,
24
25
  longdivStyles,
25
26
  rootIndexStyles,
27
+ parallelStyles,
26
28
  supsubStyles,
27
29
  placeholderStyles,
28
30
  };
package/src/mf/input.jsx CHANGED
@@ -80,6 +80,11 @@ export class Input extends React.Component {
80
80
  // Without this the spacebar does nothing: MathLive's mathModeSpace
81
81
  // defaults to an empty string.
82
82
  this.mathField.mathModeSpace = MATH_MODE_SPACE;
83
+ // After the exponent key the cursor must stay in the exponent until it is moved
84
+ // MathLive's `smartSuperscript` (on by
85
+ // default) jumps out of an empty superscript after a single digit, which breaks
86
+ // typing x^23 or 10^6 and is inconsistent with non-digit exponents.
87
+ this.mathField.smartSuperscript = false;
83
88
 
84
89
  // The mathfield renders in shadow DOM, so page CSS cannot reach it - the
85
90
  // stretchy-accent fix has to be injected there directly.
package/src/mf/static.jsx CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  trackPlaceholderCaret,
12
12
  } from '../mathlive-instance';
13
13
  import { toMathLive, fromMathLive, fieldIds } from '../latex-bridge';
14
- import { placeholderStyles, rootIndexStyles } from './common-styles';
14
+ import { placeholderStyles, rootIndexStyles, parallelStyles } from './common-styles';
15
15
 
16
16
  const log = debug('pie-lib:math-input-mathlive:static');
17
17
 
@@ -22,6 +22,7 @@ const Holder = styled('span')({
22
22
  // Readable radical index - display mode renders in the light DOM, so the
23
23
  // shadow-root copy of this rule does not reach it.
24
24
  ...rootIndexStyles,
25
+ ...parallelStyles,
25
26
  '& math-field': {
26
27
  display: 'inline-block',
27
28
  border: 'none',
@@ -101,6 +102,8 @@ export default class Static extends React.Component {
101
102
  // Without this the spacebar does nothing: MathLive's mathModeSpace
102
103
  // defaults to an empty string.
103
104
  this.mathField.mathModeSpace = MATH_MODE_SPACE;
105
+ // Same as the editor: stay in the exponent after a digit (see mf/input.jsx).
106
+ this.mathField.smartSuperscript = false;
104
107
  this.mathField.value = toMathLive(this.props.latex);
105
108
 
106
109
  // The mathfield renders in shadow DOM, so page CSS cannot reach it - the