@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 +12 -0
- package/dist/article-renderer.d.ts +5 -7
- package/dist/es/index.js +81 -89
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +81 -89
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +2 -2
- package/dist/server-item-renderer.d.ts +5 -4
- package/dist/types.d.ts +2 -1
- package/dist/widgets/expression.d.ts +12 -12
- package/package.json +5 -4
- package/src/__stories__/article-renderer.stories.tsx +22 -0
- package/src/__testdata__/article-renderer.testdata.ts +28 -0
- package/src/__tests__/server-item-renderer.test.tsx +12 -4
- package/src/article-renderer.tsx +14 -27
- package/src/server-item-renderer.tsx +10 -7
- package/src/types.ts +2 -4
- package/src/widgets/__stories__/expression.stories.tsx +3 -3
- package/tsconfig-build.tsbuildinfo +1 -1
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
|
-
|
|
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
|
|
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
|
|
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
|
|
44041
|
-
return nextProps !== this.props
|
|
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
|
|
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) {
|