@khanacademy/math-input 16.3.0 → 16.4.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @khanacademy/math-input
2
2
 
3
+ ## 16.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#881](https://github.com/Khan/perseus/pull/881) [`f02eb991`](https://github.com/Khan/perseus/commit/f02eb991cec37dcff02056c0d6b54fc6dfd96948) Thanks [@nedredmond](https://github.com/nedredmond)! - Swap out Label Image custom dropdown for WonderBlocks
8
+
9
+ ## 16.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#871](https://github.com/Khan/perseus/pull/871) [`610ebba2`](https://github.com/Khan/perseus/commit/610ebba29ab8b2ee4ddf4879f8c8b87993f29b20) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Ensured that tapping an already focused math input will reopen the keypad if it is closed.
14
+
3
15
  ## 16.3.0
4
16
 
5
17
  ### Minor Changes
@@ -82,8 +82,8 @@ declare class MathInput extends React.Component<Props, State> {
82
82
  * @param {number} y - the y coordinate in the viewport
83
83
  */
84
84
  _insertCursorAtClosestNode: (arg1: number, arg2: number) => void;
85
- handleTouchStart: (arg1: React.TouchEvent<HTMLDivElement>) => void;
86
- handleClick: (e: React.MouseEvent<HTMLDivElement>) => void;
85
+ handleTouchStart: (e: React.TouchEvent<HTMLDivElement>, keypadActive: boolean, setKeypadActive: (keypadActive: boolean) => void) => void;
86
+ handleClick: (e: React.MouseEvent<HTMLDivElement>, keypadActive: boolean, setKeypadActive: (keypadActive: boolean) => void) => void;
87
87
  handleTouchMove: (arg1: React.TouchEvent<HTMLDivElement>) => void;
88
88
  handleTouchEnd: (arg1: React.TouchEvent<HTMLDivElement>) => void;
89
89
  /**
package/dist/es/index.js CHANGED
@@ -5,7 +5,7 @@ import { getDecimalSeparator, getLocale } from '@khanacademy/wonder-blocks-i18n'
5
5
  import { entries } from '@khanacademy/wonder-stuff-core';
6
6
  import { StyleSheet, css } from 'aphrodite';
7
7
  import * as React from 'react';
8
- import { useEffect, useState, useMemo } from 'react';
8
+ import { useState, useMemo, useEffect } from 'react';
9
9
  import ReactDOM from 'react-dom';
10
10
  import $ from 'jquery';
11
11
  import MathQuill from 'mathquill';
@@ -17,7 +17,7 @@ import PropTypes from 'prop-types';
17
17
 
18
18
  // This file is processed by a Rollup plugin (replace) to inject the production
19
19
  const libName = "@khanacademy/math-input";
20
- const libVersion = "16.3.0";
20
+ const libVersion = "16.4.1";
21
21
  addLibraryVersionToPerseusDebug(libName, libVersion);
22
22
 
23
23
  function _extends() {
@@ -100,6 +100,49 @@ View.styles = StyleSheet.create({
100
100
  }
101
101
  });
102
102
 
103
+ /**
104
+ * KeypadContext provides a way to the Keypad and Perseus Renderers to
105
+ * communicate.
106
+ *
107
+ * The StatefulKeypadContextProvider wraps the application
108
+ * while KeypadContext.Consumer wraps things that need this state:
109
+ * - mobile keypad usages
110
+ * - Perseus Renderers (Server/Item/Article)
111
+ */
112
+ // @ts-expect-error - TS2322 - Type 'Context<{ setKeypadElement: (keypadElement: HTMLElement | null | undefined) => void; keypadElement: null; setRenderer: (renderer: RendererInterface | null | undefined) => void; renderer: null; setScrollableElement: (scrollableElement: HTMLElement | ... 1 more ... | undefined) => void; scrollableElement: null; }>' is not assignable to type 'Context<KeypadContext>'.
113
+ const KeypadContext = /*#__PURE__*/React.createContext({
114
+ setKeypadActive: keypadActive => {},
115
+ keypadActive: false,
116
+ setKeypadElement: keypadElement => {},
117
+ keypadElement: null,
118
+ setRenderer: renderer => {},
119
+ renderer: null,
120
+ setScrollableElement: scrollableElement => {},
121
+ scrollableElement: null
122
+ });
123
+ function StatefulKeypadContextProvider(props) {
124
+ // whether or not to display the keypad
125
+ const [keypadActive, setKeypadActive] = useState(false);
126
+ // used to communicate between the keypad and the Renderer
127
+ const [keypadElement, setKeypadElement] = useState();
128
+ // this is a KeypadContextRendererInterface from Perseus
129
+ const [renderer, setRenderer] = useState();
130
+ const [scrollableElement, setScrollableElement] = useState();
131
+ const memoizedValue = useMemo(() => ({
132
+ keypadActive,
133
+ setKeypadActive,
134
+ keypadElement,
135
+ setKeypadElement,
136
+ renderer,
137
+ setRenderer,
138
+ scrollableElement,
139
+ setScrollableElement
140
+ }), [keypadActive, setKeypadActive, keypadElement, setKeypadElement, renderer, setRenderer, scrollableElement, setScrollableElement]);
141
+ return /*#__PURE__*/React.createElement(KeypadContext.Provider, {
142
+ value: memoizedValue
143
+ }, props.children);
144
+ }
145
+
103
146
  /**
104
147
  * Common parameters used to style components.
105
148
  */
@@ -1694,7 +1737,7 @@ class MathInput extends React.Component {
1694
1737
  context: this.mathField.contextForCursor()
1695
1738
  });
