@khanacademy/perseus 4.0.0 → 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.
Files changed (81) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/highlighting/ui/highlighting-ui.d.ts +1 -1
  3. package/dist/es/index.js +7968 -8296
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.js +46 -223
  6. package/dist/index.js.map +1 -1
  7. package/dist/multi-items/multi-renderer.d.ts +1 -1
  8. package/dist/multi-items/multi-renderer.js.flow +1 -1
  9. package/dist/multi-items/prop-type-builders.d.ts +1 -1
  10. package/dist/multi-items/shape-types.d.ts +1 -1
  11. package/dist/multi-items/shape-types.js.flow +1 -1
  12. package/dist/multi-items/tree-types.d.ts +1 -1
  13. package/dist/multi-items/tree-types.js.flow +1 -1
  14. package/dist/widgets/__stories__/test-keypad-context-wrapper.d.ts +6 -0
  15. package/dist/widgets/__stories__/test-keypad-context-wrapper.js.flow +14 -0
  16. package/package.json +8 -8
  17. package/src/__testdata__/item-renderer.testdata.ts +1 -1
  18. package/src/__testdata__/renderer.testdata.ts +1 -1
  19. package/src/__tests__/item-renderer.test.tsx +1 -2
  20. package/src/__tests__/renderer-api.test.tsx +1 -5
  21. package/src/__tests__/renderer.test.tsx +1 -1
  22. package/src/components/fixed-to-responsive.tsx +0 -1
  23. package/src/components/graph.tsx +0 -4
  24. package/src/components/highlighting/ui/highlighting-ui.tsx +3 -13
  25. package/src/components/highlighting/ui/selection-tracker.tsx +1 -1
  26. package/src/components/highlighting/word-indexer.tsx +0 -4
  27. package/src/components/math-input.tsx +0 -2
  28. package/src/components/number-input.tsx +0 -2
  29. package/src/components/text-list-editor.tsx +0 -4
  30. package/src/components/zoomable-tex.tsx +0 -2
  31. package/src/components/zoomable.tsx +0 -4
  32. package/src/definition-context.tsx +0 -1
  33. package/src/hints-renderer.tsx +1 -1
  34. package/src/interactive2/__tests__/movable-point.test.ts +0 -1
  35. package/src/item-renderer.tsx +0 -5
  36. package/src/mixins/changeable.ts +1 -1
  37. package/src/multi-items/__stories__/multi-renderer.stories.tsx +0 -4
  38. package/src/multi-items/__tests__/items.test.ts +3 -13
  39. package/src/multi-items/__tests__/multi-renderer.test.tsx +1 -1
  40. package/src/multi-items/__tests__/prop-type-builders.test.ts +1 -1
  41. package/src/multi-items/__tests__/trees.test.ts +2 -10
  42. package/src/multi-items/multi-renderer.tsx +7 -10
  43. package/src/multi-items/prop-type-builders.ts +1 -1
  44. package/src/multi-items/shape-types.ts +1 -1
  45. package/src/multi-items/tree-types.ts +1 -1
  46. package/src/perseus-markdown.tsx +0 -2
  47. package/src/perseus-types.ts +1 -1
  48. package/src/renderer.tsx +2 -5
  49. package/src/server-item-renderer.tsx +0 -3
  50. package/src/util/interactive.ts +1 -5
  51. package/src/util/math.ts +0 -3
  52. package/src/widgets/__stories__/expression.stories.tsx +113 -7
  53. package/src/widgets/__stories__/image.stories.tsx +1 -1
  54. package/src/widgets/__stories__/{on-screen-keypad.stories.tsx → test-keypad-context-wrapper.tsx} +17 -57
  55. package/src/widgets/__testdata__/expression.testdata.ts +16 -12
  56. package/src/widgets/__testdata__/numeric-input.testdata.ts +0 -1
  57. package/src/widgets/__testdata__/transformer.testdata.ts +0 -1
  58. package/src/widgets/__tests__/radio.test.ts +1 -1
  59. package/src/widgets/expression.tsx +1 -1
  60. package/src/widgets/graded-group-set.tsx +0 -4
  61. package/src/widgets/graded-group.tsx +0 -4
  62. package/src/widgets/grapher/util.tsx +1 -5
  63. package/src/widgets/grapher.tsx +0 -5
  64. package/src/widgets/group.tsx +0 -1
  65. package/src/widgets/interaction.tsx +0 -1
  66. package/src/widgets/interactive-graph.tsx +3 -62
  67. package/src/widgets/label-image.tsx +1 -1
  68. package/src/widgets/measurer.tsx +0 -1
  69. package/src/widgets/number-line.tsx +0 -2
  70. package/src/widgets/orderer.tsx +0 -3
  71. package/src/widgets/passage/passage-markdown.tsx +1 -1
  72. package/src/widgets/passage-ref-target.tsx +0 -1
  73. package/src/widgets/passage.tsx +1 -1
  74. package/src/widgets/plotter.tsx +0 -1
  75. package/src/widgets/radio/__stories__/base-radio.stories.tsx +2 -2
  76. package/src/widgets/radio/base-radio.tsx +1 -1
  77. package/src/widgets/transformer.tsx +1 -16
  78. package/src/widgets.ts +1 -1
  79. package/src/zoom.ts +0 -3
  80. package/tsconfig.tsbuildinfo +1 -1
  81. /package/dist/{strings → strings.js} +0 -0
