@khanacademy/perseus 10.1.0 → 11.1.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,25 @@
1
1
  # @khanacademy/perseus
2
2
 
3
+ ## 11.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8dc86906: Ensure that radio widget choices can scroll horizontally, but not vertically.
8
+ Previously, unnecessary vertical scrollbars appeared on some choices containing
9
+ MathJax elements.
10
+
11
+ ## 11.0.0
12
+
13
+ ### Major Changes
14
+
15
+ - 2af4f9fa: Switch from using ProvideKeypad in ArticleRenderer to passing the keypad element down instead
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [2af4f9fa]
20
+ - @khanacademy/math-input@11.0.0
21
+ - @khanacademy/perseus-core@1.0.0
22
+
3
23
  ## 10.1.0
4
24
 
5
25
  ### 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
@@ -22719,7 +22719,8 @@ const Choice = function Choice(props) {
22719
22719
  display: "flex",
22720
22720
  flexDirection: "row",
22721
22721
  opacity: showDimmed ? 0.5 : 1.0,
22722
- overflow: "auto"
22722
+ overflowX: "auto",
22723
+ overflowY: "hidden"
22723
22724
  }
22724
22725
  }, /*#__PURE__*/React.createElement("div", {
22725
22726
  className: "perseus-sr-only"
@@ -43882,80 +43883,10 @@ registerWidgets(allWidgets);
43882
43883
  const ItemVersion = getVersionVector();
43883
43884
  ItemVersion["::renderer::"] = version.itemDataVersion;
43884
43885
 
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
43886
  class ArticleRenderer extends React.Component {
43953
43887
  constructor(props) {
43954
43888
  super(props);
43955
43889
  this._currentFocus = void 0;
43956
- this.keypadElement = () => {
43957
- return ProvideKeypad.keypadElement.call(this);
43958
- };
43959
43890
  this._handleFocusChange = (newFocusPath, oldFocusPath) => {
43960
43891
  // TODO(charlie): DRY this up--some of this logic is repeated in
43961
43892
  // ItemRenderer.
@@ -43966,7 +43897,13 @@ class ArticleRenderer extends React.Component {
43966
43897
  }
43967
43898
  };
43968
43899
  this._setCurrentFocus = newFocusPath => {
43969
- const keypadElement = this.keypadElement();
43900
+ const {
43901
+ keypadElement,
43902
+ apiOptions
43903
+ } = this.props;
43904
+ const {
43905
+ isMobile
43906
+ } = apiOptions;
43970
43907
  const prevFocusPath = this._currentFocus;
43971
43908
  this._currentFocus = newFocusPath;
43972
43909
 
@@ -43984,18 +43921,12 @@ class ArticleRenderer extends React.Component {
43984
43921
  });
43985
43922
  }
43986
43923
  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());
43924
+ this.props.apiOptions.onFocusChange(this._currentFocus, prevFocusPath, didFocusInput ? keypadElement == null ? void 0 : keypadElement.getDOMNode() : null);
43990
43925
  }
43991
-
43992
- // @ts-expect-error - TS1345 - An expression of type 'void' cannot be tested for truthiness.
43993
- if (keypadElement) {
43926
+ if (keypadElement && isMobile) {
43994
43927
  if (didFocusInput) {
43995
- // @ts-expect-error - TS2339 - Property 'activate' does not exist on type 'never'.
43996
43928
  keypadElement.activate();
43997
43929
  } else {
43998
- // @ts-expect-error - TS2339 - Property 'dismiss' does not exist on type 'never'.
43999
43930
  keypadElement.dismiss();
44000
43931
  }
44001
43932
  }
@@ -44031,17 +43962,12 @@ class ArticleRenderer extends React.Component {
44031
43962
  this._sections = () => {
44032
43963
  return Array.isArray(this.props.json) ? this.props.json : [this.props.json];
44033
43964
  };
44034
- this.state = ProvideKeypad.getInitialState.call(this);
44035
43965
  }
44036
43966
  componentDidMount() {
44037
- ProvideKeypad.componentDidMount.call(this);
44038
43967
  this._currentFocus = null;
44039
43968
  }
44040
- shouldComponentUpdate(nextProps, nextState) {
44041
- return nextProps !== this.props || nextState !== this.state;
44042
- }
44043
- componentWillUnmount() {
44044
- ProvideKeypad.componentWillUnmount.call(this);
43969
+ shouldComponentUpdate(nextProps) {
43970
+ return nextProps !== this.props;
44045
43971
  }
44046
43972
  render() {
44047
43973
  const apiOptions = _extends({}, ApiOptions.defaults, this.props.apiOptions, {
@@ -44067,7 +43993,7 @@ class ArticleRenderer extends React.Component {
44067
43993
  ref: refForSection,
44068
43994
  key: i,
44069
43995
  key_: i,
44070
- keypadElement: this.keypadElement(),
43996
+ keypadElement: this.props.keypadElement,
44071
43997
  apiOptions: _extends({}, apiOptions, {
44072
43998
  onFocusChange: (newFocusPath, oldFocusPath) => {
44073
43999
  // Prefix the paths with the relevant section,
@@ -44435,6 +44361,73 @@ const styles$4 = StyleSheet.create({
44435
44361
  }
44436
44362
  });
44437
44363
 
44364
+ /* eslint-disable @khanacademy/ts-no-error-suppressions */
44365
+ // NOTE: This is not a real component. It's a collection of methods used to
44366
+ // create and manage a Keypad instances.
44367
+ // TODO(LP-10789): replace this with a React Context object to pass information
44368
+ // between Perseus and the Keypad.
44369
+ const ProvideKeypad = {
44370
+ getInitialState() {
44371
+ const _this = this;
44372
+ let keypadElement = null;
44373
+ if (_this.props.apiOptions && _this.props.apiOptions.customKeypad && _this.props.apiOptions.nativeKeypadProxy) {
44374
+ keypadElement = _this.props.apiOptions.nativeKeypadProxy(
44375
+ // @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...'.
44376
+ () => _this.blur && _this.blur());
44377
+ }
44378
+ return {
44379
+ keypadElement
44380
+ };
44381
+ },
44382
+ componentDidMount() {
44383
+ const _this = this;
44384
+ const apiOptions = _this.props.apiOptions;
44385
+ if (apiOptions && apiOptions.customKeypad && !apiOptions.nativeKeypadProxy) {
44386
+ var _document$body;
44387
+ // TODO(charlie): Render this and the wrapped component in the same
44388
+ // React tree. We may also want to add this keypad asynchronously
44389
+ // or on-demand in the future.
44390
+ _this._keypadContainer = document.createElement("div");
44391
+ (_document$body = document.body) == null ? void 0 : _document$body.appendChild(_this._keypadContainer);
44392
+ render( /*#__PURE__*/React.createElement(MobileKeypad, {
44393
+ onElementMounted: element => {
44394
+ // NOTE(kevinb): The reason why this setState works is
44395
+ // b/c we're calling it manually from item-renderer.jsx
44396
+ // and we're manually setting the 'this' by using 'call'
44397
+ // @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...'.
44398
+ _this.setState({
44399
+ keypadElement: element
44400
+ });
44401
+ },
44402
+ onDismiss: () => {
44403
+ // @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...'.
44404
+ _this.blur && _this.blur();
44405
+ }
44406
+ // @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...'.
44407
+ ,
44408
+ style: _this.props.keypadStyle,
44409
+ useV2Keypad: apiOptions.useV2Keypad
44410
+ }), _this._keypadContainer);
44411
+ }
44412
+ },
44413
+ componentWillUnmount() {
44414
+ const _this = this;
44415
+ if (_this._keypadContainer) {
44416
+ ReactDOM__default.unmountComponentAtNode(_this._keypadContainer);
44417
+ if (_this._keypadContainer.parentNode) {
44418
+ // Note ChildNode.remove() isn't available in older Android
44419
+ // webviews.
44420
+ _this._keypadContainer.parentNode.removeChild(_this._keypadContainer);
44421
+ }
44422
+ _this._keypadContainer = null;
44423
+ }
44424
+ },
44425
+ keypadElement() {
44426
+ const _this = this;
44427
+ return _this.state.keypadElement;
44428
+ }
44429
+ };
44430
+
44438
44431
  const {
44439
44432
  mapObject: mapObject$1
44440
44433
  } = objective_;
@@ -44925,8 +44918,8 @@ class ServerItemRenderer extends React.Component {
44925
44918
  return Util.inputPathsEqual(inputPath, this._currentFocus);
44926
44919
  });
44927
44920
  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'.
44921
+ onFocusChange(this._currentFocus, prevFocus, didFocusInput ? keypadElement == null ? void 0 : keypadElement.getDOMNode() : null,
44922
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'false | Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement | undefined'.
44930
44923
  didFocusInput && this.questionRenderer.getDOMNodeForPath(newFocus));
44931
44924
  }
44932
44925
  if (keypadElement && isMobile) {