@khanacademy/math-input 4.1.0 → 4.2.0

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 (77) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/components/input/math-wrapper.d.ts +1 -1
  3. package/dist/components/input/math-wrapper.js.flow +1 -1
  4. package/dist/components/input/mathquill-instance.d.ts +14 -3
  5. package/dist/components/input/mathquill-instance.js.flow +18 -3
  6. package/dist/components/input/mathquill-types.d.ts +28 -6
  7. package/dist/components/input/mathquill-types.js.flow +31 -7
  8. package/dist/components/key-handlers/handle-arrow.d.ts +3 -0
  9. package/dist/components/{input/key-handlers → key-handlers}/handle-arrow.js.flow +2 -2
  10. package/dist/components/{input/key-handlers → key-handlers}/handle-backspace.d.ts +1 -1
  11. package/dist/components/{input/key-handlers → key-handlers}/handle-backspace.js.flow +1 -1
  12. package/dist/components/key-handlers/handle-exponent.d.ts +3 -0
  13. package/dist/components/{input/key-handlers → key-handlers}/handle-exponent.js.flow +2 -2
  14. package/dist/components/{input/key-handlers → key-handlers}/handle-jump-out.d.ts +2 -2
  15. package/dist/components/{input/key-handlers → key-handlers}/handle-jump-out.js.flow +2 -2
  16. package/dist/components/key-handlers/key-translator.d.ts +4 -0
  17. package/dist/components/{key-translator.js.flow → key-handlers/key-translator.js.flow} +3 -3
  18. package/dist/components/keypad/geometry-page/index.d.ts +2 -1
  19. package/dist/components/keypad/geometry-page/index.js.flow +2 -1
  20. package/dist/components/keypad/index.d.ts +2 -1
  21. package/dist/components/keypad/index.js.flow +2 -1
  22. package/dist/components/keypad/keypad-page-items.d.ts +8 -16
  23. package/dist/components/keypad/keypad-page-items.js.flow +11 -16
  24. package/dist/components/keypad/numbers-page/index.d.ts +2 -1
  25. package/dist/components/keypad/numbers-page/index.js.flow +2 -1
  26. package/dist/components/keypad/operators-page/advanced-relations-buttons.d.ts +2 -1
  27. package/dist/components/keypad/operators-page/advanced-relations-buttons.js.flow +2 -1
  28. package/dist/components/keypad/operators-page/basic-relations-buttons.d.ts +2 -1
  29. package/dist/components/keypad/operators-page/basic-relations-buttons.js.flow +2 -1
  30. package/dist/components/keypad/operators-page/index.d.ts +2 -1
  31. package/dist/components/keypad/operators-page/index.js.flow +2 -1
  32. package/dist/components/keypad/operators-page/logarithms-buttons.d.ts +2 -1
  33. package/dist/components/keypad/operators-page/logarithms-buttons.js.flow +2 -1
  34. package/dist/components/keypad/operators-page/pre-algebra-buttons.d.ts +2 -1
  35. package/dist/components/keypad/operators-page/pre-algebra-buttons.js.flow +2 -1
  36. package/dist/es/index.js +395 -366
  37. package/dist/es/index.js.map +1 -1
  38. package/dist/index.d.ts +3 -1
  39. package/dist/index.js +398 -367
  40. package/dist/index.js.flow +6 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/types.d.ts +1 -0
  43. package/dist/types.js.flow +1 -0
  44. package/package.json +1 -1
  45. package/src/components/input/math-input.tsx +10 -14
  46. package/src/components/input/math-wrapper.ts +23 -49
  47. package/src/components/input/mathquill-helpers.ts +11 -11
  48. package/src/components/input/mathquill-instance.ts +57 -2
  49. package/src/components/input/mathquill-types.ts +37 -7
  50. package/src/components/{input/key-handlers → key-handlers}/handle-arrow.ts +6 -6
  51. package/src/components/{input/key-handlers → key-handlers}/handle-backspace.ts +19 -17
  52. package/src/components/{input/key-handlers → key-handlers}/handle-exponent.ts +8 -5
  53. package/src/components/{input/key-handlers → key-handlers}/handle-jump-out.ts +15 -10
  54. package/src/components/{key-translator.ts → key-handlers/key-translator.ts} +43 -28
  55. package/src/components/keypad/__tests__/Button.test.tsx +51 -0
  56. package/src/components/keypad/__tests__/keypad-button.test.tsx +41 -0
  57. package/src/components/keypad/__tests__/keypad-v2-mathquill.test.tsx +231 -0
  58. package/src/components/keypad/__tests__/keypad-v2.cypress.ts +46 -0
  59. package/src/components/keypad/geometry-page/index.tsx +2 -1
  60. package/src/components/keypad/index.tsx +2 -1
  61. package/src/components/keypad/keypad-mathquill.stories.tsx +15 -23
  62. package/src/components/keypad/keypad-page-items.tsx +10 -19
  63. package/src/components/keypad/numbers-page/index.tsx +2 -1
  64. package/src/components/keypad/operators-page/advanced-relations-buttons.tsx +2 -1
  65. package/src/components/keypad/operators-page/basic-relations-buttons.tsx +2 -1
  66. package/src/components/keypad/operators-page/index.tsx +2 -1
  67. package/src/components/keypad/operators-page/logarithms-buttons.tsx +2 -1
  68. package/src/components/keypad/operators-page/pre-algebra-buttons.tsx +2 -1
  69. package/src/index.ts +6 -1
  70. package/src/types.ts +2 -0
  71. package/tsconfig-build.json +1 -2
  72. package/tsconfig-build.tsbuildinfo +1 -1
  73. package/dist/components/input/__tests__/test-math-wrapper.d.ts +0 -8
  74. package/dist/components/input/__tests__/test-math-wrapper.js.flow +0 -14
  75. package/dist/components/input/key-handlers/handle-arrow.d.ts +0 -3
  76. package/dist/components/input/key-handlers/handle-exponent.d.ts +0 -3
  77. package/dist/components/key-translator.d.ts +0 -4
