@khanacademy/perseus 4.0.1 → 4.0.2
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 +11 -0
- package/dist/components/highlighting/ui/highlighting-ui.d.ts +1 -1
- package/dist/es/index.js +46 -223
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +46 -223
- package/dist/index.js.map +1 -1
- package/dist/multi-items/multi-renderer.d.ts +1 -1
- package/dist/multi-items/multi-renderer.js.flow +1 -1
- package/dist/multi-items/prop-type-builders.d.ts +1 -1
- package/dist/multi-items/shape-types.d.ts +1 -1
- package/dist/multi-items/shape-types.js.flow +1 -1
- package/dist/multi-items/tree-types.d.ts +1 -1
- package/dist/multi-items/tree-types.js.flow +1 -1
- package/dist/widgets/__stories__/test-keypad-context-wrapper.d.ts +6 -0
- package/dist/widgets/__stories__/test-keypad-context-wrapper.js.flow +14 -0
- package/package.json +4 -4
- package/src/__testdata__/item-renderer.testdata.ts +1 -1
- package/src/__testdata__/renderer.testdata.ts +1 -1
- package/src/__tests__/item-renderer.test.tsx +1 -2
- package/src/__tests__/renderer-api.test.tsx +1 -5
- package/src/__tests__/renderer.test.tsx +1 -1
- package/src/components/fixed-to-responsive.tsx +0 -1
- package/src/components/graph.tsx +0 -4
- package/src/components/highlighting/ui/highlighting-ui.tsx +3 -13
- package/src/components/highlighting/ui/selection-tracker.tsx +1 -1
- package/src/components/highlighting/word-indexer.tsx +0 -4
- package/src/components/math-input.tsx +0 -2
- package/src/components/number-input.tsx +0 -2
- package/src/components/text-list-editor.tsx +0 -4
- package/src/components/zoomable-tex.tsx +0 -2
- package/src/components/zoomable.tsx +0 -4
- package/src/definition-context.tsx +0 -1
- package/src/hints-renderer.tsx +1 -1
- package/src/interactive2/__tests__/movable-point.test.ts +0 -1
- package/src/item-renderer.tsx +0 -5
- package/src/mixins/changeable.ts +1 -1
- package/src/multi-items/__stories__/multi-renderer.stories.tsx +0 -4
- package/src/multi-items/__tests__/items.test.ts +3 -13
- package/src/multi-items/__tests__/multi-renderer.test.tsx +1 -1
- package/src/multi-items/__tests__/prop-type-builders.test.ts +1 -1
- package/src/multi-items/__tests__/trees.test.ts +2 -10
- package/src/multi-items/multi-renderer.tsx +7 -10
- package/src/multi-items/prop-type-builders.ts +1 -1
- package/src/multi-items/shape-types.ts +1 -1
- package/src/multi-items/tree-types.ts +1 -1
- package/src/perseus-markdown.tsx +0 -2
- package/src/perseus-types.ts +1 -1
- package/src/renderer.tsx +2 -5
- package/src/server-item-renderer.tsx +0 -3
- package/src/util/interactive.ts +0 -4
- package/src/util/math.ts +0 -3
- package/src/widgets/__stories__/expression.stories.tsx +113 -7
- package/src/widgets/__stories__/image.stories.tsx +1 -1
- package/src/widgets/__stories__/{on-screen-keypad.stories.tsx → test-keypad-context-wrapper.tsx} +17 -57
- package/src/widgets/__testdata__/expression.testdata.ts +16 -12
- package/src/widgets/__testdata__/numeric-input.testdata.ts +0 -1
- package/src/widgets/__testdata__/transformer.testdata.ts +0 -1
- package/src/widgets/__tests__/radio.test.ts +1 -1
- package/src/widgets/expression.tsx +1 -1
- package/src/widgets/graded-group-set.tsx +0 -4
- package/src/widgets/graded-group.tsx +0 -4
- package/src/widgets/grapher/util.tsx +1 -5
- package/src/widgets/grapher.tsx +0 -5
- package/src/widgets/group.tsx +0 -1
- package/src/widgets/interaction.tsx +0 -1
- package/src/widgets/interactive-graph.tsx +3 -62
- package/src/widgets/label-image.tsx +1 -1
- package/src/widgets/measurer.tsx +0 -1
- package/src/widgets/number-line.tsx +0 -2
- package/src/widgets/orderer.tsx +0 -3
- package/src/widgets/passage/passage-markdown.tsx +1 -1
- package/src/widgets/passage-ref-target.tsx +0 -1
- package/src/widgets/passage.tsx +1 -1
- package/src/widgets/plotter.tsx +0 -1
- package/src/widgets/radio/__stories__/base-radio.stories.tsx +2 -2
- package/src/widgets/radio/base-radio.tsx +1 -1
- package/src/widgets/transformer.tsx +1 -16
- package/src/widgets.ts +1 -1
- package/src/zoom.ts +0 -3
- package/tsconfig.tsbuildinfo +1 -1
package/src/perseus-types.ts
CHANGED
|
@@ -1423,7 +1423,7 @@ export type PerseusInputNumberWidgetOptions = {
|
|
|
1423
1423
|
customKeypad?: boolean;
|
|
1424
1424
|
};
|
|
1425
1425
|
|
|
1426
|
-
// TODO(FEI-3983): Create proper
|
|
1426
|
+
// TODO(FEI-3983): Create proper types for these.
|
|
1427
1427
|
export type PerseusExampleGraphieWidgetOptions = any;
|
|
1428
1428
|
export type PerseusExampleWidgetOptions = any;
|
|
1429
1429
|
export type PerseusLightsPuzzleWidgetOptions = any;
|
package/src/renderer.tsx
CHANGED
|
@@ -150,7 +150,7 @@ type Props = {
|
|
|
150
150
|
findExternalWidgets: any;
|
|
151
151
|
highlightedWidgets?: ReadonlyArray<any>;
|
|
152
152
|
images: PerseusRenderer["images"];
|
|
153
|
-
keypadElement?: any; // TODO(kevinb): add proper
|
|
153
|
+
keypadElement?: any; // TODO(kevinb): add proper types,
|
|
154
154
|
onInteractWithWidget: (id: string) => void;
|
|
155
155
|
onRender: (node?: any) => void;
|
|
156
156
|
problemNum?: number;
|
|
@@ -593,11 +593,9 @@ class Renderer extends React.Component<Props, State> {
|
|
|
593
593
|
interactionTracker = this._interactionTrackers[id] =
|
|
594
594
|
new InteractionTracker(
|
|
595
595
|
apiOptions.trackInteraction,
|
|
596
|
-
// $FlowFixMe[incompatible-call]
|
|
597
596
|
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
598
597
|
widgetInfo && widgetInfo.type,
|
|
599
598
|
id,
|
|
600
|
-
// $FlowFixMe[incompatible-call]
|
|
601
599
|
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
602
600
|
Widgets.getTracking(widgetInfo && widgetInfo.type),
|
|
603
601
|
);
|
|
@@ -1086,7 +1084,7 @@ class Renderer extends React.Component<Props, State> {
|
|
|
1086
1084
|
const isString = typeof nodeOut === "string";
|
|
1087
1085
|
if (typeof nodeOut === "string" && lastWasString) {
|
|
1088
1086
|
/**
|
|
1089
|
-
* We know that last was string, but
|
|
1087
|
+
* We know that last was string, but TypeScript can't see this
|
|
1090
1088
|
* refinement.
|
|
1091
1089
|
*/
|
|
1092
1090
|
result[result.length - 1] += nodeOut;
|
|
@@ -1308,7 +1306,6 @@ class Renderer extends React.Component<Props, State> {
|
|
|
1308
1306
|
{({setAssetStatus}) => (
|
|
1309
1307
|
<SvgImage
|
|
1310
1308
|
setAssetStatus={setAssetStatus}
|
|
1311
|
-
/* $FlowFixMe[incompatible-type]: sanitizeUrl() can return null */
|
|
1312
1309
|
// @ts-expect-error [FEI-5003] - TS2322 - Type 'string | null | undefined' is not assignable to type 'string | undefined'.
|
|
1313
1310
|
src={PerseusMarkdown.sanitizeUrl(node.target)}
|
|
1314
1311
|
alt={node.alt}
|
|
@@ -171,12 +171,9 @@ export class ServerItemRenderer
|
|
|
171
171
|
onFocusChange(
|
|
172
172
|
this._currentFocus,
|
|
173
173
|
prevFocus,
|
|
174
|
-
// $FlowFixMe[incompatible-call]: onFocusChange expects an HTMLElement or nothing
|
|
175
174
|
didFocusInput && keypadElement && keypadElement.getDOMNode(),
|
|
176
|
-
// $FlowFixMe[incompatible-call]: onFocusChange expects an HTMLElement or nothing
|
|
177
175
|
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'false | Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement | undefined'.
|
|
178
176
|
didFocusInput &&
|
|
179
|
-
// $FlowFixMe[incompatible-call]: onFocusChange expects an HTMLElement or nothing
|
|
180
177
|
this.questionRenderer.getDOMNodeForPath(newFocus),
|
|
181
178
|
);
|
|
182
179
|
}
|
package/src/util/interactive.ts
CHANGED
|
@@ -3510,7 +3510,6 @@ function Protractor(graph: any, center: any) {
|
|
|
3510
3510
|
}
|
|
3511
3511
|
const time = Math.abs(this.rotation - angle) * 5;
|
|
3512
3512
|
$({0: this.rotation}).animate(
|
|
3513
|
-
// $FlowFixMe[unsupported-syntax]
|
|
3514
3513
|
{0: angle},
|
|
3515
3514
|
{
|
|
3516
3515
|
duration: time,
|
|
@@ -3578,11 +3577,8 @@ function Ruler(graphie: any, options: any) {
|
|
|
3578
3577
|
if (options.ticksPerUnit === 10) {
|
|
3579
3578
|
// decimal, as on a centimeter ruler
|
|
3580
3579
|
tickHeightMap = {
|
|
3581
|
-
// $FlowFixMe[unsupported-syntax]
|
|
3582
3580
|
10: tickHeight,
|
|
3583
|
-
// $FlowFixMe[unsupported-syntax]
|
|
3584
3581
|
5: tickHeight * 0.55,
|
|
3585
|
-
// $FlowFixMe[unsupported-syntax]
|
|
3586
3582
|
1: tickHeight * 0.35,
|
|
3587
3583
|
};
|
|
3588
3584
|
} else {
|
package/src/util/math.ts
CHANGED
|
@@ -91,8 +91,6 @@ const KhanMath = {
|
|
|
91
91
|
|
|
92
92
|
return true;
|
|
93
93
|
},
|
|
94
|
-
|
|
95
|
-
// $FlowFixMe[incompatible-return]
|
|
96
94
|
// @ts-expect-error [FEI-5003] - TS2366 - Function lacks ending return statement and return type does not include 'undefined'.
|
|
97
95
|
getPrimeFactorization: function (number: number): ReadonlyArray<number> {
|
|
98
96
|
if (number === 1) {
|
|
@@ -160,7 +158,6 @@ const KhanMath = {
|
|
|
160
158
|
// tolerance can't be bigger than 1, sorry
|
|
161
159
|
toFraction: function (
|
|
162
160
|
decimal: number,
|
|
163
|
-
// $FlowFixMe[incompatible-return]
|
|
164
161
|
tolerance?: number,
|
|
165
162
|
): [number, number] {
|
|
166
163
|
if (tolerance == null) {
|
|
@@ -1,29 +1,135 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {ItemRendererWithDebugUI} from "../../../../../testing/item-renderer-with-debug-ui";
|
|
4
|
+
import KeypadContext from "../../keypad-context";
|
|
4
5
|
import {
|
|
5
6
|
expressionItem2,
|
|
6
7
|
expressionItem3,
|
|
7
8
|
} from "../__testdata__/expression.testdata";
|
|
9
|
+
import expressionExport from "../expression";
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
import TestKeypadContext from "./test-keypad-context-wrapper";
|
|
12
|
+
|
|
13
|
+
import type {PerseusItem} from "../../perseus-types";
|
|
14
|
+
|
|
15
|
+
type StoryArgs = {
|
|
16
|
+
customKeypad: boolean;
|
|
17
|
+
};
|
|
10
18
|
|
|
11
19
|
type Story = {
|
|
12
20
|
title: string;
|
|
21
|
+
argTypes: any;
|
|
13
22
|
};
|
|
14
23
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
type WrappedKeypadContextProps = {
|
|
25
|
+
item: PerseusItem;
|
|
26
|
+
customKeypad: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const WrappedKeypadContext = (props: WrappedKeypadContextProps) => {
|
|
30
|
+
return (
|
|
31
|
+
<TestKeypadContext>
|
|
32
|
+
<KeypadContext.Consumer>
|
|
33
|
+
{({keypadElement, setRenderer, scrollableElement}) => {
|
|
34
|
+
return (
|
|
35
|
+
<ItemRendererWithDebugUI
|
|
36
|
+
item={props.item}
|
|
37
|
+
apiOptions={{
|
|
38
|
+
customKeypad: props.customKeypad,
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}}
|
|
43
|
+
</KeypadContext.Consumer>
|
|
44
|
+
</TestKeypadContext>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const DesktopKitchenSink: React.FC<StoryArgs> = (
|
|
49
|
+
args,
|
|
50
|
+
): React.ReactElement => {
|
|
51
|
+
const reviewModeRubric = {
|
|
52
|
+
functions: ["f", "g", "h"],
|
|
53
|
+
times: true,
|
|
54
|
+
answerForms: [],
|
|
55
|
+
buttonSets: [
|
|
56
|
+
"basic",
|
|
57
|
+
"basic+div",
|
|
58
|
+
"trig",
|
|
59
|
+
"prealgebra",
|
|
60
|
+
"logarithms",
|
|
61
|
+
"basic relations",
|
|
62
|
+
"advanced relations",
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const keypadConfiguration = {
|
|
67
|
+
keypadType: "EXPRESSION",
|
|
68
|
+
extraKeys: ["x", "y", "z"],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div style={{padding: "2rem"}}>
|
|
73
|
+
<expressionExport.widget
|
|
74
|
+
alignment={null}
|
|
75
|
+
value=""
|
|
76
|
+
containerSizeClass="small"
|
|
77
|
+
findWidgets={(callback) => []}
|
|
78
|
+
isLastUsedWidget={false}
|
|
79
|
+
onChange={() => {}}
|
|
80
|
+
problemNum={1}
|
|
81
|
+
static={false}
|
|
82
|
+
trackInteraction={() => {}}
|
|
83
|
+
widgetId="expression"
|
|
84
|
+
reviewModeRubric={reviewModeRubric}
|
|
85
|
+
keypadConfiguration={keypadConfiguration}
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const Desktop: React.FC<StoryArgs> = (args): React.ReactElement => {
|
|
92
|
+
return <WrappedKeypadContext item={expressionItem3} customKeypad={false} />;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const Mobile: React.FC<StoryArgs> = (args): React.ReactElement => {
|
|
96
|
+
return (
|
|
97
|
+
<div>
|
|
98
|
+
<p>
|
|
99
|
+
For some reason you need to be{" "}
|
|
100
|
+
<a href="https://developer.chrome.com/docs/devtools/device-mode/">
|
|
101
|
+
emulating mobile
|
|
102
|
+
</a>{" "}
|
|
103
|
+
to see the custom keypad.
|
|
104
|
+
</p>
|
|
105
|
+
<WrappedKeypadContext item={expressionItem3} customKeypad={true} />
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
18
109
|
|
|
19
110
|
export const ExpressionItem2: React.FC<StoryArgs> = (
|
|
20
111
|
args,
|
|
21
112
|
): React.ReactElement => {
|
|
22
|
-
return
|
|
113
|
+
return (
|
|
114
|
+
<WrappedKeypadContext
|
|
115
|
+
item={expressionItem2}
|
|
116
|
+
customKeypad={args.customKeypad}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
23
119
|
};
|
|
24
120
|
|
|
25
121
|
export const ExpressionItem3: React.FC<StoryArgs> = (
|
|
26
122
|
args,
|
|
27
123
|
): React.ReactElement => {
|
|
28
|
-
return
|
|
124
|
+
return (
|
|
125
|
+
<WrappedKeypadContext
|
|
126
|
+
item={expressionItem3}
|
|
127
|
+
customKeypad={args.customKeypad}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
29
130
|
};
|
|
131
|
+
|
|
132
|
+
export default {
|
|
133
|
+
title: "Perseus/Widgets/Expression",
|
|
134
|
+
argTypes: {customKeypad: {control: "boolean"}},
|
|
135
|
+
} as Story;
|
|
@@ -31,7 +31,7 @@ export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
|
|
|
31
31
|
options:
|
|
32
32
|
// `options` is nullable so we have handle it explicitly
|
|
33
33
|
// to avoid spreading `null` and generating
|
|
34
|
-
// hard-to-understand
|
|
34
|
+
// hard-to-understand type errors about missing keys
|
|
35
35
|
// in object literal.
|
|
36
36
|
imageOptions != null
|
|
37
37
|
? {
|
package/src/widgets/__stories__/{on-screen-keypad.stories.tsx → test-keypad-context-wrapper.tsx}
RENAMED
|
@@ -3,60 +3,11 @@ import {View} from "@khanacademy/wonder-blocks-core";
|
|
|
3
3
|
import {StyleSheet} from "aphrodite";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
|
|
6
|
-
import {ItemRenderer} from "../../index";
|
|
7
6
|
import KeypadContext from "../../keypad-context";
|
|
8
|
-
import {expressionItem3} from "../__testdata__/expression.testdata";
|
|
9
|
-
|
|
10
|
-
type StoryArgs = Record<any, any>;
|
|
11
|
-
|
|
12
|
-
type Story = {
|
|
13
|
-
title: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export default {
|
|
17
|
-
title: "Perseus/Demos/On Screen Keypad",
|
|
18
|
-
} as Story;
|
|
19
|
-
|
|
20
|
-
const Content = (): React.ReactElement => {
|
|
21
|
-
return (
|
|
22
|
-
<KeypadContext.Consumer>
|
|
23
|
-
{({keypadElement, setRenderer, scrollableElement}) => (
|
|
24
|
-
<>
|
|
25
|
-
<ItemRenderer
|
|
26
|
-
ref={setRenderer}
|
|
27
|
-
problemNum={0}
|
|
28
|
-
apiOptions={{
|
|
29
|
-
customKeypad: true,
|
|
30
|
-
onFocusChange: (
|
|
31
|
-
newFocusPath,
|
|
32
|
-
oldFocusPath,
|
|
33
|
-
keypadElement,
|
|
34
|
-
focusedElement,
|
|
35
|
-
) => {},
|
|
36
|
-
}}
|
|
37
|
-
item={expressionItem3}
|
|
38
|
-
savedState={null}
|
|
39
|
-
/>
|
|
40
|
-
<div id="workarea" />
|
|
41
|
-
<div id="hintsarea" />
|
|
42
|
-
</>
|
|
43
|
-
)}
|
|
44
|
-
</KeypadContext.Consumer>
|
|
45
|
-
);
|
|
46
|
-
};
|
|
47
7
|
|
|
48
8
|
const Footer = (): React.ReactElement => {
|
|
49
9
|
return (
|
|
50
|
-
<View
|
|
51
|
-
style={[
|
|
52
|
-
styles.keypadContainer,
|
|
53
|
-
{
|
|
54
|
-
// NOTE: in webapp we normally get this from problemProgress
|
|
55
|
-
// from the exercise state store.
|
|
56
|
-
height: 240,
|
|
57
|
-
},
|
|
58
|
-
]}
|
|
59
|
-
>
|
|
10
|
+
<View style={styles.keypadContainer}>
|
|
60
11
|
<KeypadContext.Consumer>
|
|
61
12
|
{({keypadElement, setKeypadElement, renderer}) => (
|
|
62
13
|
<Keypad
|
|
@@ -70,9 +21,15 @@ const Footer = (): React.ReactElement => {
|
|
|
70
21
|
);
|
|
71
22
|
};
|
|
72
23
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
24
|
+
type TestKeypadContextWrapperProps = {
|
|
25
|
+
children: React.ReactElement;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const TestKeypadContextWrapper = (
|
|
29
|
+
props: TestKeypadContextWrapperProps,
|
|
30
|
+
): React.ReactElement => {
|
|
31
|
+
const [keypadElement, setKeypadElement] = React.useState(null);
|
|
32
|
+
const [renderer, setRenderer] = React.useState(null);
|
|
76
33
|
const [scrollableElement, setScrollableElement] = React.useState(
|
|
77
34
|
document.body,
|
|
78
35
|
);
|
|
@@ -80,8 +37,10 @@ const Demo = () => {
|
|
|
80
37
|
return (
|
|
81
38
|
<KeypadContext.Provider
|
|
82
39
|
value={{
|
|
40
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'Dispatch<SetStateAction<HTMLElement>>' is not assignable to type '(scrollableElement?: HTMLElement | null | undefined) => void'.
|
|
83
41
|
setKeypadElement,
|
|
84
42
|
keypadElement,
|
|
43
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'Dispatch<SetStateAction<HTMLElement>>' is not assignable to type '(scrollableElement?: HTMLElement | null | undefined) => void'.
|
|
85
44
|
setRenderer,
|
|
86
45
|
renderer,
|
|
87
46
|
// @ts-expect-error [FEI-5003] - TS2322 - Type 'Dispatch<SetStateAction<HTMLElement>>' is not assignable to type '(scrollableElement?: HTMLElement | null | undefined) => void'.
|
|
@@ -89,15 +48,13 @@ const Demo = () => {
|
|
|
89
48
|
scrollableElement,
|
|
90
49
|
}}
|
|
91
50
|
>
|
|
92
|
-
|
|
51
|
+
{props.children}
|
|
93
52
|
<Footer />
|
|
94
53
|
</KeypadContext.Provider>
|
|
95
54
|
);
|
|
96
55
|
};
|
|
97
56
|
|
|
98
|
-
export
|
|
99
|
-
<Demo />
|
|
100
|
-
);
|
|
57
|
+
export default TestKeypadContextWrapper;
|
|
101
58
|
|
|
102
59
|
const styles = StyleSheet.create({
|
|
103
60
|
keypad: {
|
|
@@ -116,5 +73,8 @@ const styles = StyleSheet.create({
|
|
|
116
73
|
// Prevent container from swallowing events that the exercise
|
|
117
74
|
// below it needs to respond to.
|
|
118
75
|
pointerEvents: "none",
|
|
76
|
+
// NOTE: in webapp we normally get this from problemProgress
|
|
77
|
+
// from the exercise state store.
|
|
78
|
+
height: 240,
|
|
119
79
|
},
|
|
120
80
|
});
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
PerseusRenderer,
|
|
3
2
|
PerseusExpressionWidgetOptions,
|
|
4
3
|
Version,
|
|
4
|
+
PerseusItem,
|
|
5
5
|
} from "../../perseus-types";
|
|
6
6
|
|
|
7
|
-
type Item = {
|
|
8
|
-
question: PerseusRenderer;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
7
|
const createItemJson = (
|
|
12
8
|
widgetOptions: PerseusExpressionWidgetOptions,
|
|
13
9
|
version: Version,
|
|
14
|
-
):
|
|
10
|
+
): PerseusItem => {
|
|
15
11
|
return {
|
|
16
12
|
question: {
|
|
17
13
|
content: "[[☃ expression 1]]",
|
|
@@ -25,9 +21,14 @@ const createItemJson = (
|
|
|
25
21
|
},
|
|
26
22
|
},
|
|
27
23
|
},
|
|
28
|
-
|
|
24
|
+
_multi: null,
|
|
25
|
+
answer: null,
|
|
29
26
|
answerArea: {
|
|
27
|
+
zTable: false,
|
|
28
|
+
chi2Table: false,
|
|
29
|
+
tTable: false,
|
|
30
30
|
calculator: false,
|
|
31
|
+
periodicTable: false,
|
|
31
32
|
},
|
|
32
33
|
itemDataVersion: {
|
|
33
34
|
major: 0,
|
|
@@ -37,7 +38,7 @@ const createItemJson = (
|
|
|
37
38
|
};
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
export const expressionItem2:
|
|
41
|
+
export const expressionItem2: PerseusItem = createItemJson(
|
|
41
42
|
{
|
|
42
43
|
answerForms: [
|
|
43
44
|
{
|
|
@@ -88,7 +89,10 @@ export const expressionItem3Options: PerseusExpressionWidgetOptions = {
|
|
|
88
89
|
buttonsVisible: "focused",
|
|
89
90
|
};
|
|
90
91
|
|
|
91
|
-
export const expressionItem3:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
export const expressionItem3: PerseusItem = createItemJson(
|
|
93
|
+
expressionItem3Options,
|
|
94
|
+
{
|
|
95
|
+
major: 1,
|
|
96
|
+
minor: 0,
|
|
97
|
+
},
|
|
98
|
+
);
|
|
@@ -309,7 +309,7 @@ describe("single-choice question", () => {
|
|
|
309
309
|
questionWithPassage.content = `[[\u2603 passage 1]]\n\nNow what's the answer?\n\n[[\u2603 radio 1]]`;
|
|
310
310
|
questionWithPassage.widgets["passage 1"] = passageWidget;
|
|
311
311
|
const radioOptions = questionWithPassage.widgets["radio 1"];
|
|
312
|
-
// HACK(jeremy):
|
|
312
|
+
// HACK(jeremy): TypeScript doesn't know what type these options are because
|
|
313
313
|
// we've extracted them out of a generic `PerseusJson` blob and all the
|
|
314
314
|
// `widget` items are just type `Widget`.
|
|
315
315
|
(radioOptions.options as any).choices[0].content =
|
|
@@ -458,7 +458,7 @@ export class Expression extends React.Component<Props, ExpressionState> {
|
|
|
458
458
|
onFocus={() => {
|
|
459
459
|
// this.props.keypadElement should always be set
|
|
460
460
|
// when apiOptions.customKeypad is set, but how
|
|
461
|
-
// to convince
|
|
461
|
+
// to convince TypeScript of this?
|
|
462
462
|
this.props.keypadElement?.configure(
|
|
463
463
|
this.props.keypadConfiguration,
|
|
464
464
|
() => {
|
|
@@ -156,7 +156,6 @@ class GradedGroupSet extends React.Component<Props, State> {
|
|
|
156
156
|
return (
|
|
157
157
|
// TODO(jeremy): Don't spread this.props, instead
|
|
158
158
|
// pass in all props GradedGroup needs explicilty
|
|
159
|
-
// $FlowFixMe[prop-missing]
|
|
160
159
|
// @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call.
|
|
161
160
|
<GradedGroup
|
|
162
161
|
key={i}
|
|
@@ -200,7 +199,6 @@ class GradedGroupSet extends React.Component<Props, State> {
|
|
|
200
199
|
</div>
|
|
201
200
|
{/* TODO(jeremy): Don't spread this.props, instead
|
|
202
201
|
pass in all props GradedGroup needs explicitly */}
|
|
203
|
-
{/* $FlowFixMe[prop-missing] */}
|
|
204
202
|
{/* @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call. */}
|
|
205
203
|
<GradedGroup
|
|
206
204
|
key={this.state.currentGroup}
|
|
@@ -211,9 +209,7 @@ class GradedGroupSet extends React.Component<Props, State> {
|
|
|
211
209
|
{...this.props}
|
|
212
210
|
{...currentGroup}
|
|
213
211
|
inGradedGroupSet={true}
|
|
214
|
-
// $FlowFixMe[incompatible-type]
|
|
215
212
|
title={null}
|
|
216
|
-
// $FlowFixMe[incompatible-type]
|
|
217
213
|
onNextQuestion={handleNextQuestion}
|
|
218
214
|
linterContext={this.props.linterContext}
|
|
219
215
|
/>
|
|
@@ -252,7 +252,6 @@ export class GradedGroup extends React.Component<Props, State> {
|
|
|
252
252
|
: css(styles.gradedGroup);
|
|
253
253
|
|
|
254
254
|
const classes = classNames({
|
|
255
|
-
// $FlowFixMe[invalid-computed-prop]
|
|
256
255
|
[mobileClass]: apiOptions.isMobile,
|
|
257
256
|
"perseus-graded-group": true,
|
|
258
257
|
"answer-correct": apiOptions.isMobile
|
|
@@ -283,8 +282,6 @@ export class GradedGroup extends React.Component<Props, State> {
|
|
|
283
282
|
* props that are needed.
|
|
284
283
|
* TODO(FEI-4034): Only pass what the Renderer expects.
|
|
285
284
|
*/}
|
|
286
|
-
{/* $FlowFixMe[prop-missing] */}
|
|
287
|
-
{/* $FlowFixMe[incompatible-type] */}
|
|
288
285
|
{/* @ts-expect-error [FEI-5003] - TS2322 - Type '{ ref: string; apiOptions: any; onInteractWithWidget: (arg1: string) => void; linterContext: LinterContextProps; title: string; hasHint?: boolean | null | undefined; ... 22 more ...; children?: ReactNode; }' is not assignable to type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "keypadElement" | "problemNum" | "apiOptions" | "legacyPerseusLint">'. */}
|
|
289
286
|
<Renderer
|
|
290
287
|
{...this.props}
|
|
@@ -355,7 +352,6 @@ export class GradedGroup extends React.Component<Props, State> {
|
|
|
355
352
|
* We're passing a couple of props to Renderer that it doesn't
|
|
356
353
|
* require as part of {...this.props.hint}.
|
|
357
354
|
*/}
|
|
358
|
-
{/* $FlowFixMe[prop-missing] */}
|
|
359
355
|
<Renderer
|
|
360
356
|
{...this.props.hint}
|
|
361
357
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -149,8 +149,6 @@ const Quadratic = _.extend({}, PlotDefaults, {
|
|
|
149
149
|
[0.5, 0.5],
|
|
150
150
|
[0.75, 0.75],
|
|
151
151
|
],
|
|
152
|
-
|
|
153
|
-
// $FlowFixMe[prop-missing]
|
|
154
152
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'Parabola' does not exist on type 'typeof Graphie'.
|
|
155
153
|
Movable: Graphie.Parabola,
|
|
156
154
|
|
|
@@ -208,8 +206,6 @@ const Sinusoid = _.extend({}, PlotDefaults, {
|
|
|
208
206
|
[0.5, 0.5],
|
|
209
207
|
[0.6, 0.6],
|
|
210
208
|
],
|
|
211
|
-
|
|
212
|
-
// $FlowFixMe[prop-missing]
|
|
213
209
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'Sinusoid' does not exist on type 'typeof Graphie'.
|
|
214
210
|
Movable: Graphie.Sinusoid,
|
|
215
211
|
|
|
@@ -593,7 +589,7 @@ export const allTypes: any = _.keys(functionTypeMapping);
|
|
|
593
589
|
|
|
594
590
|
export function functionForType(
|
|
595
591
|
// TODO(jeremy): Actually `$Keys<typeof functionTypeMapping>` but that
|
|
596
|
-
// triggers
|
|
592
|
+
// triggers TypeScript to require all of our Plot types to be fully typed which
|
|
597
593
|
// is a big amount of work/change.
|
|
598
594
|
type: string,
|
|
599
595
|
): any {
|
package/src/widgets/grapher.tsx
CHANGED
|
@@ -119,10 +119,8 @@ class FunctionGrapher extends React.Component<FunctionGrapherProps> {
|
|
|
119
119
|
coord={coord}
|
|
120
120
|
static={this.props.static}
|
|
121
121
|
constraints={[
|
|
122
|
-
// $FlowFixMe[prop-missing]
|
|
123
122
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
|
|
124
123
|
Interactive2.MovablePoint.constraints.bound(),
|
|
125
|
-
// $FlowFixMe[prop-missing]
|
|
126
124
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
|
|
127
125
|
Interactive2.MovablePoint.constraints.snap(),
|
|
128
126
|
(coord: any) => {
|
|
@@ -205,7 +203,6 @@ class FunctionGrapher extends React.Component<FunctionGrapherProps> {
|
|
|
205
203
|
const scale = box[0] / interactiveSizes.defaultBoxSize;
|
|
206
204
|
// @ts-expect-error [FEI-5003] - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
207
205
|
image = (
|
|
208
|
-
// $FlowFixMe[prop-missing]: alt props is missing
|
|
209
206
|
// @ts-expect-error [FEI-5003] - TS2741 - Property 'alt' is missing in type '{ src: any; width: any; height: any; scale: number; }' but required in type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "height" | "width" | "title" | "alt" | "trackInteraction" | "preloader" | "allowFullBleed" | "extraGraphie" | "overrideAriaHidden">'.
|
|
210
207
|
<SvgImage
|
|
211
208
|
src={imageDescription.url}
|
|
@@ -295,10 +292,8 @@ class FunctionGrapher extends React.Component<FunctionGrapherProps> {
|
|
|
295
292
|
});
|
|
296
293
|
}}
|
|
297
294
|
constraints={[
|
|
298
|
-
// $FlowFixMe[prop-missing]
|
|
299
295
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
|
|
300
296
|
Interactive2.MovableLine.constraints.bound(),
|
|
301
|
-
// $FlowFixMe[prop-missing]
|
|
302
297
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
|
|
303
298
|
Interactive2.MovableLine.constraints.snap(),
|
|
304
299
|
(newCoord, oldCoord: any) => {
|
package/src/widgets/group.tsx
CHANGED
|
@@ -171,7 +171,6 @@ class Group extends React.Component<Props> {
|
|
|
171
171
|
onInteractWithWidget={onInteractWithWidget}
|
|
172
172
|
linterContext={this.props.linterContext}
|
|
173
173
|
/>
|
|
174
|
-
{/* $FlowFixMe[prop-missing] */}
|
|
175
174
|
{/* @ts-expect-error [FEI-5003] - TS2339 - Property 'icon' does not exist on type 'Readonly<Props> & Readonly<{ children?: ReactNode; }>'. */}
|
|
176
175
|
{this.props.icon && (
|
|
177
176
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'icon' does not exist on type 'Readonly<Props> & Readonly<{ children?: ReactNode; }>'.
|