Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rough out UserInput type #1639

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
b148d3a
categorizer
handeyeco Sep 17, 2024
17cc0ac
dropdown
handeyeco Sep 17, 2024
ad19c03
remove dead code
handeyeco Sep 17, 2024
523c23c
cs program
handeyeco Sep 17, 2024
574ac1c
expression
handeyeco Sep 17, 2024
1fb16ab
grapher
handeyeco Sep 17, 2024
b53ae37
iframe
handeyeco Sep 17, 2024
8c850e4
Merge branch 'main' into LEMS-2328/type-get-user-input
handeyeco Sep 17, 2024
666e962
input number
handeyeco Sep 17, 2024
e40d631
label image
handeyeco Sep 17, 2024
a8a50bd
matcher
handeyeco Sep 17, 2024
0d1f1c2
matrix
handeyeco Sep 17, 2024
ab140d9
number-line
handeyeco Sep 17, 2024
45a69cb
numeric-input
handeyeco Sep 17, 2024
6133957
orderer
handeyeco Sep 17, 2024
7d34ff3
plotter
handeyeco Sep 17, 2024
7f6b22d
sorter
handeyeco Sep 17, 2024
a88dacd
table
handeyeco Sep 17, 2024
d91b1e7
rough out some of the complex types
handeyeco Sep 17, 2024
ada3dcd
type interactive-graph
handeyeco Sep 19, 2024
9c88e03
merge main
handeyeco Sep 19, 2024
8b98029
categorizer rubric
handeyeco Sep 19, 2024
bef2f4a
cs rubric
handeyeco Sep 19, 2024
b192ffb
dropdown rubric
handeyeco Sep 19, 2024
82416bc
explanation rubric...
handeyeco Sep 19, 2024
c1d1024
expression rubric
handeyeco Sep 19, 2024
33b4d89
Merge branch 'main' into LEMS-2328/type-get-user-input
handeyeco Sep 19, 2024
c6fa948
graded group
handeyeco Sep 19, 2024
242df16
grapher rubric
handeyeco Sep 19, 2024
86a91d9
group weirdness
handeyeco Sep 19, 2024
ac9bb19
input number rubric
handeyeco Sep 19, 2024
7e54302
interaction rubric
handeyeco Sep 23, 2024
14eab2e
interactive-graph rubric
handeyeco Sep 23, 2024
7b7ed76
label image rubric
handeyeco Sep 23, 2024
1affd52
matcher rubric
handeyeco Sep 23, 2024
5c83c47
matrix rubric
handeyeco Sep 23, 2024
0654631
forgot something
handeyeco Sep 23, 2024
9909c83
molecule rubric
handeyeco Sep 23, 2024
3b5dc9a
number line rubric
handeyeco Sep 23, 2024
4b9deb4
numeric-input rubric
handeyeco Sep 23, 2024
445f2fd
orderer rubric
handeyeco Sep 23, 2024
30db17e
passage rubrics
handeyeco Sep 23, 2024
f759c05
phet rubric
handeyeco Sep 23, 2024
3d582ad
radio rubric
handeyeco Sep 23, 2024
4800998
sorter rubric
handeyeco Sep 23, 2024
320dccf
table rubric
handeyeco Sep 23, 2024
0072a57
some cleanup
handeyeco Sep 24, 2024
55c40f2
merge main
handeyeco Sep 24, 2024
228d785
merge main
handeyeco Sep 24, 2024
ad58a01
cleanup
handeyeco Sep 24, 2024
dcb4699
changeset
handeyeco Sep 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/perseus/src/__tests__/renderer-api.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import inputNumber1Item from "./test-items/input-number-1-item";
import inputNumber2Item from "./test-items/input-number-2-item";
import tableItem from "./test-items/table-item";

import type {PerseusInputNumberUserInput} from "../validation.types";
import type {UserEvent} from "@testing-library/user-event";

