@khanacademy/perseus 10.1.0 → 11.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,17 @@
1
1
  # @khanacademy/perseus
2
2
 
3
+ ## 11.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 2af4f9fa: Switch from using ProvideKeypad in ArticleRenderer to passing the keypad element down instead
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [2af4f9fa]
12
+ - @khanacademy/math-input@11.0.0
13
+ - @khanacademy/perseus-core@1.0.0
14
+
3
15
  ## 10.1.0
4
16
 
5
17
  ### Minor Changes
@@ -6,6 +6,8 @@ import * as React from "react";
6
6
  import type { KeypadProps } from "./mixins/provide-keypad";
7
7
  import type { PerseusRenderer } from "./perseus-types";
8
8
  import type { APIOptions, PerseusDependenciesV2 } from "./types";
9
+ import type { KeypadAPI } from "@khanacademy/math-input";
10
+ import type { KeypadContextRendererInterface } from "@khanacademy/perseus-core";
9
11
  import type { LinterContextProps } from "@khanacademy/perseus-linter";
10
12
  type Props = {
11
13
  apiOptions: APIOptions;
@@ -16,6 +18,7 @@ type Props = {
16
18
  useNewStyles: boolean;
17
19
  linterContext: LinterContextProps;
18
20
  legacyPerseusLint?: ReadonlyArray<string>;
21
+ keypadElement?: KeypadAPI | null | undefined;
19
22
  dependencies: PerseusDependenciesV2;
20
23
  } & KeypadProps;
21
24
  type DefaultProps = {
@@ -23,17 +26,12 @@ type DefaultProps = {
23
26
  useNewStyles: Props["useNewStyles"];
24
27
  linterContext: Props["linterContext"];
25
28
  };
26
- type State = {
27
- keypadElement: any | null;
28
- };
29
- declare class ArticleRenderer extends React.Component<Props, State> {
29
+ declare class ArticleRenderer extends React.Component<Props> implements KeypadContextRendererInterface {
30
30
  _currentFocus: any;
31
31
  static defaultProps: DefaultProps;
32
32
  constructor(props: Props);
33
33
  componentDidMount(): void;
34
- shouldComponentUpdate(nextProps: Props, nextState: State): boolean;
35
- componentWillUnmount(): void;
36
- keypadElement: () => void;
34
+ shouldComponentUpdate(nextProps: Props): boolean;
37
35
  _handleFocusChange: (arg1: any, arg2: any) => void;
38
36
  _setCurrentFocus: (arg1: any) => void;
39
37
  _onRendererBlur: (arg1: any) => void;
package/dist/es/index.js CHANGED
@@ -43882,80 +43882,10 @@ registerWidgets(allWidgets);
43882
43882
  const ItemVersion = getVersionVector();
43883
43883
  ItemVersion["::renderer::"] = version.itemDataVersion;
43884
43884
 
43885
- /* eslint-disable @khanacademy/ts-no-error-suppressions */
43886
- // NOTE: This is not a real component. It's a collection of methods used to
43887
- // create and manage a Keypad instances.
43888
- // TODO(LP-10789): replace this with a React Context object to pass information
43889
- // between Perseus and the Keypad.
43890
- const ProvideKeypad = {
43891
- getInitialState() {
43892
- const _this = this;
43893
- let keypadElement = null;
43894
- if (_this.props.apiOptions && _this.props.apiOptions.customKeypad && _this.props.apiOptions.nativeKeypadProxy) {
43895
- keypadElement = _this.props.apiOptions.nativeKeypadProxy(
43896
- // @ts-expect-error - TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'. | TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
43897
- () => _this.blur && _this.blur());
43898
- }
43899
- return {
43900
- keypadElement
43901
- };
43902
- },
43903
- componentDidMount() {
43904
- const _this = this;
43905
- const apiOptions = _this.props.apiOptions;
43906
- if (apiOptions && apiOptions.customKeypad && !apiOptions.nativeKeypadProxy) {
43907
- var _document$body;
43908
- // TODO(charlie): Render this and the wrapped component in the same
43909
- // React tree. We may also want to add this keypad asynchronously
43910
- // or on-demand in the future.
43911
- _this._keypadContainer = document.createElement("div");
43912
- (_document$body = document.body) == null ? void 0 : _document$body.appendChild(_this._keypadContainer);
43913
- render( /*#__PURE__*/React.createElement(MobileKeypad, {
43914
- onElementMounted: element => {
43915
- // NOTE(kevinb): The reason why this setState works is
43916
- // b/c we're calling it manually from item-renderer.jsx
43917
- // and we're manually setting the 'this' by using 'call'
43918
- // @ts-expect-error - TS2339 - Property 'setState' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
43919
- _this.setState({
43920
- keypadElement: element
43921
- });
43922
- },
43923
- onDismiss: () => {
43924
- // @ts-expect-error - TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'. | TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
43925
- _this.blur && _this.blur();
43926
- }
43927
- // @ts-expect-error - TS2339 - Property 'props' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
43928
- ,
43929
- style: _this.props.keypadStyle,
43930
- useV2Keypad: apiOptions.useV2Keypad
43931
- }), _this._keypadContainer);
43932
- }
43933
- },
43934
- componentWillUnmount() {
43935
- const _this = this;
43936
- if (_this._keypadContainer) {
43937
- ReactDOM__default.unmountComponentAtNode(_this._keypadContainer);
43938
- if (_this._keypadContainer.parentNode) {
43939
- // Note ChildNode.remove() isn't available in older Android
43940
- // webviews.
43941
- _this._keypadContainer.parentNode.removeChild(_this._keypadContainer);
43942
- }
43943
- _this._keypadContainer = null;
43944
- }
43945
- },
43946
- keypadElement() {
43947
- const _this = this;
43948
- return _this.state.keypadElement;
43949
- }
43950
- };
43951
-
43952
43885
  class ArticleRenderer extends React.Component {
43953
43886
  constructor(props) {
43954
43887
  super(props);
43955
43888
  this._currentFocus = void 0;
43956
- this.keypadElement = () => {
43957
- return ProvideKeypad.keypadElement.call(this);
43958
- };
43959
43889
  this._handleFocusChange = (newFocusPath, oldFocusPath) => {
43960
43890
  // TODO(charlie): DRY this up--some of this logic is repeated in
43961
43891
  // ItemRenderer.
@@ -43966,7 +43896,13 @@ class ArticleRenderer extends React.Component {
43966
43896
  }
43967
43897
  };
43968
43898
  this._setCurrentFocus = newFocusPath => {
43969
- const keypadElement = this.keypadElement();
43899
+ const {
43900
+ keypadElement,
43901
+ apiOptions
43902
+ } = this.props;
43903
+ const {
43904
+ isMobile
43905
+ } = apiOptions;
43970
43906
  const prevFocusPath = this._currentFocus;
43971
43907
  this._currentFocus = newFocusPath;
43972
43908
 
@@ -43984,18 +43920,12 @@ class ArticleRenderer extends React.Component {
43984
43920
  });
43985
43921
  }
43986
43922
  if (this.props.apiOptions.onFocusChange != null) {
43987
- this.props.apiOptions.onFocusChange(this._currentFocus, prevFocusPath,
43988
- // @ts-expect-error - TS2339 - Property 'getDOMNode' does not exist on type 'never'.
43989
- didFocusInput && keypadElement && keypadElement.getDOMNode());
43923
+ this.props.apiOptions.onFocusChange(this._currentFocus, prevFocusPath, didFocusInput ? keypadElement == null ? void 0 : keypadElement.getDOMNode() : null);
43990
43924
  }
43991
-
43992
- // @ts-expect-error - TS1345 - An expression of type 'void' cannot be tested for truthiness.
43993
- if (keypadElement) {
43925
+ if (keypadElement && isMobile) {
43994
43926
  if (didFocusInput) {
43995
- // @ts-expect-error - TS2339 - Property 'activate' does not exist on type 'never'.
43996
43927
  keypadElement.activate();
43997
43928
  } else {
43998
- // @ts-expect-error - TS2339 - Property 'dismiss' does not exist on type 'never'.
43999
43929
  keypadElement.dismiss();
44000
43930
  }
44001
43931
  }
@@ -44031,17 +43961,12 @@ class ArticleRenderer extends React.Component {
44031
43961
  this._sections = () => {
44032
43962
  return Array.isArray(this.props.json) ? this.props.json : [this.props.json];
44033
43963
  };
44034
- this.state = ProvideKeypad.getInitialState.call(this);
44035
43964
  }
44036
43965
  componentDidMount() {
44037
- ProvideKeypad.componentDidMount.call(this);
44038
43966
  this._currentFocus = null;
44039
43967
  }
44040
- shouldComponentUpdate(nextProps, nextState) {
44041
- return nextProps !== this.props || nextState !== this.state;
44042
- }
44043
- componentWillUnmount() {
44044
- ProvideKeypad.componentWillUnmount.call(this);
43968
+ shouldComponentUpdate(nextProps) {
43969
+ return nextProps !== this.props;
44045
43970
  }
44046
43971
  render() {
44047
43972
  const apiOptions = _extends({}, ApiOptions.defaults, this.props.apiOptions, {
@@ -44067,7 +43992,7 @@ class ArticleRenderer extends React.Component {
44067
43992
  ref: refForSection,
44068
43993
  key: i,
44069
43994
  key_: i,
44070
- keypadElement: this.keypadElement(),
43995
+ keypadElement: this.props.keypadElement,
44071
43996
  apiOptions: _extends({}, apiOptions, {
44072
43997
  onFocusChange: (newFocusPath, oldFocusPath) => {
44073
43998
  // Prefix the paths with the relevant section,
@@ -44435,6 +44360,73 @@ const styles$4 = StyleSheet.create({
44435
44360
  }
44436
44361
  });
44437
44362
 
44363
+ /* eslint-disable @khanacademy/ts-no-error-suppressions */
44364
+ // NOTE: This is not a real component. It's a collection of methods used to
44365
+ // create and manage a Keypad instances.
44366
+ // TODO(LP-10789): replace this with a React Context object to pass information
44367
+ // between Perseus and the Keypad.
44368
+ const ProvideKeypad = {
44369
+ getInitialState() {
44370
+ const _this = this;
44371
+ let keypadElement = null;
44372
+ if (_this.props.apiOptions && _this.props.apiOptions.customKeypad && _this.props.apiOptions.nativeKeypadProxy) {
44373
+ keypadElement = _this.props.apiOptions.nativeKeypadProxy(
44374
+ // @ts-expect-error - TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'. | TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
44375
+ () => _this.blur && _this.blur());
44376
+ }
44377
+ return {
44378
+ keypadElement
44379
+ };
44380
+ },
44381
+ componentDidMount() {
44382
+ const _this = this;
44383
+ const apiOptions = _this.props.apiOptions;
44384
+ if (apiOptions && apiOptions.customKeypad && !apiOptions.nativeKeypadProxy) {
44385
+ var _document$body;
44386
+ // TODO(charlie): Render this and the wrapped component in the same
44387
+ // React tree. We may also want to add this keypad asynchronously
44388
+ // or on-demand in the future.
44389
+ _this._keypadContainer = document.createElement("div");
44390
+ (_document$body = document.body) == null ? void 0 : _document$body.appendChild(_this._keypadContainer);
44391
+ render( /*#__PURE__*/React.createElement(MobileKeypad, {
44392
+ onElementMounted: element => {
44393
+ // NOTE(kevinb): The reason why this setState works is
44394
+ // b/c we're calling it manually from item-renderer.jsx
44395
+ // and we're manually setting the 'this' by using 'call'
44396
+ // @ts-expect-error - TS2339 - Property 'setState' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
44397
+ _this.setState({
44398
+ keypadElement: element
44399
+ });
44400
+ },
44401
+ onDismiss: () => {
44402
+ // @ts-expect-error - TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'. | TS2339 - Property 'blur' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
44403
+ _this.blur && _this.blur();
44404
+ }
44405
+ // @ts-expect-error - TS2339 - Property 'props' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
44406
+ ,
44407
+ style: _this.props.keypadStyle,
44408
+ useV2Keypad: apiOptions.useV2Keypad
44409
+ }), _this._keypadContainer);
44410
+ }
44411
+ },
44412
+ componentWillUnmount() {
44413
+ const _this = this;
44414
+ if (_this._keypadContainer) {
44415
+ ReactDOM__default.unmountComponentAtNode(_this._keypadContainer);
44416
+ if (_this._keypadContainer.parentNode) {
44417
+ // Note ChildNode.remove() isn't available in older Android
44418
+ // webviews.
44419
+ _this._keypadContainer.parentNode.removeChild(_this._keypadContainer);
44420
+ }
44421
+ _this._keypadContainer = null;
44422
+ }
44423
+ },
44424
+ keypadElement() {
44425
+ const _this = this;
44426
+ return _this.state.keypadElement;
44427
+ }
44428
+ };
44429
+
44438
44430
  const {
44439
44431
  mapObject: mapObject$1
44440
44432
  } = objective_;
@@ -44925,8 +44917,8 @@ class ServerItemRenderer extends React.Component {
44925
44917
  return Util.inputPathsEqual(inputPath, this._currentFocus);
44926
44918
  });
44927
44919
  if (onFocusChange != null) {
44928
- onFocusChange(this._currentFocus, prevFocus, didFocusInput && keypadElement && keypadElement.getDOMNode(),
44929
- // @ts-expect-error - TS2345 - Argument of type 'false | Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement | undefined'.
44920
+ onFocusChange(this._currentFocus, prevFocus, didFocusInput ? keypadElement == null ? void 0 : keypadElement.getDOMNode() : null,
44921
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'false | Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement | undefined'.
44930
44922
  didFocusInput && this.questionRenderer.getDOMNodeForPath(newFocus));
44931
44923
  }
44932
44924
  if (keypadElement && isMobile) {