@@ -397,10 +397,8 @@ export default {
397
397
  parse: parse,
398
398
  parseInline: inlineParser,
399
399
  reactFor: SimpleMarkdown.reactFor,
400
- // $FlowFixMe[incompatible-use]
401
400
  ruleOutput: SimpleMarkdown.ruleOutput(rules, "react") as any,
402
401
  basicOutput: SimpleMarkdown.reactFor(
403
- // $FlowFixMe[incompatible-use]
404
402
  SimpleMarkdown.ruleOutput(rules, "react"),
405
403
  ) as any,
406
404
  sanitizeUrl: SimpleMarkdown.sanitizeUrl,
@@ -1423,7 +1423,7 @@ export type PerseusInputNumberWidgetOptions = {
1423
1423
  customKeypad?: boolean;
1424
1424
  };
1425
1425
 
1426
- // TODO(FEI-3983): Create proper flow types for these.
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 flow types,
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 Flow can't see this
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
  }
@@ -2591,7 +2591,7 @@ _.extend(GraphUtils.Graphie.prototype, {
2591
2591
  // and maximum angle values bounding a circle sector, and
2592
2592
  // the third column refers to the cursor name that will be
2593
2593
  // applied if the mouse position falls inside the given sector.
2594
- const cursorAxes = [
2594
+ const cursorAxes: Array<[number, number, string]> = [
2595
2595
  [Math.PI * -1.0, Math.PI * -0.875, "ew-resize"],
2596
2596
  [Math.PI * -0.875, Math.PI * -0.625, "nesw-resize"],
2597
2597
  [Math.PI * -0.625, Math.PI * -0.375, "ns-resize"],
@@ -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 {RendererWithDebugUI} from "../../../../../testing/renderer-with-debug-ui";
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
- type StoryArgs = Record<any, any>;
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
- export default {
16
- title: "Perseus/Widgets/Expression",
17
- } as Story;
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 <RendererWithDebugUI question={expressionItem2.question} />;
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 <RendererWithDebugUI question={expressionItem3.question} />;
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 Flow type errors about missing keys
34
+ // hard-to-understand type errors about missing keys
35
35
  // in object literal.
36
36
  imageOptions != null
37
37
  ? {
@@ -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
- const Demo = () => {
74
- const [keypadElement, setKeypadElement] = React.useState<any>(null);
75
- const [renderer, setRenderer] = React.useState<any>(null);
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
- <Content />
51
+ {props.children}
93
52
  <Footer />
94
53
  </KeypadContext.Provider>
95
54
  );
96
55
  };
97
56
 
98
- export const CustomKeypad: React.FC<StoryArgs> = (args): React.ReactElement => (
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
- ): Item => {
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
- // @ts-expect-error [FEI-5003] - TS2322 - Type '{ question: { content: string; images: {}; widgets: { "expression 1": { type: "expression"; graded: true; options: PerseusExpressionWidgetOptions; version: Version; }; }; }; answerArea: { ...; }; itemDataVersion: { ...; }; hints: never[]; }' is not assignable to type 'Item'.
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: Item = createItemJson(
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: Item = createItemJson(expressionItem3Options, {
92
- major: 1,
93
- minor: 0,
94
- });
92
+ export const expressionItem3: PerseusItem = createItemJson(
93
+ expressionItem3Options,
94
+ {
95
+ major: 1,
96
+ minor: 0,
97
+ },
98
+ );
@@ -87,7 +87,6 @@ export const percentageProblem: PerseusRenderer = {
87
87
  status: "correct",
88
88
  maxError: null,
89
89
  strict: false,
90
- // $FlowFixMe[incompatible-cast] I need this to be a percent
91
90
  value: "33%",
92
91
  simplify: "required",
93
92
  message: "",
@@ -59,7 +59,6 @@ export const question: PerseusRenderer = {
59
59
  graphMode: "interactive",
60
60
  listMode: "static",
61
61
  starting: {
62
- // $FlowFixMe[speculation-ambiguous]
63
62
  shape: {
64
63
  coords: [
65
64
  [0, 0],
@@ -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): Flow doesn't know what type these options are because
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 Flow of this?
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 Flow to require all of our Plot types to be fully typed which
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 {
@@ -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) => {
@@ -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; }>'.
@@ -206,7 +206,6 @@ class Interaction extends React.Component<Props, State> {
206
206
  });
207
207
  compiledVars[name] = function (x: any) {
208
208
  return func(
209
- // $FlowFixMe[extra-arg]
210
209
  _.extend({}, compiledVars, {
211
210
  x: x,
212
211
  }),