const itemWidget = inputNumber1Item;
Expand Down Expand Up @@ -75,8 +76,9 @@ describe("Perseus API", function () {
const {renderer} = renderQuestion(inputNumber1Item.question);
act(() =>
renderer.setInputValue(["input-number 1"], "3", function () {
const guess = renderer.getUserInput()[0];
expect(guess.currentValue).toBe("3");
const guess =
renderer.getUserInput()[0] as PerseusInputNumberUserInput;
expect(guess?.currentValue).toBe("3");
done();
}),
);
Expand Down
1 change: 0 additions & 1 deletion packages/perseus/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ export type {
PerseusPythonProgramWidgetOptions,
PerseusRadioWidgetOptions,
PerseusExampleWidgetOptions,
PerseusExampleGraphieWidgetOptions,
PerseusSimpleMarkdownTesterWidgetOptions,
PerseusRenderer,
PerseusWidget,
Expand Down
21 changes: 0 additions & 21 deletions packages/perseus/src/mixins/__tests__/widget-prop-denylist.test.ts

This file was deleted.

10 changes: 0 additions & 10 deletions packages/perseus/src/mixins/widget-prop-denylist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,4 @@ const denylist = [
"keypadElement",
];

export const removeDenylistProps = (props: any): any => {
const newProps = {...props} as const;
for (const prop of denylist) {
if (prop in newProps) {
delete newProps[prop];
}
}
return newProps;
};

export default denylist;
19 changes: 0 additions & 19 deletions packages/perseus/src/perseus-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,24 +380,6 @@ export type PerseusExampleWidgetOptions = {
value: string;
};

export type PerseusExampleGraphieGraph = {
box: Size;
range: [Coord, Coord];
labels: ReadonlyArray<string>;
markings: "graph" | "grid" | "none";
gridStep: [number, number];
step: [number, number];
showProtractor?: boolean;
showRuler?: boolean;
valid?: boolean;
backgroundImage?: PerseusImageBackground | null;
};

export type PerseusExampleGraphieWidgetOptions = {
graph: PerseusExampleGraphieGraph;
coord: [Coord, Coord] | null;
};

export type PerseusExplanationWidgetOptions = {
// Translatable Text; The clickable text to expand an explanation. e.g. "What is an apple?"
showPrompt: string;
Expand Down Expand Up @@ -1619,7 +1601,6 @@ export type PerseusWidgetOptions =
| PerseusCSProgramWidgetOptions
| PerseusDefinitionWidgetOptions
| PerseusDropdownWidgetOptions
| PerseusExampleGraphieWidgetOptions
| PerseusExampleWidgetOptions
| PerseusExplanationWidgetOptions
| PerseusExpressionWidgetOptions
Expand Down
31 changes: 13 additions & 18 deletions packages/perseus/src/renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import type {
PerseusScore,
WidgetProps,
} from "./types";
import type {UserInput} from "./validation.types";
import type {KeypadAPI} from "@khanacademy/math-input";
import type {LinterContextProps} from "@khanacademy/perseus-linter";

Expand Down Expand Up @@ -103,11 +104,6 @@ type SetWidgetPropsFn = (
silent?: boolean,
) => void;

// The return type for getUserInput. Widgets have full control of what is
// returned so it's not easily typed (some widgets return a scalar (string),
// some return a custom-built object
type WidgetUserInput = any;

type SerializedState = {
[id: string]: any;
};
Expand Down Expand Up @@ -149,7 +145,7 @@ export type Widget = {
// TODO(jeremy): I think this is actually a callback
focus?: () => unknown,
) => void;
getUserInput?: () => WidgetUserInput | null | undefined;
getUserInput?: () => UserInput | null | undefined;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a hunch that my request will lead down a rabbit hole of fighting TypeScript, but would it be possible to make this Widget type generic so that the UserInput type would be a generic type? That way, the numeric-input could only legally return PerseusNumericInputUserInput.

If 5 min of trying doesn't work, we can push that out, but it's been a thought I've often had as I worked with this Widget type. (the same goes for return type of getSerializedState)

simpleValidate?: (
options?: any,
onOutputError?: (
Expand Down Expand Up @@ -1760,17 +1756,16 @@ class Renderer extends React.Component<Props, State> {
/**
* Returns an array of the widget `.getUserInput()` results
*/
getUserInput: () => ReadonlyArray<WidgetUserInput | null | undefined> =
() => {
return this.widgetIds.map((id: string) => {
const widget = this.getWidgetInstance(id);
if (widget && widget.getUserInput) {
// TODO(Jeremy): Add the widget ID in here so we can more
// easily correlate it to the widget state.
return widget.getUserInput();
}
});
};
getUserInput: () => ReadonlyArray<UserInput | null | undefined> = () => {
return this.widgetIds.map((id: string) => {
const widget = this.getWidgetInstance(id);
if (widget && widget.getUserInput) {
// TODO(Jeremy): Add the widget ID in here so we can more
// easily correlate it to the widget state.
return widget.getUserInput();
}
});
};

/**
* Returns an array of all widget IDs in the order they occur in
Expand All @@ -1790,7 +1785,7 @@ class Renderer extends React.Component<Props, State> {
* so we should aim to remove one of these functions.
*/
getUserInputForWidgets: () => {
[widgetId: string]: WidgetUserInput | null | undefined;
[widgetId: string]: UserInput | null | undefined;
} = () => {
return mapObjectFromArray(this.widgetIds, (id) => {
const widget = this.getWidgetInstance(id);
Expand Down
3 changes: 3 additions & 0 deletions packages/perseus/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,9 @@ export type FilterCriterion =
) => boolean);

// NOTE: Rubric should always be the corresponding widget options type for the component.
// TODO: in fact, is it really the rubric? WidgetOptions is what we use to configure the widget
// (which is what this seems to be for)
// and Rubric is what we use to score the widgets (which not all widgets need validation)
handeyeco marked this conversation as resolved.
Show resolved Hide resolved
export type WidgetProps<
RenderProps,
Rubric,
Expand Down
Loading
Loading