1696
1739
  };
1697
- this.handleTouchStart = e => {
1740
+ this.handleTouchStart = (e, keypadActive, setKeypadActive) => {
1698
1741
  e.stopPropagation();
1699
1742
 
1700
1743
  // Hide the cursor handle on touch start, if the handle itself isn't
@@ -1713,6 +1756,11 @@ class MathInput extends React.Component {
1713
1756
  this._insertCursorAtClosestNode(touch.clientX, touch.clientY);
1714
1757
  }
1715
1758
 
1759
+ // If we're already focused, but the keypad isn't active, activate it.
1760
+ if (this.state.focused && !keypadActive) {
1761
+ setKeypadActive(true);
1762
+ }
1763
+
1716
1764
  // Trigger a focus event, if we're not already focused.
1717
1765
  if (!this.state.focused) {
1718
1766
  this.focus();
@@ -1721,7 +1769,7 @@ class MathInput extends React.Component {
1721
1769
  // We want to allow the user to be able to focus the input via click
1722
1770
  // when using ChromeOS third-party browsers that use mobile user agents,
1723
1771
  // but don't actually simulate touch events.
1724
- this.handleClick = e => {
1772
+ this.handleClick = (e, keypadActive, setKeypadActive) => {
1725
1773
  e.stopPropagation();
1726
1774
 
1727
1775
  // Hide the cursor handle on click
@@ -1738,6 +1786,11 @@ class MathInput extends React.Component {
1738
1786
  this._insertCursorAtClosestNode(e.clientX, e.clientY);
1739
1787
  }
1740
1788
 
1789
+ // If we're already focused, but the keypad isn't active, activate it.
1790
+ if (this.state.focused && !keypadActive) {
1791
+ setKeypadActive(true);
1792
+ }
1793
+
1741
1794
  // Trigger a focus event, if we're not already focused.
1742
1795
  if (!this.state.focused) {
1743
1796
  this.focus();
@@ -2036,6 +2089,7 @@ class MathInput extends React.Component {
2036
2089
  if (!this._container.contains(evt.target)) {
2037
2090
  if (this.props.keypadElement && this.props.keypadElement.getDOMNode()) {
2038
2091
  const [x, y] = [evt.clientX, evt.clientY];
2092
+
2039
2093
  // We only want to blur if the click is above the keypad,
2040
2094
  // to the left of the keypad, or to the right of the keypad.
2041
2095
  // The reasoning for not blurring for any clicks below the keypad is
@@ -2101,12 +2155,19 @@ class MathInput extends React.Component {
2101
2155
  // TODO(diedra): Fix the bug that is causing Android to require a two finger tap
2102
2156
  // to the open the keyboard, and then remove the second half of this label.
2103
2157
  const ariaLabel = i18n._("Math input box") + " " + i18n._("Tap with one or two fingers to open keyboard");
2104
- return /*#__PURE__*/React.createElement(View, {
2158
+ return /*#__PURE__*/React.createElement(KeypadContext.Consumer, null, ({
2159
+ keypadActive,
2160
+ setKeypadActive
2161
+ }) => /*#__PURE__*/React.createElement(View, {
2105
2162
  style: styles$7.input,
2106
- onTouchStart: this.handleTouchStart,
2163
+ onTouchStart: e => {
2164
+ this.handleTouchStart(e, keypadActive, setKeypadActive);
2165
+ },
2107
2166
  onTouchMove: this.handleTouchMove,
2108
2167
  onTouchEnd: this.handleTouchEnd,
2109
- onClick: this.handleClick,
2168
+ onClick: e => {
2169
+ this.handleClick(e, keypadActive, setKeypadActive);
2170
+ },
2110
2171
  role: "textbox",
2111
2172
  ariaLabel: ariaLabel
2112
2173
  }, /*#__PURE__*/React.createElement("div", {
@@ -2128,7 +2189,7 @@ class MathInput extends React.Component {
2128
2189
  onTouchMove: this.onCursorHandleTouchMove,
2129
2190
  onTouchEnd: this.onCursorHandleTouchEnd,
2130
2191
  onTouchCancel: this.onCursorHandleTouchCancel
2131
- })));
2192
+ }))));
2132
2193
  }
2133
2194
  }
2134
2195
  MathInput.defaultProps = {
@@ -5091,49 +5152,6 @@ const styles$1 = StyleSheet.create({
5091
5152
  }
5092
5153
  });
5093
5154
 
5094
- /**
5095
- * KeypadContext provides a way to the Keypad and Perseus Renderers to
5096
- * communicate.
5097
- *
5098
- * The StatefulKeypadContextProvider wraps the application
5099
- * while KeypadContext.Consumer wraps things that need this state:
5100
- * - mobile keypad usages
5101
- * - Perseus Renderers (Server/Item/Article)
5102
- */
5103
- // @ts-expect-error - TS2322 - Type 'Context<{ setKeypadElement: (keypadElement: HTMLElement | null | undefined) => void; keypadElement: null; setRenderer: (renderer: RendererInterface | null | undefined) => void; renderer: null; setScrollableElement: (scrollableElement: HTMLElement | ... 1 more ... | undefined) => void; scrollableElement: null; }>' is not assignable to type 'Context<KeypadContext>'.
5104
- const KeypadContext = /*#__PURE__*/React.createContext({
5105
- setKeypadActive: keypadActive => {},
5106
- keypadActive: false,
5107
- setKeypadElement: keypadElement => {},
5108
- keypadElement: null,
5109
- setRenderer: renderer => {},
5110
- renderer: null,
5111
- setScrollableElement: scrollableElement => {},
5112
- scrollableElement: null
5113
- });
5114
- function StatefulKeypadContextProvider(props) {
5115
- // whether or not to display the keypad
5116
- const [keypadActive, setKeypadActive] = useState(false);
5117
- // used to communicate between the keypad and the Renderer
5118
- const [keypadElement, setKeypadElement] = useState();
5119
- // this is a KeypadContextRendererInterface from Perseus
5120
- const [renderer, setRenderer] = useState();
5121
- const [scrollableElement, setScrollableElement] = useState();
5122
- const memoizedValue = useMemo(() => ({
5123
- keypadActive,
5124
- setKeypadActive,
5125
- keypadElement,
5126
- setKeypadElement,
5127
- renderer,
5128
- setRenderer,
5129
- scrollableElement,
5130
- setScrollableElement
5131
- }), [keypadActive, setKeypadActive, keypadElement, setKeypadElement, renderer, setRenderer, scrollableElement, setScrollableElement]);
5132
- return /*#__PURE__*/React.createElement(KeypadContext.Provider, {
5133
- value: memoizedValue
5134
- }, props.children);
5135
- }
5136
-
5137
5155
  function flatten(list) {
5138
5156
  const result = [];
5139
5157
  if (!list) {