@khanacademy/math-input 2.0.0 → 4.0.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 (264) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/components/input/__tests__/test-math-wrapper.d.ts +1 -1
  3. package/dist/components/input/__tests__/test-math-wrapper.js.flow +1 -1
  4. package/dist/components/input/key-handlers/handle-arrow.d.ts +3 -0
  5. package/dist/components/input/key-handlers/handle-arrow.js.flow +12 -0
  6. package/dist/components/input/key-handlers/handle-backspace.d.ts +7 -0
  7. package/dist/components/input/key-handlers/handle-backspace.js.flow +14 -0
  8. package/dist/components/input/key-handlers/handle-exponent.d.ts +3 -0
  9. package/dist/components/input/key-handlers/handle-exponent.js.flow +12 -0
  10. package/dist/components/input/key-handlers/handle-jump-out.d.ts +7 -0
  11. package/dist/components/input/key-handlers/handle-jump-out.js.flow +14 -0
  12. package/dist/components/input/math-input.d.ts +1 -1
  13. package/dist/components/input/math-input.js.flow +1 -1
  14. package/dist/components/input/math-wrapper.d.ts +7 -78
  15. package/dist/components/input/math-wrapper.js.flow +16 -78
  16. package/dist/components/input/mathquill-helpers.d.ts +46 -0
  17. package/dist/components/input/mathquill-helpers.js.flow +56 -0
  18. package/dist/components/input/mathquill-instance.d.ts +3 -0
  19. package/dist/components/input/mathquill-instance.js.flow +9 -0
  20. package/dist/components/input/mathquill-types.d.ts +25 -0
  21. package/dist/components/input/mathquill-types.js.flow +34 -0
  22. package/dist/components/key-translator.d.ts +4 -0
  23. package/dist/components/key-translator.js.flow +10 -0
  24. package/dist/components/keypad/button-assets.d.ts +2 -2
  25. package/dist/components/keypad/button-assets.js.flow +2 -2
  26. package/dist/components/keypad/button.d.ts +1 -2
  27. package/dist/components/keypad/button.js.flow +1 -1
  28. package/dist/components/keypad/{pre-algebra-page.d.ts → geometry-page/index.d.ts} +1 -1
  29. package/dist/components/keypad/{pre-algebra-page.js.flow → geometry-page/index.js.flow} +1 -1
  30. package/dist/components/keypad/index.d.ts +5 -4
  31. package/dist/components/keypad/index.js.flow +9 -4
  32. package/dist/components/keypad/keypad-page-items.d.ts +9 -3
  33. package/dist/components/keypad/keypad-page-items.js.flow +9 -3
  34. package/dist/components/keypad/{numeric-input-page.d.ts → numbers-page/index.d.ts} +3 -2
  35. package/dist/components/keypad/numbers-page/index.js.flow +17 -0
  36. package/dist/components/keypad/numbers-page/types.d.ts +4 -0
  37. package/dist/components/keypad/numbers-page/types.js.flow +10 -0
  38. package/dist/components/keypad/operators-page/advanced-relations-buttons.d.ts +7 -0
  39. package/dist/components/keypad/{numeric-input-page.js.flow → operators-page/advanced-relations-buttons.js.flow} +3 -4
  40. package/dist/components/keypad/operators-page/basic-relations-buttons.d.ts +7 -0
  41. package/dist/components/keypad/{trigonometry-page.js.flow → operators-page/basic-relations-buttons.js.flow} +3 -6
  42. package/dist/components/keypad/operators-page/index.d.ts +9 -0
  43. package/dist/components/keypad/operators-page/index.js.flow +17 -0
  44. package/dist/components/keypad/operators-page/logarithms-buttons.d.ts +7 -0
  45. package/dist/components/keypad/operators-page/logarithms-buttons.js.flow +12 -0
  46. package/dist/components/keypad/operators-page/pre-algebra-buttons.d.ts +7 -0
  47. package/dist/components/keypad/operators-page/pre-algebra-buttons.js.flow +12 -0
  48. package/dist/components/keypad/operators-page/types.d.ts +6 -0
  49. package/dist/components/keypad/operators-page/types.js.flow +12 -0
  50. package/dist/components/{compute-layout-parameters.d.ts → keypad-legacy/compute-layout-parameters.d.ts} +1 -1
  51. package/dist/components/{compute-layout-parameters.js.flow → keypad-legacy/compute-layout-parameters.js.flow} +1 -1
  52. package/dist/components/{echo-manager.d.ts → keypad-legacy/echo-manager.d.ts} +2 -11
  53. package/dist/components/{echo-manager.js.flow → keypad-legacy/echo-manager.js.flow} +2 -11
  54. package/dist/components/{expression-keypad.d.ts → keypad-legacy/expression-keypad.d.ts} +3 -4
  55. package/dist/components/{expression-keypad.js.flow → keypad-legacy/expression-keypad.js.flow} +3 -4
  56. package/dist/components/{fraction-keypad.d.ts → keypad-legacy/fraction-keypad.d.ts} +2 -2
  57. package/dist/components/{fraction-keypad.js.flow → keypad-legacy/fraction-keypad.js.flow} +2 -2
  58. package/dist/components/{gesture-manager.d.ts → keypad-legacy/gesture-manager.d.ts} +22 -10
  59. package/dist/components/{gesture-manager.js.flow → keypad-legacy/gesture-manager.js.flow} +28 -13
  60. package/dist/components/{gesture-state-machine.d.ts → keypad-legacy/gesture-state-machine.d.ts} +9 -9
  61. package/dist/components/{gesture-state-machine.js.flow → keypad-legacy/gesture-state-machine.js.flow} +10 -10
  62. package/dist/components/{icon.d.ts → keypad-legacy/icon.d.ts} +1 -1
  63. package/dist/components/{icon.js.flow → keypad-legacy/icon.js.flow} +1 -1
  64. package/dist/components/{keypad-button.d.ts → keypad-legacy/keypad-button.d.ts} +6 -6
  65. package/dist/components/{keypad-button.js.flow → keypad-legacy/keypad-button.js.flow} +7 -7
  66. package/dist/components/{keypad-container.d.ts → keypad-legacy/keypad-container.d.ts} +2 -2
  67. package/dist/components/{keypad-container.js.flow → keypad-legacy/keypad-container.js.flow} +3 -3
  68. package/dist/components/{keypad.d.ts → keypad-legacy/keypad.d.ts} +3 -3
  69. package/dist/components/{keypad.js.flow → keypad-legacy/keypad.js.flow} +3 -3
  70. package/dist/components/{multi-symbol-grid.d.ts → keypad-legacy/multi-symbol-grid.d.ts} +1 -1
  71. package/dist/components/{multi-symbol-grid.js.flow → keypad-legacy/multi-symbol-grid.js.flow} +1 -1
  72. package/dist/components/{multi-symbol-popover.d.ts → keypad-legacy/multi-symbol-popover.d.ts} +1 -1
  73. package/dist/components/{multi-symbol-popover.js.flow → keypad-legacy/multi-symbol-popover.js.flow} +1 -1
  74. package/dist/components/{node-manager.d.ts → keypad-legacy/node-manager.d.ts} +3 -4
  75. package/dist/components/{node-manager.js.flow → keypad-legacy/node-manager.js.flow} +3 -5
  76. package/dist/components/{popover-manager.d.ts → keypad-legacy/popover-manager.d.ts} +1 -1
  77. package/dist/components/{popover-manager.js.flow → keypad-legacy/popover-manager.js.flow} +1 -1
  78. package/dist/components/{popover-state-machine.d.ts → keypad-legacy/popover-state-machine.d.ts} +1 -1
  79. package/dist/components/{popover-state-machine.js.flow → keypad-legacy/popover-state-machine.js.flow} +1 -1
  80. package/dist/components/{provided-keypad.d.ts → keypad-legacy/provided-keypad.d.ts} +1 -1
  81. package/dist/components/{provided-keypad.js.flow → keypad-legacy/provided-keypad.js.flow} +1 -1
  82. package/dist/{store → components/keypad-legacy/store}/actions.d.ts +6 -17
  83. package/dist/{store → components/keypad-legacy/store}/actions.js.flow +7 -22
  84. package/dist/{store → components/keypad-legacy/store}/index.d.ts +0 -1
  85. package/dist/{store → components/keypad-legacy/store}/index.js.flow +0 -1
  86. package/dist/components/keypad-legacy/store/shared.d.ts +7 -0
  87. package/dist/components/keypad-legacy/store/shared.js.flow +14 -0
  88. package/dist/{store → components/keypad-legacy/store}/types.d.ts +5 -15
  89. package/dist/{store → components/keypad-legacy/store}/types.js.flow +5 -15
  90. package/dist/components/keypad-legacy/touchable-keypad-button.d.ts +37 -0
  91. package/dist/components/keypad-legacy/touchable-keypad-button.js.flow +59 -0
  92. package/dist/components/{two-page-keypad.d.ts → keypad-legacy/two-page-keypad.d.ts} +0 -1
  93. package/dist/components/{two-page-keypad.js.flow → keypad-legacy/two-page-keypad.js.flow} +0 -1
  94. package/dist/data/key-configs.d.ts +4 -5
  95. package/dist/data/key-configs.js.flow +3 -6
  96. package/dist/data/keys.d.ts +2 -56
  97. package/dist/data/keys.js.flow +116 -57
  98. package/dist/enums.d.ts +2 -9
  99. package/dist/enums.js.flow +2 -11
  100. package/dist/es/index.js +6393 -5116
  101. package/dist/es/index.js.map +1 -1
  102. package/dist/index.d.ts +5 -3
  103. package/dist/index.js +6868 -5330
  104. package/dist/index.js.flow +6 -3
  105. package/dist/index.js.map +1 -1
  106. package/dist/strings.js +26 -10
  107. package/dist/types.d.ts +19 -17
  108. package/dist/types.js.flow +28 -23
  109. package/package.json +1 -1
  110. package/src/components/input/__tests__/context-tracking.test.ts +43 -44
  111. package/src/components/input/__tests__/mathquill.test.ts +133 -135
  112. package/src/components/input/key-handlers/handle-arrow.ts +70 -0
  113. package/src/components/input/key-handlers/handle-backspace.ts +275 -0
  114. package/src/components/input/key-handlers/handle-exponent.ts +52 -0
  115. package/src/components/input/key-handlers/handle-jump-out.ts +103 -0
  116. package/src/components/input/math-input.tsx +12 -13
  117. package/src/components/input/math-wrapper.ts +88 -837
  118. package/src/components/input/mathquill-helpers.ts +268 -0
  119. package/src/components/input/mathquill-instance.ts +5 -0
  120. package/src/components/input/mathquill-types.ts +55 -0
  121. package/src/components/key-translator.ts +209 -0
  122. package/src/components/keypad/button-assets.tsx +452 -116
  123. package/src/components/keypad/button.stories.tsx +61 -13
  124. package/src/components/keypad/button.tsx +1 -1
  125. package/src/components/keypad/{trigonometry-page.tsx → geometry-page/index.tsx} +4 -5
  126. package/src/components/keypad/index.tsx +19 -14
  127. package/src/components/keypad/keypad-mathquill.stories.tsx +69 -0
  128. package/src/components/keypad/keypad-page-items.tsx +36 -22
  129. package/src/components/keypad/keypad-pages.stories.tsx +5 -5
  130. package/src/components/keypad/keypad.stories.tsx +75 -17
  131. package/src/components/keypad/{numeric-input-page.tsx → numbers-page/index.tsx} +47 -11
  132. package/src/components/keypad/numbers-page/types.ts +4 -0
  133. package/src/components/keypad/operators-page/advanced-relations-buttons.tsx +32 -0
  134. package/src/components/keypad/operators-page/basic-relations-buttons.tsx +32 -0
  135. package/src/components/keypad/{pre-algebra-page.tsx → operators-page/index.tsx} +26 -30
  136. package/src/components/keypad/operators-page/logarithms-buttons.tsx +32 -0
  137. package/src/components/keypad/operators-page/pre-algebra-buttons.tsx +36 -0
  138. package/src/components/keypad/operators-page/types.ts +6 -0
  139. package/src/components/{__tests__ → keypad-legacy/__tests__}/two-page-keypad.test.tsx +0 -2
  140. package/src/components/{compute-layout-parameters.ts → keypad-legacy/compute-layout-parameters.ts} +2 -3
  141. package/src/components/{corner-decal.tsx → keypad-legacy/corner-decal.tsx} +2 -3
  142. package/src/components/{echo-manager.tsx → keypad-legacy/echo-manager.tsx} +8 -21
  143. package/src/components/{empty-keypad-button.tsx → keypad-legacy/empty-keypad-button.tsx} +8 -6
  144. package/src/components/{expression-keypad.tsx → keypad-legacy/expression-keypad.tsx} +8 -17
  145. package/src/components/{fraction-keypad.tsx → keypad-legacy/fraction-keypad.tsx} +6 -6
  146. package/src/components/{gesture-manager.ts → keypad-legacy/gesture-manager.ts} +34 -11
  147. package/src/components/{gesture-state-machine.ts → keypad-legacy/gesture-state-machine.ts} +14 -14
  148. package/src/components/{icon.tsx → keypad-legacy/icon.tsx} +3 -3
  149. package/src/components/{keypad-button.tsx → keypad-legacy/keypad-button.tsx} +26 -26
  150. package/src/components/{keypad-container.tsx → keypad-legacy/keypad-container.tsx} +6 -6
  151. package/src/components/{keypad.tsx → keypad-legacy/keypad.tsx} +5 -5
  152. package/src/components/{many-keypad-button.tsx → keypad-legacy/many-keypad-button.tsx} +13 -6
  153. package/src/components/{math-icon.tsx → keypad-legacy/math-icon.tsx} +2 -2
  154. package/src/components/{multi-symbol-grid.tsx → keypad-legacy/multi-symbol-grid.tsx} +4 -4
  155. package/src/components/{multi-symbol-popover.tsx → keypad-legacy/multi-symbol-popover.tsx} +3 -4
  156. package/src/components/{navigation-pad.tsx → keypad-legacy/navigation-pad.tsx} +5 -5
  157. package/src/components/{node-manager.ts → keypad-legacy/node-manager.ts} +2 -10
  158. package/src/components/{popover-manager.tsx → keypad-legacy/popover-manager.tsx} +2 -2
  159. package/src/components/{popover-state-machine.ts → keypad-legacy/popover-state-machine.ts} +1 -1
  160. package/src/components/{provided-keypad.tsx → keypad-legacy/provided-keypad.tsx} +4 -5
  161. package/src/{store → components/keypad-legacy/store}/actions.ts +7 -36
  162. package/src/{store → components/keypad-legacy/store}/echo-reducer.ts +3 -7
  163. package/src/{store → components/keypad-legacy/store}/index.ts +7 -20
  164. package/src/{store → components/keypad-legacy/store}/input-reducer.ts +4 -5
  165. package/src/{store → components/keypad-legacy/store}/keypad-reducer.ts +3 -4
  166. package/src/{store → components/keypad-legacy/store}/layout-reducer.ts +3 -3
  167. package/src/{store → components/keypad-legacy/store}/shared.ts +3 -3
  168. package/src/{store → components/keypad-legacy/store}/types.ts +15 -19
  169. package/src/components/{styles.ts → keypad-legacy/styles.ts} +1 -1
  170. package/src/components/{text-icon.tsx → keypad-legacy/text-icon.tsx} +2 -2
  171. package/src/components/{touchable-keypad-button.tsx → keypad-legacy/touchable-keypad-button.tsx} +35 -21
  172. package/src/components/{two-page-keypad.tsx → keypad-legacy/two-page-keypad.tsx} +5 -6
  173. package/src/components/tabbar/icons.tsx +0 -2
  174. package/src/data/key-configs.ts +751 -309
  175. package/src/data/keys.ts +118 -70
  176. package/src/enums.ts +10 -9
  177. package/src/index.ts +6 -3
  178. package/src/math-input.stories.tsx +3 -3
  179. package/src/types.ts +21 -16
  180. package/tsconfig-build.tsbuildinfo +1 -1
  181. package/dist/components/keypad/trigonometry-page.d.ts +0 -8
  182. package/dist/components/touchable-keypad-button.d.ts +0 -30
  183. package/dist/components/touchable-keypad-button.js.flow +0 -35
  184. package/dist/components/velocity-tracker.d.ts +0 -48
  185. package/dist/components/velocity-tracker.js.flow +0 -54
  186. package/dist/store/pager-reducer.d.ts +0 -4
  187. package/dist/store/pager-reducer.js.flow +0 -13
  188. package/dist/store/shared.d.ts +0 -7
  189. package/dist/store/shared.js.flow +0 -14
  190. package/src/components/velocity-tracker.ts +0 -86
  191. package/src/store/pager-reducer.ts +0 -125
  192. /package/dist/components/{corner-decal.d.ts → keypad-legacy/corner-decal.d.ts} +0 -0
  193. /package/dist/components/{corner-decal.js.flow → keypad-legacy/corner-decal.js.flow} +0 -0
  194. /package/dist/components/{empty-keypad-button.d.ts → keypad-legacy/empty-keypad-button.d.ts} +0 -0
  195. /package/dist/components/{empty-keypad-button.js.flow → keypad-legacy/empty-keypad-button.js.flow} +0 -0
  196. /package/dist/components/{many-keypad-button.d.ts → keypad-legacy/many-keypad-button.d.ts} +0 -0
  197. /package/dist/components/{many-keypad-button.js.flow → keypad-legacy/many-keypad-button.js.flow} +0 -0
  198. /package/dist/components/{math-icon.d.ts → keypad-legacy/math-icon.d.ts} +0 -0
  199. /package/dist/components/{math-icon.js.flow → keypad-legacy/math-icon.js.flow} +0 -0
  200. /package/dist/components/{navigation-pad.d.ts → keypad-legacy/navigation-pad.d.ts} +0 -0
  201. /package/dist/components/{navigation-pad.js.flow → keypad-legacy/navigation-pad.js.flow} +0 -0
  202. /package/dist/{store → components/keypad-legacy/store}/echo-reducer.d.ts +0 -0
  203. /package/dist/{store → components/keypad-legacy/store}/echo-reducer.js.flow +0 -0
  204. /package/dist/{store → components/keypad-legacy/store}/input-reducer.d.ts +0 -0
  205. /package/dist/{store → components/keypad-legacy/store}/input-reducer.js.flow +0 -0
  206. /package/dist/{store → components/keypad-legacy/store}/keypad-reducer.d.ts +0 -0
  207. /package/dist/{store → components/keypad-legacy/store}/keypad-reducer.js.flow +0 -0
  208. /package/dist/{store → components/keypad-legacy/store}/layout-reducer.d.ts +0 -0
  209. /package/dist/{store → components/keypad-legacy/store}/layout-reducer.js.flow +0 -0
  210. /package/dist/components/{styles.d.ts → keypad-legacy/styles.d.ts} +0 -0
  211. /package/dist/components/{styles.js.flow → keypad-legacy/styles.js.flow} +0 -0
  212. /package/dist/components/{svg-icon.d.ts → keypad-legacy/svg-icon.d.ts} +0 -0
  213. /package/dist/components/{svg-icon.js.flow → keypad-legacy/svg-icon.js.flow} +0 -0
  214. /package/dist/components/{text-icon.d.ts → keypad-legacy/text-icon.d.ts} +0 -0
  215. /package/dist/components/{text-icon.js.flow → keypad-legacy/text-icon.js.flow} +0 -0
  216. /package/dist/components/{z-indexes.d.ts → keypad-legacy/z-indexes.d.ts} +0 -0
  217. /package/dist/components/{z-indexes.js.flow → keypad-legacy/z-indexes.js.flow} +0 -0
  218. /package/src/components/{__tests__ → keypad-legacy/__tests__}/gesture-state-machine.test.ts +0 -0
  219. /package/src/components/{__tests__ → keypad-legacy/__tests__}/node-manager.test.ts +0 -0
  220. /package/src/components/{iconography → keypad-legacy/iconography}/arrow.js +0 -0
  221. /package/src/components/{iconography → keypad-legacy/iconography}/backspace.js +0 -0
  222. /package/src/components/{iconography → keypad-legacy/iconography}/cdot.js +0 -0
  223. /package/src/components/{iconography → keypad-legacy/iconography}/cos.js +0 -0
  224. /package/src/components/{iconography → keypad-legacy/iconography}/cube-root.js +0 -0
  225. /package/src/components/{iconography → keypad-legacy/iconography}/dismiss.js +0 -0
  226. /package/src/components/{iconography → keypad-legacy/iconography}/divide.js +0 -0
  227. /package/src/components/{iconography → keypad-legacy/iconography}/down.js +0 -0
  228. /package/src/components/{iconography → keypad-legacy/iconography}/equal.js +0 -0
  229. /package/src/components/{iconography → keypad-legacy/iconography}/exp-2.js +0 -0
  230. /package/src/components/{iconography → keypad-legacy/iconography}/exp-3.js +0 -0
  231. /package/src/components/{iconography → keypad-legacy/iconography}/exp.js +0 -0
  232. /package/src/components/{iconography → keypad-legacy/iconography}/frac.js +0 -0
  233. /package/src/components/{iconography → keypad-legacy/iconography}/geq.js +0 -0
  234. /package/src/components/{iconography → keypad-legacy/iconography}/gt.js +0 -0
  235. /package/src/components/{iconography → keypad-legacy/iconography}/index.js +0 -0
  236. /package/src/components/{iconography → keypad-legacy/iconography}/jump-into-numerator.js +0 -0
  237. /package/src/components/{iconography → keypad-legacy/iconography}/jump-out-base.js +0 -0
  238. /package/src/components/{iconography → keypad-legacy/iconography}/jump-out-denominator.js +0 -0
  239. /package/src/components/{iconography → keypad-legacy/iconography}/jump-out-exponent.js +0 -0
  240. /package/src/components/{iconography → keypad-legacy/iconography}/jump-out-numerator.js +0 -0
  241. /package/src/components/{iconography → keypad-legacy/iconography}/jump-out-parentheses.js +0 -0
  242. /package/src/components/{iconography → keypad-legacy/iconography}/left-paren.js +0 -0
  243. /package/src/components/{iconography → keypad-legacy/iconography}/left.js +0 -0
  244. /package/src/components/{iconography → keypad-legacy/iconography}/leq.js +0 -0
  245. /package/src/components/{iconography → keypad-legacy/iconography}/ln.js +0 -0
  246. /package/src/components/{iconography → keypad-legacy/iconography}/log-n.js +0 -0
  247. /package/src/components/{iconography → keypad-legacy/iconography}/log.js +0 -0
  248. /package/src/components/{iconography → keypad-legacy/iconography}/lt.js +0 -0
  249. /package/src/components/{iconography → keypad-legacy/iconography}/minus.js +0 -0
  250. /package/src/components/{iconography → keypad-legacy/iconography}/neq.js +0 -0
  251. /package/src/components/{iconography → keypad-legacy/iconography}/parens.js +0 -0
  252. /package/src/components/{iconography → keypad-legacy/iconography}/percent.js +0 -0
  253. /package/src/components/{iconography → keypad-legacy/iconography}/period.js +0 -0
  254. /package/src/components/{iconography → keypad-legacy/iconography}/plus.js +0 -0
  255. /package/src/components/{iconography → keypad-legacy/iconography}/radical.js +0 -0
  256. /package/src/components/{iconography → keypad-legacy/iconography}/right-paren.js +0 -0
  257. /package/src/components/{iconography → keypad-legacy/iconography}/right.js +0 -0
  258. /package/src/components/{iconography → keypad-legacy/iconography}/sin.js +0 -0
  259. /package/src/components/{iconography → keypad-legacy/iconography}/sqrt.js +0 -0
  260. /package/src/components/{iconography → keypad-legacy/iconography}/tan.js +0 -0
  261. /package/src/components/{iconography → keypad-legacy/iconography}/times.js +0 -0
  262. /package/src/components/{iconography → keypad-legacy/iconography}/up.js +0 -0
  263. /package/src/components/{svg-icon.tsx → keypad-legacy/svg-icon.tsx} +0 -0
  264. /package/src/components/{z-indexes.ts → keypad-legacy/z-indexes.ts} +0 -0