package/dist/types.d.ts CHANGED
@@ -61,4 +61,5 @@ export type ActiveNodesObj = {
61
61
  export type LayoutProps = {
62
62
  initialBounds: Bound;
63
63
  };
64
+ export type ClickKeyCallback = (key: Key) => void;
64
65
  export {};
@@ -76,3 +76,4 @@ export type ActiveNodesObj = {|
76
76
  export type LayoutProps = {|
77
77
  initialBounds: Bound,
78
78
  |};
79
+ export type ClickKeyCallback = (key: Key) => void;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Khan Academy's new expression editor for the mobile web.",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "4.1.0",
6
+ "version": "4.2.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -87,21 +87,17 @@ class MathInput extends React.Component<Props, State> {
87
87
  componentDidMount() {
88
88
  this._isMounted = true;
89
89
 
90
- this.mathField = new MathWrapper(
91
- this._mathContainer,
92
- {},
93
- {
94
- onCursorMove: (cursor: Cursor) => {
95
- // TODO(charlie): It's not great that there is so much coupling
96
- // between this keypad and the input behavior. We should wrap
97
- // this `MathInput` component in an intermediary component
98
- // that translates accesses on the keypad into vanilla props,
99
- // to make this input keypad-agnostic.
100
- this.props.keypadElement &&
101
- this.props.keypadElement.setCursor(cursor);
102
- },
90
+ this.mathField = new MathWrapper(this._mathContainer, {
91
+ onCursorMove: (cursor: Cursor) => {
92
+ // TODO(charlie): It's not great that there is so much coupling
93
+ // between this keypad and the input behavior. We should wrap
94
+ // this `MathInput` component in an intermediary component
95
+ // that translates accesses on the keypad into vanilla props,
96
+ // to make this input keypad-agnostic.
97
+ this.props.keypadElement &&
98
+ this.props.keypadElement.setCursor(cursor);
103
99
  },
104
- );
100
+ });
105
101
 
106
102
  // NOTE(charlie): MathQuill binds this handler to manage its
107
103
  // drag-to-select behavior. For reasons that I can't explain, the event
@@ -18,58 +18,30 @@ import $ from "jquery";
18
18
 
19
19
  import Key from "../../data/keys";
20
20
  import {Cursor} from "../../types";
21
- import keyTranslator from "../key-translator";
21
+ import handleBackspace from "../key-handlers/handle-backspace";
22
+ import keyTranslator from "../key-handlers/key-translator";
22
23
 
23
- import handleArrow from "./key-handlers/handle-arrow";
24
- import handleBackspace from "./key-handlers/handle-backspace";
25
- import handleExponent from "./key-handlers/handle-exponent";
26
- import handleJumpOut from "./key-handlers/handle-jump-out";
27
24
  import {
28
25
  getCursor,
29
26
  contextForCursor,
30
27
  maybeFindCommand,
31
28
  } from "./mathquill-helpers";
32
- import MQ from "./mathquill-instance";
29
+ import {createMathField, mathQuillInstance} from "./mathquill-instance";
33
30
  import {
34
31
  MathFieldInterface,
35
32
  MathFieldCursor,
36
- MathQuillUpdaterCallback,
33
+ MathFieldUpdaterCallback,
37
34
  } from "./mathquill-types";
38
35
 
39
- function buildNormalFunctionCallback(command: string) {
40
- return function (mathField: MathFieldInterface) {
41
- mathField.write(`\\${command}\\left(\\right)`);
42
- mathField.keystroke("Left");
43
- };
44
- }
45
-
46
- const customKeyTranslator: Record<Key, MathQuillUpdaterCallback> = {
36
+ const mobileKeyTranslator: Record<Key, MathFieldUpdaterCallback> = {
47
37
  ...keyTranslator,
48
- // note(Matthew): in all likelihood, this should be moved
49
- // to the shared key2MathQuill translator. During this refactor
50
- // I tried to keep logic the same while deduplicating code.
51
- // Perseus' Expression MathInput treats this stuff differently
52
- // (or doesn't do anything with them at all), so I kept it that way
38
+ // note(Matthew): our mobile backspace logic is really complicated
39
+ // and for some reason doesn't really work in the desktop experience.
40
+ // So we default to the basic backspace functionality in the
41
+ // key translator and overwrite it with the complicated logic here
42
+ // until we can unify the experiences (if we even want to).
43
+ // https://khanacademy.atlassian.net/browse/LC-906
53
44
  BACKSPACE: handleBackspace,
54
- EXP: handleExponent,
55
- EXP_2: handleExponent,
56
- EXP_3: handleExponent,
57
- FRAC: (mathQuill) => {
58
- mathQuill.cmd("\\frac");
59
- },
60
- JUMP_OUT_PARENTHESES: handleJumpOut,
61
- JUMP_OUT_EXPONENT: handleJumpOut,
62
- JUMP_OUT_BASE: handleJumpOut,
63
- JUMP_INTO_NUMERATOR: handleJumpOut,
64
- JUMP_OUT_NUMERATOR: handleJumpOut,
65
- JUMP_OUT_DENOMINATOR: handleJumpOut,
66
- LEFT: handleArrow,
67
- RIGHT: handleArrow,
68
- LOG: buildNormalFunctionCallback("log"),
69
- LN: buildNormalFunctionCallback("ln"),
70
- SIN: buildNormalFunctionCallback("sin"),
71
- COS: buildNormalFunctionCallback("cos"),
72
- TAN: buildNormalFunctionCallback("tan"),
73
45
  };
74
46
 
75
47
  /**
@@ -78,16 +50,18 @@ const customKeyTranslator: Record<Key, MathQuillUpdaterCallback> = {
78
50
  * from MathQuill changes.
79
51
  */
80
52
  class MathWrapper {
81
- mathField: MathFieldInterface; // MathQuill input
53
+ mathField: MathFieldInterface; // MathQuill MathField input
82
54
  callbacks: any;
83
55
 
84
- constructor(element, options = {}, callbacks = {}) {
85
- this.mathField = MQ.MathField(element, {
86
- // use a span instead of a textarea so that we don't bring up the
87
- // native keyboard on mobile when selecting the input
88
- substituteTextarea: function () {
89
- return document.createElement("span");
90
- },
56
+ constructor(element, callbacks = {}) {
57
+ this.mathField = createMathField(element, () => {
58
+ return {
59
+ // use a span instead of a textarea so that we don't bring up the
60
+ // native keyboard on mobile when selecting the input
61
+ substituteTextarea: function () {
62
+ return document.createElement("span");
63
+ },
64
+ };
91
65
  });
92
66
  this.callbacks = callbacks;
93
67
  }
@@ -119,7 +93,7 @@ class MathWrapper {
119
93
  */
120
94
  pressKey(key: Key): Cursor {
121
95
  const cursor = this.getCursor();
122
- const translator = customKeyTranslator[key];
96
+ const translator = mobileKeyTranslator[key];
123
97
 
124
98
  if (translator) {
125
99
  translator(this.mathField, key);
@@ -173,7 +147,7 @@ class MathWrapper {
173
147
  // Unless that would leave us mid-command, in which case, we
174
148
  // need to adjust and place the cursor inside the parens
175
149
  // following the command.
176
- const command = maybeFindCommand(cursor[MQ.L]);
150
+ const command = maybeFindCommand(cursor[mathQuillInstance.L]);
177
151
  if (command && command.endNode) {
178
152
  // NOTE(charlie): endNode should definitely be \left(.
179
153
  cursor.insLeftOf(command.endNode);
@@ -1,5 +1,5 @@
1
1
  import {CursorContext} from "./cursor-contexts";
2
- import MQ from "./mathquill-instance";
2
+ import {mathQuillInstance} from "./mathquill-instance";
3
3
  import {
4
4
  MathFieldActionType,
5
5
  MathFieldCursor,
@@ -126,8 +126,8 @@ export function isInsideLogIndex(cursor: MathFieldCursor): boolean {
126
126
 
127
127
  export function isInsideEmptyNode(cursor: MathFieldCursor): boolean {
128
128
  return (
129
- cursor[MQ.L] === MathFieldActionType.MQ_END &&
130
- cursor[MQ.R] === MathFieldActionType.MQ_END
129
+ cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END &&
130
+ cursor[mathQuillInstance.R] === MathFieldActionType.MQ_END
131
131
  );
132
132
  }
133
133
 
@@ -191,7 +191,7 @@ export function maybeFindCommand(initialNode) {
191
191
  break;
192
192
  }
193
193
 
194
- node = node[MQ.L];
194
+ node = node[mathQuillInstance.L];
195
195
  }
196
196
 
197
197
  // If we hit the start of a command, then grab the rest of it by
@@ -199,7 +199,7 @@ export function maybeFindCommand(initialNode) {
199
199
  // with its terminal node.
200
200
  if (startNode) {
201
201
  // Next, iterate from the start to the right.
202
- node = initialNode[MQ.R];
202
+ node = initialNode[mathQuillInstance.R];
203
203
  while (node !== 0) {
204
204
  const ctrlSeq = node.ctrlSeq.trim();
205
205
  if (commandCharRegex.test(ctrlSeq)) {
@@ -213,7 +213,7 @@ export function maybeFindCommand(initialNode) {
213
213
  break;
214
214
  }
215
215
 
216
- node = node[MQ.R];
216
+ node = node[mathQuillInstance.R];
217
217
  }
218
218
  if (validCommands.includes(name)) {
219
219
  return {name, startNode, endNode};
@@ -235,19 +235,19 @@ export function maybeFindCommand(initialNode) {
235
235
  * name (`name`) of the command
236
236
  */
237
237
  export function maybeFindCommandBeforeParens(leftParenNode) {
238
- return maybeFindCommand(leftParenNode[MQ.L]);
238
+ return maybeFindCommand(leftParenNode[mathQuillInstance.L]);
239
239
  }
240
240
 
241
241
  export function contextForCursor(cursor: MathFieldCursor): CursorContext {
242
242
  // First, try to find any fraction to the right, unimpeded.
243
243
  let visitor = cursor;
244
- while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
245
- if (isFraction(visitor[MQ.R])) {
244
+ while (visitor[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
245
+ if (isFraction(visitor[mathQuillInstance.R])) {
246
246
  return CursorContext.BEFORE_FRACTION;
247
- } else if (!isLeaf(visitor[MQ.R])) {
247
+ } else if (!isLeaf(visitor[mathQuillInstance.R])) {
248
248
  break;
249
249
  }
250
- visitor = visitor[MQ.R];
250
+ visitor = visitor[mathQuillInstance.R];
251
251
  }
252
252
 
253
253
  // If that didn't work, check if the parent or grandparent is a special
@@ -1,5 +1,60 @@
1
1
  import MathQuill from "mathquill";
2
2
 
3
- import {MathQuillInterface} from "./mathquill-types";
3
+ import {MathQuillInterface, MathFieldConfig} from "./mathquill-types";
4
4
 
5
- export default MathQuill.getInterface(2) as MathQuillInterface;
5
+ // We only need one MathQuill instance (referred to as MQ in the docs)
6
+ // and that contains some MQ constants and the MathField constructor
7
+ export const mathQuillInstance = MathQuill.getInterface(
8
+ 2,
9
+ ) as MathQuillInterface;
10
+
11
+ function createBaseConfig(): MathFieldConfig {
12
+ return {
13
+ // LaTeX commands that, when typed, are immediately replaced by the
14
+ // appropriate symbol. This does not include ln, log, or any of the
15
+ // trig functions; those are always interpreted as commands.
16
+ autoCommands: "pi theta phi sqrt nthroot",
17
+
18
+ // Pop the cursor out of super/subscripts on arithmetic operators
19
+ // or (in)equalities.
20
+ charsThatBreakOutOfSupSub: "+-*/=<>≠≤≥",
21
+
22
+ // Prevent excessive super/subscripts or fractions from being
23
+ // created without operands, e.g. when somebody holds down a key
24
+ supSubsRequireOperand: true,
25
+
26
+ // The name of this option is somewhat misleading, as tabbing in
27
+ // MathQuill breaks you out of a nested context (fraction/script)
28
+ // if you're in one, but moves focus to the next input if you're
29
+ // not. Spaces (with this option enabled) are just ignored in the
30
+ // latter case.
31
+ //
32
+ // TODO(alex): In order to allow inputting mixed numbers, we will
33
+ // have to accept spaces in certain cases. The desired behavior is
34
+ // still to escape nested contexts if currently in one, but to
35
+ // insert a space if not (we don't expect mixed numbers in nested
36
+ // contexts). We should also limit to one consecutive space.
37
+ spaceBehavesLikeTab: true,
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Creates a new [MathField](http://docs.mathquill.com/en/latest/Api_Methods/#mqmathfieldhtml_element-config)
43
+ * instance within the given `container`.
44
+ *
45
+ * An optional configuration callback can be provided to customize
46
+ * the created MathField. A default configuration is passed to this
47
+ * callback which can then be adjusted as needed. The configuration
48
+ * returned from this callback is used to create the MathField.
49
+ * This allows callers to do minimal configuration as only configs
50
+ * that vary from the default need to be provided.
51
+ */
52
+ export function createMathField(
53
+ container: HTMLDivElement | HTMLSpanElement,
54
+ configCallback?: (baseConfig: MathFieldConfig) => MathFieldConfig,
55
+ ) {
56
+ const baseConfig = createBaseConfig();
57
+ const config = configCallback ? configCallback(baseConfig) : baseConfig;
58
+
59
+ return mathQuillInstance.MathField(container, config);
60
+ }
@@ -3,22 +3,52 @@ import Key from "../../data/keys";
3
3
  export interface MathQuillInterface {
4
4
  L: "L";
5
5
  R: "R";
6
- MathField: (mount: HTMLDivElement, options: any) => MathFieldInterface;
6
+ MathField: (
7
+ mount: HTMLDivElement | HTMLSpanElement,
8
+ config: MathFieldConfig,
9
+ ) => MathFieldInterface;
7
10
  }
8
11
 
12
+ type MathQuillDir = "L" | "R";
13
+
14
+ export type MathFieldConfig = {
15
+ spaceBehavesLikeTab?: boolean;
16
+ leftRightIntoCmdGoes?: string;
17
+ restrictMismatchedBrackets?: boolean;
18
+ sumStartsWithNEquals?: boolean;
19
+ supSubsRequireOperand?: boolean;
20
+ charsThatBreakOutOfSupSub?: string;
21
+ autoSubscriptNumerals?: boolean;
22
+ autoCommands?: string;
23
+ autoOperatorNames?: string;
24
+ maxDepth?: number;
25
+ substituteTextarea?: () => HTMLElement;
26
+ handlers?: {
27
+ edit?: (mathField: MathFieldInterface) => void;
28
+ upOutOf?: (mathField: MathFieldInterface) => void;
29
+ moveOutOf?: (dir: MathQuillDir, mathField: MathFieldInterface) => void;
30
+ };
31
+ };
32
+
9
33
  export interface MathFieldInterface {
34
+ // Puts the focus on the editable field.
35
+ // http://docs.mathquill.com/en/latest/Api_Methods/#focus
36
+ focus: () => MathFieldInterface;
37
+ // Removes focus from the editable field.
38
+ // http://docs.mathquill.com/en/latest/Api_Methods/#blur
39
+ blur: () => MathFieldInterface;
10
40
  // Write LaTeX
11
41
  // https://docs.mathquill.com/en/latest/Api_Methods/#writelatex_string
12
- write: (input: string) => void;
42
+ write: (input: string) => MathFieldInterface;
13
43
  // Enter a LaTeX command
14
44
  // https://docs.mathquill.com/en/latest/Api_Methods/#cmdlatex_string
15
- cmd: (input: string) => void;
45
+ cmd: (input: string) => MathFieldInterface;
16
46
  // Simulates keystrokes given a string like "Ctrl-Home Del"
17
47
  // https://docs.mathquill.com/en/latest/Api_Methods/#keystrokekeys
18
- keystroke: (input: string) => void;
48
+ keystroke: (input: string) => MathFieldInterface;
19
49
  // Simulates typing text, one character at a time
20
50
  // https://docs.mathquill.com/en/latest/Api_Methods/#typedtexttext
21
- typedText: (input: string) => void;
51
+ typedText: (input: string) => MathFieldInterface;
22
52
  // () => {}: Gets the contents as LaTeX
23
53
  // (string) => {}: Sets the contents as LaTeX
24
54
  // https://docs.mathquill.com/en/latest/Api_Methods/#latex
@@ -49,7 +79,7 @@ export enum MathFieldActionType {
49
79
  // we reach into the internals to get it
50
80
  export type MathFieldCursor = any;
51
81
 
52
- export type MathQuillUpdaterCallback = (
53
- mathQuill: MathFieldInterface,
82
+ export type MathFieldUpdaterCallback = (
83
+ mathField: MathFieldInterface,
54
84
  key: Key,
55
85
  ) => void;
@@ -1,15 +1,15 @@
1
- import Key from "../../../data/keys";
1
+ import Key from "../../data/keys";
2
2
  import {
3
3
  maybeFindCommand,
4
4
  maybeFindCommandBeforeParens,
5
5
  getCursor,
6
- } from "../mathquill-helpers";
7
- import MQ from "../mathquill-instance";
6
+ } from "../input/mathquill-helpers";
7
+ import {mathQuillInstance} from "../input/mathquill-instance";
8
8
  import {
9
9
  MathFieldInterface,
10
10
  MathFieldActionType,
11
11
  MathFieldCursor,
12
- } from "../mathquill-types";
12
+ } from "../input/mathquill-types";
13
13
 
14
14
  function handleLeftArrow(
15
15
  mathField: MathFieldInterface,
@@ -25,7 +25,7 @@ function handleLeftArrow(
25
25
  // the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
26
26
  // the nodes to the left of our grandparent comprise a valid function
27
27
  // name.
28
- if (cursor[MQ.L] === MathFieldActionType.MQ_END) {
28
+ if (cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END) {
29
29
  const parent = cursor.parent;
30
30
  const grandparent = parent.parent;
31
31
  if (grandparent.ctrlSeq === "\\left(") {
@@ -45,7 +45,7 @@ function handleRightArrow(
45
45
  mathField: MathFieldInterface,
46
46
  cursor: MathFieldCursor,
47
47
  ) {
48
- const command = maybeFindCommand(cursor[MQ.R]);
48
+ const command = maybeFindCommand(cursor[mathQuillInstance.R]);
49
49
  if (command) {
50
50
  // Similarly, if a function is to our right, then we need to place
51
51
  // the cursor at the start of its parenthetical content, which is
@@ -8,19 +8,20 @@ import {
8
8
  selectNode,
9
9
  getCursor,
10
10
  maybeFindCommandBeforeParens,
11
- } from "../mathquill-helpers";
12
- import MQ from "../mathquill-instance";
11
+ } from "../input/mathquill-helpers";
12
+ import {mathQuillInstance} from "../input/mathquill-instance";
13
13
  import {
14
14
  MathFieldActionType,
15
15
  MathFieldInterface,
16
16
  MathFieldCursor,
17
- } from "../mathquill-types";
17
+ } from "../input/mathquill-types";
18
18
 
19
19
  function handleBackspaceInNthRoot(
20
20
  mathField: MathFieldInterface,
21
21
  cursor: MathFieldCursor,
22
22
  ) {
23
- const isAtLeftEnd = cursor[MQ.L] === MathFieldActionType.MQ_END;
23
+ const isAtLeftEnd =
24
+ cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END;
24
25
 
25
26
  const isRootEmpty = isInsideEmptyNode(cursor.parent.parent.blocks[0].ends);
26
27
 
@@ -46,7 +47,7 @@ function handleBackspaceInRootIndex(
46
47
 
47
48
  const grandparent = cursor.parent.parent;
48
49
  const latex = grandparent.latex();
49
- const reinsertionPoint = grandparent[MQ.L];
50
+ const reinsertionPoint = grandparent[mathQuillInstance.L];
50
51
 
51
52
  selectNode(grandparent, cursor);
52
53
 
@@ -68,13 +69,13 @@ function handleBackspaceInRootIndex(
68
69
 
69
70
  // Adjust the cursor to be to the left the sqrt.
70
71
  if (reinsertionPoint === MathFieldActionType.MQ_END) {
71
- mathField.moveToDirEnd(MQ.L);
72
+ mathField.moveToDirEnd(mathQuillInstance.L);
72
73
  } else {
73
74
  cursor.insRightOf(reinsertionPoint);
74
75
  }
75
76
  }
76
77
  } else {
77
- if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
78
+ if (cursor[mathQuillInstance.L] !== MathFieldActionType.MQ_END) {
78
79
  // If the cursor is not at the leftmost position inside the
79
80
  // root's index, delete a character.
80
81
  mathField.keystroke("Backspace");
@@ -97,8 +98,8 @@ function handleBackspaceInLogIndex(
97
98
  cursor.insLeftOf(command?.startNode);
98
99
  cursor.startSelection();
99
100
 
100
- if (grandparent[MQ.R] !== MathFieldActionType.MQ_END) {
101
- cursor.insRightOf(grandparent[MQ.R]);
101
+ if (grandparent[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
102
+ cursor.insRightOf(grandparent[mathQuillInstance.R]);
102
103
  } else {
103
104
  cursor.insRightOf(grandparent);
104
105
  }
@@ -106,7 +107,8 @@ function handleBackspaceInLogIndex(
106
107
  cursor.select();
107
108
  cursor.endSelection();
108
109
 
109
- const isLogBodyEmpty = grandparent[MQ.R].contentjQ.text() === "";
110
+ const isLogBodyEmpty =
111
+ grandparent[mathQuillInstance.R].contentjQ.text() === "";
110
112
 
111
113
  if (isLogBodyEmpty) {
112
114
  // If there's no content inside the log's parens then delete the
@@ -127,8 +129,8 @@ function handleBackspaceOutsideParens(cursor: MathFieldCursor) {
127
129
  // (x+1)| => |(x+1)|
128
130
  // \log(x+1)| => |\log(x+1)|
129
131
 
130
- const leftNode = cursor[MQ.L];
131
- const rightNode = cursor[MQ.R];
132
+ const leftNode = cursor[mathQuillInstance.L];
133
+ const rightNode = cursor[mathQuillInstance.R];
132
134
  const command = maybeFindCommandBeforeParens(leftNode);
133
135
 
134
136
  if (command && command.startNode) {
@@ -179,7 +181,7 @@ function handleBackspaceInsideParens(
179
181
  // - \log(|x+1) => |\log(x+1)|
180
182
  // - \log(|) => |
181
183
 
182
- if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
184
+ if (cursor[mathQuillInstance.L] !== MathFieldActionType.MQ_END) {
183
185
  // This command contains math and there's some math to
184
186
  // the left of the cursor that we should delete normally
185
187
  // before doing anything special.
@@ -193,12 +195,12 @@ function handleBackspaceInsideParens(
193
195
  // has a subscript as is the case in log_n then move the cursor into
194
196
  // the subscript, e.g. \log_{5}(|x+1) => \log_{5|}(x+1)
195
197
 
196
- if (grandparent[MQ.L].sub) {
198
+ if (grandparent[mathQuillInstance.L].sub) {
197
199
  // if there is a subscript
198
- if (grandparent[MQ.L].sub.jQ.text()) {
200
+ if (grandparent[mathQuillInstance.L].sub.jQ.text()) {
199
201
  // and it contains text
200
202
  // move the cursor to the right end of the subscript
201
- cursor.insAtRightEnd(grandparent[MQ.L].sub);
203
+ cursor.insAtRightEnd(grandparent[mathQuillInstance.L].sub);
202
204
  return;
203
205
  }
204
206
  }
@@ -238,7 +240,7 @@ function handleBackspace(mathField: MathFieldInterface) {
238
240
  if (!cursor.selection) {
239
241
  const parent = cursor.parent;
240
242
  const grandparent = parent.parent;
241
- const leftNode = cursor[MQ.L];
243
+ const leftNode = cursor[mathQuillInstance.L];
242
244
 
243
245
  if (isFraction(leftNode)) {
244
246
  selectNode(leftNode, cursor);
@@ -1,7 +1,10 @@
1
- import Key from "../../../data/keys";
2
- import {getCursor} from "../mathquill-helpers";
3
- import MQ from "../mathquill-instance";
4
- import {MathFieldInterface, MathFieldActionType} from "../mathquill-types";
1
+ import Key from "../../data/keys";
2
+ import {getCursor} from "../input/mathquill-helpers";
3
+ import {mathQuillInstance} from "../input/mathquill-instance";
4
+ import {
5
+ MathFieldInterface,
6
+ MathFieldActionType,
7
+ } from "../input/mathquill-types";
5
8
 
6
9
  const ArithmeticOperators = ["+", "-", "\\cdot", "\\times", "\\div"];
7
10
  const EqualityOperators = ["=", "\\neq", "<", "\\leq", ">", "\\geq"];
@@ -16,7 +19,7 @@ export default function handleExponent(
16
19
  // parentheses and apply the exponent to that.
17
20
  const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
18
21
 
19
- const precedingNode = cursor[MQ.L];
22
+ const precedingNode = cursor[mathQuillInstance.L];
20
23
  const shouldPrefixWithParens =
21
24
  precedingNode === MathFieldActionType.MQ_END ||
22
25
  invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
@@ -1,13 +1,16 @@
1
- import Key from "../../../data/keys";
2
- import {CursorContext} from "../cursor-contexts";
1
+ import Key from "../../data/keys";
2
+ import {CursorContext} from "../input/cursor-contexts";
3
3
  import {
4
4
  isFraction,
5
5
  isParens,
6
6
  contextForCursor,
7
7
  getCursor,
8
- } from "../mathquill-helpers";
9
- import MQ from "../mathquill-instance";
10
- import {MathFieldInterface, MathFieldActionType} from "../mathquill-types";
8
+ } from "../input/mathquill-helpers";
9
+ import {mathQuillInstance} from "../input/mathquill-instance";
10
+ import {
11
+ MathFieldInterface,
12
+ MathFieldActionType,
13
+ } from "../input/mathquill-types";
11
14
 
12
15
  const KeysForJumpContext = {
13
16
  [CursorContext.IN_PARENS]: "JUMP_OUT_PARENTHESES",
@@ -46,11 +49,13 @@ function handleJumpOut(mathField: MathFieldInterface, key: Key): void {
46
49
  // Find the nearest fraction to the right of the cursor.
47
50
  let fractionNode;
48
51
  let visitor = cursor;
49
- while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
50
- if (isFraction(visitor[MQ.R])) {
51
- fractionNode = visitor[MQ.R];
52
+ while (
53
+ visitor[mathQuillInstance.R] !== MathFieldActionType.MQ_END
54
+ ) {
55
+ if (isFraction(visitor[mathQuillInstance.R])) {
56
+ fractionNode = visitor[mathQuillInstance.R];
52
57
  }
53
- visitor = visitor[MQ.R];
58
+ visitor = visitor[mathQuillInstance.R];
54
59
  }
55
60
 
56
61
  // Jump into it!
@@ -82,7 +87,7 @@ function handleJumpOut(mathField: MathFieldInterface, key: Key): void {
82
87
  // Navigate right once more, if we're right before parens. This
83
88
  // is to handle the standard case in which the subscript is the
84
89
  // base of a custom log.
85
- if (isParens(cursor[MQ.R])) {
90
+ if (isParens(cursor[mathQuillInstance.R])) {
86
91
  mathField.keystroke("Right");
87
92
  }
88
93
  break;