@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 +20 -0
- package/dist/article-renderer.d.ts +5 -7
- package/dist/es/index.js +83 -90
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +83 -90
- 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/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +5 -5
- package/src/server-item-renderer.tsx +10 -7
- package/src/types.ts +2 -4
- package/src/widgets/__stories__/expression.stories.tsx +3 -3
- package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +5 -5
- package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +28 -28
- package/src/widgets/radio/choice.tsx +2 -1
- package/tsconfig-build.tsbuildinfo +1 -1
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
|
-
|
|
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
|
@@ -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
|
-
|
|
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
|
|
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
|
|
44041
|
-
return nextProps !== this.props
|
|
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
|
|
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) {
|