@@ -0,0 +1,70 @@
1
+ import Key from "../../../data/keys";
2
+ import {
3
+ maybeFindCommand,
4
+ maybeFindCommandBeforeParens,
5
+ getCursor,
6
+ } from "../mathquill-helpers";
7
+ import MQ from "../mathquill-instance";
8
+ import {
9
+ MathFieldInterface,
10
+ MathFieldActionType,
11
+ MathFieldCursor,
12
+ } from "../mathquill-types";
13
+
14
+ function handleLeftArrow(
15
+ mathField: MathFieldInterface,
16
+ cursor: MathFieldCursor,
17
+ ) {
18
+ // If we're inside a function, and just after the left parentheses, we
19
+ // need to skip the entire function name, rather than move the cursor
20
+ // inside of it. For example, when hitting left from within the
21
+ // parentheses in `cos()`, we want to place the cursor to the left of
22
+ // the entire expression, rather than between the `s` and the left
23
+ // parenthesis.
24
+ // From the cursor's perspective, this requires that our left node is
25
+ // the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
26
+ // the nodes to the left of our grandparent comprise a valid function
27
+ // name.
28
+ if (cursor[MQ.L] === MathFieldActionType.MQ_END) {
29
+ const parent = cursor.parent;
30
+ const grandparent = parent.parent;
31
+ if (grandparent.ctrlSeq === "\\left(") {
32
+ const command = maybeFindCommandBeforeParens(grandparent);
33
+ if (command) {
34
+ cursor.insLeftOf(command.startNode);
35
+ return;
36
+ }
37
+ }
38
+ }
39
+
40
+ // Otherwise, we default to the standard MathQull left behavior.
41
+ mathField.keystroke("Left");
42
+ }
43
+
44
+ function handleRightArrow(
45
+ mathField: MathFieldInterface,
46
+ cursor: MathFieldCursor,
47
+ ) {
48
+ const command = maybeFindCommand(cursor[MQ.R]);
49
+ if (command) {
50
+ // Similarly, if a function is to our right, then we need to place
51
+ // the cursor at the start of its parenthetical content, which is
52
+ // done by putting it to the left of ites parentheses and then
53
+ // moving right once.
54
+ cursor.insLeftOf(command.endNode);
55
+ mathField.keystroke("Right");
56
+ } else {
57
+ // Otherwise, we default to the standard MathQull right behavior.
58
+ mathField.keystroke("Right");
59
+ }
60
+ }
61
+
62
+ export default function handleArrow(mathField: MathFieldInterface, key: Key) {
63
+ const cursor = getCursor(mathField);
64
+
65
+ if (key === "LEFT") {
66
+ handleLeftArrow(mathField, cursor);
67
+ } else if (key === "RIGHT") {
68
+ handleRightArrow(mathField, cursor);
69
+ }
70
+ }
@@ -0,0 +1,275 @@
1
+ import {
2
+ isFraction,
3
+ isSquareRoot,
4
+ isNthRoot,
5
+ isNthRootIndex,
6
+ isInsideLogIndex,
7
+ isInsideEmptyNode,
8
+ selectNode,
9
+ getCursor,
10
+ maybeFindCommandBeforeParens,
11
+ } from "../mathquill-helpers";
12
+ import MQ from "../mathquill-instance";
13
+ import {
14
+ MathFieldActionType,
15
+ MathFieldInterface,
16
+ MathFieldCursor,
17
+ } from "../mathquill-types";
18
+
19
+ function handleBackspaceInNthRoot(
20
+ mathField: MathFieldInterface,
21
+ cursor: MathFieldCursor,
22
+ ) {
23
+ const isAtLeftEnd = cursor[MQ.L] === MathFieldActionType.MQ_END;
24
+
25
+ const isRootEmpty = isInsideEmptyNode(cursor.parent.parent.blocks[0].ends);
26
+
27
+ if (isAtLeftEnd) {
28
+ selectNode(cursor.parent.parent, cursor);
29
+
30
+ if (isRootEmpty) {
31
+ mathField.keystroke("Backspace");
32
+ }
33
+ } else {
34
+ mathField.keystroke("Backspace");
35
+ }
36
+ }
37
+
38
+ function handleBackspaceInRootIndex(
39
+ mathField: MathFieldInterface,
40
+ cursor: MathFieldCursor,
41
+ ) {
42
+ if (isInsideEmptyNode(cursor)) {
43
+ // When deleting the index in a nthroot, we change from the nthroot
44
+ // to a sqrt, e.g. \sqrt[|]{35x-5} => |\sqrt{35x-5}. If there's no
45
+ // content under the root, then we delete the whole thing.
46
+
47
+ const grandparent = cursor.parent.parent;
48
+ const latex = grandparent.latex();
49
+ const reinsertionPoint = grandparent[MQ.L];
50
+
51
+ selectNode(grandparent, cursor);
52
+
53
+ const rootIsEmpty = grandparent.blocks[1].jQ.text() === "";
54
+
55
+ if (rootIsEmpty) {
56
+ // If there is not content under the root then simply delete
57
+ // the whole thing.
58
+ mathField.keystroke("Backspace");
59
+ } else {
60
+ // Replace the nthroot with a sqrt if there was content under
61
+ // the root.
62
+
63
+ // Start by deleting the selection.
64
+ mathField.keystroke("Backspace");
65
+
66
+ // Replace the nth-root with a sqrt.
67
+ mathField.write(latex.replace(/^\\sqrt\[\]/, "\\sqrt"));
68
+
69
+ // Adjust the cursor to be to the left the sqrt.
70
+ if (reinsertionPoint === MathFieldActionType.MQ_END) {
71
+ mathField.moveToDirEnd(MQ.L);
72
+ } else {
73
+ cursor.insRightOf(reinsertionPoint);
74
+ }
75
+ }
76
+ } else {
77
+ if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
78
+ // If the cursor is not at the leftmost position inside the
79
+ // root's index, delete a character.
80
+ mathField.keystroke("Backspace");
81
+ } else {
82
+ // TODO(kevinb) verify that we want this behavior after testing
83
+ // Do nothing because we haven't completely deleted the
84
+ // index of the radical.
85
+ }
86
+ }
87
+ }
88
+
89
+ function handleBackspaceInLogIndex(
90
+ mathField: MathFieldInterface,
91
+ cursor: MathFieldCursor,
92
+ ) {
93
+ if (isInsideEmptyNode(cursor)) {
94
+ const grandparent = cursor.parent.parent;
95
+ const command = maybeFindCommandBeforeParens(grandparent);
96
+
97
+ cursor.insLeftOf(command?.startNode);
98
+ cursor.startSelection();
99
+
100
+ if (grandparent[MQ.R] !== MathFieldActionType.MQ_END) {
101
+ cursor.insRightOf(grandparent[MQ.R]);
102
+ } else {
103
+ cursor.insRightOf(grandparent);
104
+ }
105
+
106
+ cursor.select();
107
+ cursor.endSelection();
108
+
109
+ const isLogBodyEmpty = grandparent[MQ.R].contentjQ.text() === "";
110
+
111
+ if (isLogBodyEmpty) {
112
+ // If there's no content inside the log's parens then delete the
113
+ // whole thing.
114
+ mathField.keystroke("Backspace");
115
+ }
116
+ } else {
117
+ mathField.keystroke("Backspace");
118
+ }
119
+ }
120
+
121
+ function handleBackspaceOutsideParens(cursor: MathFieldCursor) {
122
+ // In this case the node with '\\left(' for its ctrlSeq
123
+ // is the parent of the expression contained within the
124
+ // parentheses.
125
+ //
126
+ // Handle selecting an expression before deleting:
127
+ // (x+1)| => |(x+1)|
128
+ // \log(x+1)| => |\log(x+1)|
129
+
130
+ const leftNode = cursor[MQ.L];
131
+ const rightNode = cursor[MQ.R];
132
+ const command = maybeFindCommandBeforeParens(leftNode);
133
+
134
+ if (command && command.startNode) {
135
+ // There's a command before the parens so we select it as well as
136
+ // the parens.
137
+ cursor.insLeftOf(command.startNode);
138
+ cursor.startSelection();
139
+ if (rightNode === MathFieldActionType.MQ_END) {
140
+ cursor.insAtRightEnd(cursor.parent);
141
+ } else {
142
+ cursor.insLeftOf(rightNode);
143
+ }
144
+ cursor.select();
145
+ cursor.endSelection();
146
+ } else {
147
+ cursor.startSelection();
148
+ cursor.insLeftOf(leftNode); // left of \\left(
149
+ cursor.select();
150
+ cursor.endSelection();
151
+ }
152
+ }
153
+
154
+ function handleBackspaceInsideParens(
155
+ mathField: MathFieldInterface,
156
+ cursor: MathFieldCursor,
157
+ ) {
158
+ // Handle situations when the cursor is inside parens or a
159
+ // command that uses parens, e.g. \log() or \tan()
160
+ //
161
+ // MathQuill represents log(x+1) in roughly the following way
162
+ // [l, o, g, \\left[parent:[x, +, 1]]]
163
+ //
164
+ // If the cursor is inside the parentheses it's next to one of:
165
+ // x, +, or 1. This makes sub_sub_expr its parent and sub_expr
166
+ // it's parent.
167
+ //
168
+ // Interestingly parent doesn't have any nodes to the left or
169
+ // right of it (even though the corresponding DOM node has
170
+ // ( and ) characters on either side.
171
+ //
172
+ // The grandparent's ctrlSeq is `\\left(`. The `\\right)` isn't
173
+ // stored anywhere. NOTE(kevinb): I believe this is because
174
+ // MathQuill knows what the close paren should be and does the
175
+ // right thing at render time.
176
+ //
177
+ // This conditional branch handles the following cases:
178
+ // - \log(x+1|) => \log(x+|)
179
+ // - \log(|x+1) => |\log(x+1)|
180
+ // - \log(|) => |
181
+
182
+ if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
183
+ // This command contains math and there's some math to
184
+ // the left of the cursor that we should delete normally
185
+ // before doing anything special.
186
+ mathField.keystroke("Backspace");
187
+ return;
188
+ }
189
+
190
+ const grandparent = cursor.parent.parent;
191
+
192
+ // If the cursors is inside the parens at the start but the command
193
+ // has a subscript as is the case in log_n then move the cursor into
194
+ // the subscript, e.g. \log_{5}(|x+1) => \log_{5|}(x+1)
195
+
196
+ if (grandparent[MQ.L].sub) {
197
+ // if there is a subscript
198
+ if (grandparent[MQ.L].sub.jQ.text()) {
199
+ // and it contains text
200
+ // move the cursor to the right end of the subscript
201
+ cursor.insAtRightEnd(grandparent[MQ.L].sub);
202
+ return;
203
+ }
204
+ }
205
+
206
+ // Determine if the parens are empty before we modify the
207
+ // cursor's position.
208
+ const isEmpty = isInsideEmptyNode(cursor);
209
+
210
+ // Insert the cursor to the left of the command if there is one
211
+ // or before the '\\left(` if there isn't
212
+ const command = maybeFindCommandBeforeParens(grandparent);
213
+
214
+ cursor.insLeftOf((command && command.startNode) || grandparent);
215
+ cursor.startSelection();
216
+ cursor.insRightOf(grandparent);
217
+ cursor.select();
218
+ cursor.endSelection();
219
+
220
+ // Delete the selection, but only if the parens were empty to
221
+ // begin with.
222
+ if (isEmpty) {
223
+ mathField.keystroke("Backspace");
224
+ }
225
+ }
226
+
227
+ function handleBackspaceAfterLigaturedSymbol(mathField: MathFieldInterface) {
228
+ mathField.keystroke("Backspace");
229
+ mathField.keystroke("Backspace");
230
+ }
231
+
232
+ /**
233
+ * Selects and deletes part of the expression based on the cursor location.
234
+ * See inline comments for precise behavior of different cases.
235
+ */
236
+ function handleBackspace(mathField: MathFieldInterface) {
237
+ const cursor = getCursor(mathField);
238
+ if (!cursor.selection) {
239
+ const parent = cursor.parent;
240
+ const grandparent = parent.parent;
241
+ const leftNode = cursor[MQ.L];
242
+
243
+ if (isFraction(leftNode)) {
244
+ selectNode(leftNode, cursor);
245
+ } else if (isSquareRoot(leftNode)) {
246
+ selectNode(leftNode, cursor);
247
+ } else if (isNthRoot(leftNode)) {
248
+ selectNode(leftNode, cursor);
249
+ } else if (isNthRootIndex(parent)) {
250
+ handleBackspaceInRootIndex(mathField, cursor);
251
+ } else if (leftNode.ctrlSeq === "\\left(") {
252
+ handleBackspaceOutsideParens(cursor);
253
+ } else if (grandparent.ctrlSeq === "\\left(") {
254
+ handleBackspaceInsideParens(mathField, cursor);
255
+ } else if (isInsideLogIndex(cursor)) {
256
+ handleBackspaceInLogIndex(mathField, cursor);
257
+ } else if (
258
+ leftNode.ctrlSeq === "\\ge " ||
259
+ leftNode.ctrlSeq === "\\le "
260
+ ) {
261
+ handleBackspaceAfterLigaturedSymbol(mathField);
262
+ } else if (
263
+ isNthRoot(grandparent) &&
264
+ leftNode === MathFieldActionType.MQ_END
265
+ ) {
266
+ handleBackspaceInNthRoot(mathField, cursor);
267
+ } else {
268
+ mathField.keystroke("Backspace");
269
+ }
270
+ } else {
271
+ mathField.keystroke("Backspace");
272
+ }
273
+ }
274
+
275
+ export default handleBackspace;
@@ -0,0 +1,52 @@
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";
5
+
6
+ const ArithmeticOperators = ["+", "-", "\\cdot", "\\times", "\\div"];
7
+ const EqualityOperators = ["=", "\\neq", "<", "\\leq", ">", "\\geq"];
8
+
9
+ export default function handleExponent(
10
+ mathField: MathFieldInterface,
11
+ key: Key,
12
+ ) {
13
+ const cursor = getCursor(mathField);
14
+ // If there's an invalid operator preceding the cursor (anything that
15
+ // knowingly cannot be raised to a power), add an empty set of
16
+ // parentheses and apply the exponent to that.
17
+ const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
18
+
19
+ const precedingNode = cursor[MQ.L];
20
+ const shouldPrefixWithParens =
21
+ precedingNode === MathFieldActionType.MQ_END ||
22
+ invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
23
+ if (shouldPrefixWithParens) {
24
+ mathField.write("\\left(\\right)");
25
+ }
26
+
27
+ // Insert the appropriate exponent operator.
28
+ switch (key) {
29
+ case "EXP":
30
+ mathField.cmd("^");
31
+ break;
32
+
33
+ case "EXP_2":
34
+ case "EXP_3":
35
+ mathField.write(`^${key === "EXP_2" ? 2 : 3}`);
36
+
37
+ // If we enter a square or a cube, we should leave the cursor
38
+ // within the newly inserted parens, if they exist. This takes
39
+ // exactly four left strokes, since the cursor by default would
40
+ // end up to the right of the exponent.
41
+ if (shouldPrefixWithParens) {
42
+ mathField.keystroke("Left");
43
+ mathField.keystroke("Left");
44
+ mathField.keystroke("Left");
45
+ mathField.keystroke("Left");
46
+ }
47
+ break;
48
+
49
+ default:
50
+ throw new Error(`Invalid exponent key: ${key}`);
51
+ }
52
+ }
@@ -0,0 +1,103 @@
1
+ import Key from "../../../data/keys";
2
+ import {CursorContext} from "../cursor-contexts";
3
+ import {
4
+ isFraction,
5
+ isParens,
6
+ contextForCursor,
7
+ getCursor,
8
+ } from "../mathquill-helpers";
9
+ import MQ from "../mathquill-instance";
10
+ import {MathFieldInterface, MathFieldActionType} from "../mathquill-types";
11
+
12
+ const KeysForJumpContext = {
13
+ [CursorContext.IN_PARENS]: "JUMP_OUT_PARENTHESES",
14
+ [CursorContext.IN_SUPER_SCRIPT]: "JUMP_OUT_EXPONENT",
15
+ [CursorContext.IN_SUB_SCRIPT]: "JUMP_OUT_BASE",
16
+ [CursorContext.BEFORE_FRACTION]: "JUMP_INTO_NUMERATOR",
17
+ [CursorContext.IN_NUMERATOR]: "JUMP_OUT_NUMERATOR",
18
+ [CursorContext.IN_DENOMINATOR]: "JUMP_OUT_DENOMINATOR",
19
+ };
20
+
21
+ /**
22
+ * Advances the cursor to the next logical position.
23
+ */
24
+ function handleJumpOut(mathField: MathFieldInterface, key: Key): void {
25
+ const cursor = getCursor(mathField);
26
+ const context = contextForCursor(cursor);
27
+
28
+ // Validate that the current cursor context matches the key's intent.
29
+ if (KeysForJumpContext[context] !== key) {
30
+ // If we don't have a valid cursor context, yet the user was able
31
+ // to trigger a jump-out key, that's a broken invariant. Rather
32
+ // than throw an error (which would kick the user out of the
33
+ // exercise), we do nothing, as a fallback strategy. The user can
34
+ // still move the cursor manually.
35
+ return;
36
+ }
37
+
38
+ switch (context) {
39
+ case CursorContext.IN_PARENS:
40
+ // Insert at the end of the parentheses, and then navigate right
41
+ // once more to get 'beyond' the parentheses.
42
+ cursor.insRightOf(cursor.parent.parent);
43
+ break;
44
+
45
+ case CursorContext.BEFORE_FRACTION:
46
+ // Find the nearest fraction to the right of the cursor.
47
+ let fractionNode;
48
+ let visitor = cursor;
49
+ while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
50
+ if (isFraction(visitor[MQ.R])) {
51
+ fractionNode = visitor[MQ.R];
52
+ }
53
+ visitor = visitor[MQ.R];
54
+ }
55
+
56
+ // Jump into it!
57
+ cursor.insLeftOf(fractionNode);
58
+ mathField.keystroke("Right");
59
+ break;
60
+
61
+ case CursorContext.IN_NUMERATOR:
62
+ // HACK(charlie): I can't find a better way to do this. The goal
63
+ // is to place the cursor at the start of the matching
64
+ // denominator. So, we identify the appropriate node, and
65
+ // continue rightwards until we find ourselves inside of it.
66
+ // It's possible that there are cases in which we don't reach
67
+ // the denominator, though I can't think of any.
68
+ const siblingDenominator = cursor.parent.parent.blocks[1];
69
+ while (cursor.parent !== siblingDenominator) {
70
+ mathField.keystroke("Right");
71
+ }
72
+ break;
73
+
74
+ case CursorContext.IN_DENOMINATOR:
75
+ cursor.insRightOf(cursor.parent.parent);
76
+ break;
77
+
78
+ case CursorContext.IN_SUB_SCRIPT:
79
+ // Insert just beyond the superscript.
80
+ cursor.insRightOf(cursor.parent.parent);
81
+
82
+ // Navigate right once more, if we're right before parens. This
83
+ // is to handle the standard case in which the subscript is the
84
+ // base of a custom log.
85
+ if (isParens(cursor[MQ.R])) {
86
+ mathField.keystroke("Right");
87
+ }
88
+ break;
89
+
90
+ case CursorContext.IN_SUPER_SCRIPT:
91
+ // Insert just beyond the superscript.
92
+ cursor.insRightOf(cursor.parent.parent);
93
+ break;
94
+
95
+ default:
96
+ throw new Error(
97
+ `Attempted to 'Jump Out' from node, but found no ` +
98
+ `appropriate cursor context: ${context}`,
99
+ );
100
+ }
101
+ }
102
+
103
+ export default handleJumpOut;
@@ -5,7 +5,6 @@ import {StyleSheet} from "aphrodite";
5
5
  import * as React from "react";
