@khanacademy/math-input 13.1.0 → 14.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @khanacademy/math-input
2
2
 
3
+ ## 14.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 14138bb0: Move StatefulKeypadContextProvider into math-input
8
+ - 14138bb0: Hoist keypad active state into keypad context
9
+
3
10
  ## 13.1.0
4
11
 
5
12
  ### Minor Changes
@@ -19,9 +19,10 @@ type Props = {
19
19
  onDismiss?: () => void;
20
20
  style?: StyleType;
21
21
  onAnalyticsEvent: AnalyticsEventHandlerFn;
22
+ setKeypadActive: (keypadActive: boolean) => void;
23
+ keypadActive: boolean;
22
24
  };
23
25
  type State = {
24
- active: boolean;
25
26
  containerWidth: number;
26
27
  hasBeenActivated: boolean;
27
28
  keypadConfig?: KeypadConfiguration;
@@ -1,21 +1,15 @@
1
1
  /**
2
- * KeypadContext provides a way to the Keypad and (Server)ItemRenderer to
2
+ * KeypadContext provides a way to the Keypad and Perseus Renderers to
3
3
  * communicate.
4
4
  *
5
- * The KeypadContext.Provider wraps the ExerciseFooter while KeypadContext.Consumer
6
- * wraps each (Server)ItemRenderer render site and the Keypad rendered in the
7
- * ExerciseFooter.
5
+ * The StatefulKeypadContextProvider wraps the application
6
+ * while KeypadContext.Consumer wraps things that need this state:
7
+ * - mobile keypad usages
8
+ * - Perseus Renderers (Server/Item/Article)
8
9
  */
9
10
  import * as React from "react";
10
- import type { KeypadAPI } from "../types";
11
- import type { KeypadContextRendererInterface } from "@khanacademy/perseus-core";
12
- type KeypadContext = {
13
- setKeypadElement: (keypadElement?: KeypadAPI) => void;
14
- keypadElement: KeypadAPI | null | undefined;
15
- setRenderer: (renderer?: KeypadContextRendererInterface | null | undefined) => void;
16
- renderer: KeypadContextRendererInterface | null | undefined;
17
- setScrollableElement: (scrollableElement?: HTMLElement | null | undefined) => void;
18
- scrollableElement: HTMLElement | null | undefined;
19
- };
20
- declare const context: React.Context<KeypadContext>;
21
- export default context;
11
+ import type { KeypadContextType } from "../types";
12
+ export declare const KeypadContext: React.Context<KeypadContextType>;
13
+ type Props = React.PropsWithChildren<unknown>;
14
+ export declare function StatefulKeypadContextProvider(props: Props): JSX.Element;
15
+ export {};
@@ -4,6 +4,8 @@ import type { Cursor, KeypadConfiguration, KeyHandler, KeypadAPI } from "../../t
4
4
  import type { AnalyticsEventHandlerFn } from "@khanacademy/perseus-core";
5
5
  import type { StyleType } from "@khanacademy/wonder-blocks-core";
6
6
  type Props = {
7
+ setKeypadActive: (keypadActive: boolean) => void;
8
+ keypadActive: boolean;
7
9
  onElementMounted?: (arg1: any) => void;
8
10
  onDismiss?: () => void;
9
11
  style?: StyleType;
@@ -12,6 +14,7 @@ type Props = {
12
14
  declare class ProvidedKeypad extends React.Component<Props> implements KeypadAPI {
13
15
  store: any;
14
16
  constructor(props: any);
17
+ componentDidUpdate(prevProps: any): void;
15
18
  activate: () => void;
16
19
  dismiss: () => void;
17
20
  configure: (configuration: KeypadConfiguration, cb: () => void) => void;
package/dist/es/index.js CHANGED
@@ -4,7 +4,7 @@ import { getDecimalSeparator } from '@khanacademy/wonder-blocks-i18n';
4
4
  import { entries } from '@khanacademy/wonder-stuff-core';
5
5
  import { StyleSheet, css } from 'aphrodite';
6
6
  import * as React from 'react';
7
- import { useEffect } from 'react';
7
+ import { useEffect, useState } from 'react';
8
8
  import ReactDOM from 'react-dom';
9
9
  import $ from 'jquery';
10
10
  import MathQuill from 'mathquill';
@@ -5085,17 +5085,6 @@ const styles$d = StyleSheet.create({
5085
5085
  }
5086
5086
  });
5087
5087
 
5088
- /**
5089
- * This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
5090
- * external API so that it can be hot-swapped with the v1 keypad and
5091
- * is responsible for connecting the keypad with MathInput and the Renderer.
5092
- *
5093
- * Ideally this strategy of attaching methods on the class component for
5094
- * other components to call will be replaced props/callbacks since React
5095
- * doesn't support this type of code anymore (functional components
5096
- * can't have methods attached to them).
5097
- */
5098
-
5099
5088
  class MobileKeypad extends React.Component {
5100
5089
  constructor(...args) {
5101
5090
  super(...args);
@@ -5104,7 +5093,6 @@ class MobileKeypad extends React.Component {
5104
5093
  this._throttleResize = false;
5105
5094
  this.hasMounted = false;
5106
5095
  this.state = {
5107
- active: false,
5108
5096
  containerWidth: 0,
5109
5097
  hasBeenActivated: false
5110
5098
  };
@@ -5126,18 +5114,15 @@ class MobileKeypad extends React.Component {
5126
5114
  }, 100);
5127
5115
  };
5128
5116
  this.activate = () => {
5117
+ this.props.setKeypadActive(true);
5129
5118
  this.setState({
5130
- active: true,
5131
5119
  hasBeenActivated: true
5132
5120
  });
5133
5121
  };
5134
5122
  this.dismiss = () => {
5135
- this.setState({
5136
- active: false
5137
- }, () => {
5138
- var _this$props$onDismiss, _this$props;
5139
- (_this$props$onDismiss = (_this$props = this.props).onDismiss) == null ? void 0 : _this$props$onDismiss.call(_this$props);
5140
- });
5123
+ var _this$props$onDismiss, _this$props;
5124
+ this.props.setKeypadActive(false);
5125
+ (_this$props$onDismiss = (_this$props = this.props).onDismiss) == null ? void 0 : _this$props$onDismiss.call(_this$props);
5141
5126
  };
5142
5127
  this.configure = (configuration, cb) => {
5143
5128
  this.setState({
@@ -5202,10 +5187,10 @@ class MobileKeypad extends React.Component {
5202
5187
  }
5203
5188
  render() {
5204
5189
  const {
5190
+ keypadActive,
5205
5191
  style
5206
5192
  } = this.props;
5207
5193
  const {
5208
- active,
5209
5194
  hasBeenActivated,
5210
5195
  containerWidth,
5211
5196
  cursor,
@@ -5213,7 +5198,7 @@ class MobileKeypad extends React.Component {
5213
5198
  } = this.state;
5214
5199
  const containerStyle = [
5215
5200
  // internal styles
5216
- styles$c.keypadContainer, active && styles$c.activeKeypadContainer,
5201
+ styles$c.keypadContainer, keypadActive && styles$c.activeKeypadContainer,
5217
5202
  // styles passed as props
5218
5203
  ...(Array.isArray(style) ? style : [style])];
5219
5204
 
@@ -5222,7 +5207,7 @@ class MobileKeypad extends React.Component {
5222
5207
  // during the initial render.
5223
5208
  // Done inline (dynamicStyle) since stylesheets might not be loaded yet.
5224
5209
  let dynamicStyle = {};
5225
- if (!active && !hasBeenActivated) {
5210
+ if (!keypadActive && !hasBeenActivated) {
5226
5211
  dynamicStyle = {
5227
5212
  visibility: "hidden"
5228
5213
  };
@@ -5287,6 +5272,51 @@ const styles$c = StyleSheet.create({
5287
5272
  }
5288
5273
  });
5289
5274
 
5275
+ /**
5276
+ * KeypadContext provides a way to the Keypad and Perseus Renderers to
5277
+ * communicate.
5278
+ *
5279
+ * The StatefulKeypadContextProvider wraps the application
5280
+ * while KeypadContext.Consumer wraps things that need this state:
5281
+ * - mobile keypad usages
5282
+ * - Perseus Renderers (Server/Item/Article)
5283
+ */
5284
+ // @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>'.
5285
+ const KeypadContext = /*#__PURE__*/React.createContext({
5286
+ setKeypadActive: keypadActive => {},
5287
+ keypadActive: false,
5288
+ setKeypadElement: keypadElement => {},
5289
+ keypadElement: null,
5290
+ setRenderer: renderer => {},
5291
+ renderer: null,
5292
+ setScrollableElement: scrollableElement => {},
5293
+ scrollableElement: null
5294
+ });
5295
+ function StatefulKeypadContextProvider(props) {
5296
+ // whether or not to display the keypad
5297
+ const [keypadActive, setKeypadActive] = useState(false);
5298
+ // used to communicate between the keypad and the Renderer
5299
+ const [keypadElement, setKeypadElement] = useState();
5300
+ // this is a KeypadContextRendererInterface from Perseus
5301
+ const [renderer, setRenderer] = useState();
5302
+ const [scrollableElement, setScrollableElement] = useState();
5303
+ return /*#__PURE__*/React.createElement(KeypadContext.Provider, {
5304
+ value: {
5305
+ setKeypadActive,
5306
+ keypadActive,
5307
+ setKeypadElement,
5308
+ keypadElement,
5309
+ setRenderer,
5310
+ renderer,
5311
+ // The scrollableElement options can likely be removed after
5312
+ // the exercises-package is officially deprecated. They don't appear
5313
+ // to be used anywhere except for the exercises-package and tests.
5314
+ setScrollableElement,
5315
+ scrollableElement
5316
+ }
5317
+ }, props.children);
5318
+ }
5319
+
5290
5320
  /**
5291
5321
  * A small triangular decal to sit in the corner of a parent component.
5292
5322
  */
@@ -9685,10 +9715,10 @@ class ProvidedKeypad extends React.Component {
9685
9715
  super(props);
9686
9716
  this.store = void 0;
9687
9717
  this.activate = () => {
9688
- this.store.dispatch(activateKeypad());
9718
+ this.props.setKeypadActive(true);
9689
9719
  };
9690
9720
  this.dismiss = () => {
9691
- this.store.dispatch(dismissKeypad());
9721
+ this.props.setKeypadActive(false);
9692
9722
  };
9693
9723
  this.configure = (configuration, cb) => {
9694
9724
  this.store.dispatch(configureKeypad(configuration));
@@ -9713,6 +9743,14 @@ class ProvidedKeypad extends React.Component {
9713
9743
  };
9714
9744
  this.store = createStore();
9715
9745
  }
9746
+ componentDidUpdate(prevProps) {
9747
+ if (this.props.keypadActive && !prevProps.keypadActive) {
9748
+ this.store.dispatch(activateKeypad());
9749
+ }
9750
+ if (!this.props.keypadActive && prevProps.keypadActive) {
9751
+ this.store.dispatch(dismissKeypad());
9752
+ }
9753
+ }
9716
9754
  render() {
9717
9755
  const {
9718
9756
  onElementMounted,
@@ -9767,27 +9805,17 @@ function KeypadSwitch(props) {
9767
9805
  // Note: Although we pass the "onAnalyticsEvent" to both keypad components,
9768
9806
  // only the current one uses it. There's no point in instrumenting the
9769
9807
  // legacy keypad given that it's on its way out the door.
9770
- return /*#__PURE__*/React.createElement(KeypadComponent, rest);
9808
+ return /*#__PURE__*/React.createElement(KeypadContext.Consumer, null, ({
9809
+ setKeypadActive,
9810
+ keypadActive
9811
+ }) => {
9812
+ return /*#__PURE__*/React.createElement(KeypadComponent, _extends({}, rest, {
9813
+ keypadActive: keypadActive,
9814
+ setKeypadActive: setKeypadActive
9815
+ }));
9816
+ });
9771
9817
  }
9772
9818
 
9773
- /**
9774
- * KeypadContext provides a way to the Keypad and (Server)ItemRenderer to
9775
- * communicate.
9776
- *
9777
- * The KeypadContext.Provider wraps the ExerciseFooter while KeypadContext.Consumer
9778
- * wraps each (Server)ItemRenderer render site and the Keypad rendered in the
9779
- * ExerciseFooter.
9780
- */
9781
- // @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>'.
9782
- const context = /*#__PURE__*/React.createContext({
9783
- setKeypadElement: keypadElement => {},
9784
- keypadElement: null,
9785
- setRenderer: renderer => {},
9786
- renderer: null,
9787
- setScrollableElement: scrollableElement => {},
9788
- scrollableElement: null
9789
- });
9790
-
9791
9819
  /**
9792
9820
  * React PropTypes that may be shared between components.
9793
9821
  */
@@ -9803,5 +9831,5 @@ const keypadElementPropType = PropTypes.shape({
9803
9831
  getDOMNode: PropTypes.func.isRequired
9804
9832
  });
9805
9833
 
9806
- export { CursorContext, Keypad$2 as DesktopKeypad, KeyConfigs, context as KeypadContext, MathInput as KeypadInput, KeypadType, KeypadSwitch as MobileKeypad, createMathField, getCursorContext, keyToMathquillMap as keyTranslator, keypadElementPropType, mathQuillInstance };
9834
+ export { CursorContext, Keypad$2 as DesktopKeypad, KeyConfigs, KeypadContext, MathInput as KeypadInput, KeypadType, KeypadSwitch as MobileKeypad, StatefulKeypadContextProvider, createMathField, getCursorContext, keyToMathquillMap as keyTranslator, keypadElementPropType, mathQuillInstance };
9807
9835
  //# sourceMappingURL=index.js.map