6
6
  import ReactDOM from "react-dom";
7
7
 
8
- import Keys from "../../data/keys";
9
8
  import {View} from "../../fake-react-native-web/index";
10
9
  import {
11
10
  cursorHandleRadiusPx,
@@ -13,7 +12,7 @@ import {
13
12
  wonderBlocksBlue,
14
13
  offBlack,
15
14
  } from "../common-style";
16
- import ProvidedKeypad from "../provided-keypad";
15
+ import ProvidedKeypad from "../keypad-legacy/provided-keypad";
17
16
 
18
17
  import CursorHandle from "./cursor-handle";
19
18
  import DragListener from "./drag-listener";
@@ -783,16 +782,16 @@ class MathInput extends React.Component<Props, State> {
783
782
  key,
784
783
  ) => {
785
784
  const keyMap = {
786
- "+": Keys.PLUS,
787
- "-": Keys.MINUS,
788
- "*": Keys.TIMES,
789
- "/": Keys.DIVIDE,
790
- ".": Keys.DECIMAL,
791
- "%": Keys.PERCENT,
792
- "=": Keys.EQUAL,
793
- ">": Keys.GT,
794
- "<": Keys.LT,
795
- "^": Keys.EXP,
785
+ "+": "PLUS",
786
+ "-": "MINUS",
787
+ "*": "TIMES",
788
+ "/": "DIVIDE",
789
+ ".": "DECIMAL",
790
+ "%": "PERCENT",
791
+ "=": "EQUAL",
792
+ ">": "GT",
793
+ "<": "LT",
794
+ "^": "EXP",
796
795
  } as const;
797
796
 
798
797
  // Numbers
@@ -802,7 +801,7 @@ class MathInput extends React.Component<Props, State> {
802
801
 
803
802
  // Movement keys
804
803
  else if (key === "Backspace") {
805
- return Keys.BACKSPACE;
804
+ return "BACKSPACE";
806
805
  }
807
806
 
808
807
  // Operators