@khanacademy/perseus 19.1.1 → 19.1.3

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 (69) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/all-widgets.d.ts +1 -1
  3. package/dist/basic-widgets.d.ts +1 -1
  4. package/dist/components/graph.d.ts +7 -6
  5. package/dist/components/graphie.d.ts +8 -1
  6. package/dist/es/index.js +49 -51
  7. package/dist/es/index.js.map +1 -1
  8. package/dist/extra-widgets.d.ts +1 -1
  9. package/dist/index.js +48 -49
  10. package/dist/index.js.map +1 -1
  11. package/dist/perseus-types.d.ts +3 -3
  12. package/dist/types.d.ts +1 -1
  13. package/dist/util/graphie.d.ts +13 -6
  14. package/dist/widgets/categorizer.d.ts +1 -1
  15. package/dist/widgets/cs-program.d.ts +1 -1
  16. package/dist/widgets/definition.d.ts +1 -1
  17. package/dist/widgets/deprecated-standin/index.d.ts +1 -1
  18. package/dist/widgets/dropdown.d.ts +1 -1
  19. package/dist/widgets/explanation.d.ts +1 -1
  20. package/dist/widgets/expression.d.ts +14 -14
  21. package/dist/widgets/graded-group-set.d.ts +1 -1
  22. package/dist/widgets/graded-group.d.ts +1 -1
  23. package/dist/widgets/grapher.d.ts +1 -1
  24. package/dist/widgets/group.d.ts +1 -1
  25. package/dist/widgets/iframe.d.ts +1 -1
  26. package/dist/widgets/image.d.ts +1 -1
  27. package/dist/widgets/input-number.d.ts +1 -1
  28. package/dist/widgets/interaction.d.ts +1 -1
  29. package/dist/widgets/interactive-graph.d.ts +1 -1
  30. package/dist/widgets/label-image.d.ts +14 -14
  31. package/dist/widgets/lights-puzzle.d.ts +1 -1
  32. package/dist/widgets/matcher.d.ts +1 -1
  33. package/dist/widgets/matrix.d.ts +1 -1
  34. package/dist/widgets/measurer.d.ts +5 -5
  35. package/dist/widgets/molecule.d.ts +1 -1
  36. package/dist/widgets/number-line.d.ts +1 -1
  37. package/dist/widgets/numeric-input.d.ts +1 -1
  38. package/dist/widgets/orderer.d.ts +1 -1
  39. package/dist/widgets/passage-ref-target.d.ts +1 -1
  40. package/dist/widgets/passage-ref.d.ts +1 -1
  41. package/dist/widgets/passage.d.ts +1 -1
  42. package/dist/widgets/plotter.d.ts +1 -1
  43. package/dist/widgets/radio.d.ts +1 -1
  44. package/dist/widgets/reaction-diagram.d.ts +1 -1
  45. package/dist/widgets/sequence.d.ts +1 -1
  46. package/dist/widgets/simulator.d.ts +1 -1
  47. package/dist/widgets/sorter.d.ts +1 -1
  48. package/dist/widgets/table.d.ts +1 -1
  49. package/dist/widgets/unit.d.ts +1 -1
  50. package/dist/widgets/video.d.ts +1 -1
  51. package/package.json +3 -3
  52. package/src/__tests__/init.test.ts +10 -0
  53. package/src/__tests__/widgets.test.ts +2 -3
  54. package/src/components/graph.tsx +25 -20
  55. package/src/components/graphie.tsx +19 -14
  56. package/src/init.ts +1 -4
  57. package/src/perseus-types.ts +3 -3
  58. package/src/types.ts +4 -2
  59. package/src/util/graphie.test.ts +1 -15
  60. package/src/util/graphie.ts +14 -24
  61. package/src/util/interactive.ts +2 -2
  62. package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +1 -1
  63. package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +1 -1
  64. package/src/widgets/label-image/marker.tsx +4 -0
  65. package/src/widgets/label-image.tsx +2 -7
  66. package/src/widgets/measurer.tsx +8 -2
  67. package/src/widgets/plotter.tsx +2 -0
  68. package/src/widgets.ts +9 -4
  69. package/tsconfig-build.tsbuildinfo +1 -1
@@ -70,6 +70,7 @@ declare const _default: Readonly<{
70
70
  name: string;
71
71
  displayName: string;
72
72
  getWidget?: (() => typeof Simulator) | undefined;
73
+ widget: typeof Simulator;
73
74
  accessible?: boolean | ((props: any) => boolean) | undefined;
74
75
  hidden?: boolean | undefined;
75
76
  version?: import("../types").Version | undefined;
@@ -84,6 +85,5 @@ declare const _default: Readonly<{
84
85
  propUpgrades?: {
85
86
  [key: string]: (arg1: any) => any;
86
87
  } | undefined;
87
- widget: typeof Simulator;
88
88
  }>;
89
89
  export default _default;
@@ -63,6 +63,7 @@ declare const _default: Readonly<{
63
63
  name: string;
64
64
  displayName: string;
65
65
  getWidget?: (() => typeof Sorter) | undefined;
66
+ widget: typeof Sorter;
66
67
  accessible?: boolean | ((props: any) => boolean) | undefined;
67
68
  hidden?: boolean | undefined;
68
69
  version?: import("../types").Version | undefined;
@@ -77,6 +78,5 @@ declare const _default: Readonly<{
77
78
  propUpgrades?: {
78
79
  [key: string]: (arg1: any) => any;
79
80
  } | undefined;
80
- widget: typeof Sorter;
81
81
  }>;
82
82
  export default _default;
@@ -44,6 +44,7 @@ declare const _default: Readonly<{
44
44
  name: string;
45
45
  displayName: string;
46
46
  getWidget?: (() => typeof Table) | undefined;
47
+ widget: typeof Table;
47
48
  accessible?: boolean | ((props: any) => boolean) | undefined;
48
49
  hidden?: boolean | undefined;
49
50
  version?: import("../types").Version | undefined;
@@ -58,6 +59,5 @@ declare const _default: Readonly<{
58
59
  propUpgrades?: {
59
60
  [key: string]: (arg1: any) => any;
60
61
  } | undefined;
61
- widget: typeof Table;
62
62
  }>;
63
63
  export default _default;
@@ -58,6 +58,7 @@ declare const _default: Readonly<{
58
58
  name: string;
59
59
  displayName: string;
60
60
  getWidget?: (() => typeof OldUnitInput) | undefined;
61
+ widget: typeof OldUnitInput;
61
62
  accessible?: boolean | ((props: any) => boolean) | undefined;
62
63
  hidden?: boolean | undefined;
63
64
  version?: import("../types").Version | undefined;
@@ -72,6 +73,5 @@ declare const _default: Readonly<{
72
73
  propUpgrades?: {
73
74
  [key: string]: (arg1: any) => any;
74
75
  } | undefined;
75
- widget: typeof OldUnitInput;
76
76
  }>;
77
77
  export default _default;
@@ -29,6 +29,7 @@ declare const _default: Readonly<{
29
29
  name: string;
30
30
  displayName: string;
31
31
  getWidget?: (() => typeof Video) | undefined;
32
+ widget: typeof Video;
32
33
  accessible?: boolean | ((props: any) => boolean) | undefined;
33
34
  hidden?: boolean | undefined;
34
35
  version?: import("../types").Version | undefined;
@@ -43,6 +44,5 @@ declare const _default: Readonly<{
43
44
  propUpgrades?: {
44
45
  [key: string]: (arg1: any) => any;
45
46
  } | undefined;
46
- widget: typeof Video;
47
47
  }>;
48
48
  export default _default;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Core Perseus API (includes renderers and widgets)",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "19.1.1",
6
+ "version": "19.1.3",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -23,8 +23,8 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@khanacademy/kas": "^0.3.7",
26
- "@khanacademy/kmath": "^0.1.9",
27
- "@khanacademy/math-input": "^17.0.1",
26
+ "@khanacademy/kmath": "^0.1.10",
27
+ "@khanacademy/math-input": "^17.0.2",
28
28
  "@khanacademy/perseus-core": "1.4.1",
29
29
  "@khanacademy/perseus-linter": "^0.3.10",
30
30
  "@khanacademy/pure-markdown": "^0.2.13",
@@ -0,0 +1,10 @@
1
+ import init from "../init";
2
+ import {getWidget} from "../widgets";
3
+
4
+ describe("init", () => {
5
+ it("should correctly replace the transformer widget", async () => {
6
+ await init({skipMathJax: true});
7
+
8
+ expect(getWidget("transformer")).not.toBeNull();
9
+ });
10
+ });
@@ -85,8 +85,7 @@ describe("replaceWidget", () => {
85
85
  expect(Widgets.getWidget("transformer")?.name).toBe("Radio");
86
86
  });
87
87
 
88
- it("Does nothing when the replacement isn't available", () => {
89
- Widgets.replaceWidget("radio", "dog-cat");
90
- expect(Widgets.getWidget("radio")?.name).toBe("Radio");
88
+ it("Throws when the replacement isn't available", () => {
89
+ expect(() => Widgets.replaceWidget("radio", "dog-cat")).toThrow();
91
90
  });
92
91
  });
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
2
2
  /* eslint-disable react/no-unsafe */
3
+ import {vector as kvector} from "@khanacademy/kmath";
3
4
  import $ from "jquery";
4
5
  import * as React from "react";
5
6
  import ReactDOM from "react-dom";
@@ -14,6 +15,7 @@ import SvgImage from "./svg-image";
14
15
 
15
16
  import type {Coord} from "../interactive2/types";
16
17
  import type {PerseusImageBackground} from "../perseus-types";
18
+ import type {GridDimensions} from "../util";
17
19
 
18
20
  const defaultBackgroundImage = {
19
21
  url: null,
@@ -43,12 +45,12 @@ function numSteps(range: any, step: any) {
43
45
  }
44
46
 
45
47
  type Props = {
46
- box: Readonly<[number, number]>;
48
+ box: [number, number];
47
49
  labels: ReadonlyArray<string>;
48
- range: Readonly<[Coord, Coord]>;
49
- step: Readonly<[number, number]>;
50
- gridStep: Readonly<[number, number]>;
51
- snapStep: Readonly<[number, number]>;
50
+ range: [Coord, Coord];
51
+ step: [number, number];
52
+ gridStep: [number, number];
53
+ snapStep: [number, number];
52
54
  markings: string;
53
55
  backgroundImage: PerseusImageBackground;
54
56
  showProtractor: boolean;
@@ -201,23 +203,26 @@ class Graph extends React.Component<Props> {
201
203
  Util.unescapeMathMode(label),
202
204
  );
203
205
  const range = this.props.range;
206
+ // @ts-expect-error - TS2345: Argument of type 'Element | Text | null' is not assignable to parameter of type 'HTMLElement'.
204
207
  const graphie = (this._graphie = GraphUtils.createGraphie(graphieDiv));
205
208
 
206
- const gridConfig = this._getGridConfig();
209
+ const gridConfig: [GridDimensions, GridDimensions] =
210
+ this._getGridConfig();
211
+ // @ts-expect-error - TS2339: Property 'snap' does not exist on type 'Graphie'.
207
212
  graphie.snap = this.props.snapStep;
208
213
 
209
214
  if (this.props.markings === "graph") {
210
215
  graphie.graphInit({
211
216
  range: range,
212
- scale: _.pluck(gridConfig, "scale"),
217
+ scale: kvector.map(gridConfig, (g) => g.scale),
213
218
  axisArrows: "<->",
214
219
  labelFormat: function (s) {
215
220
  return "\\small{" + s + "}";
216
221
  },
217
222
  gridStep: this.props.gridStep,
218
- tickStep: _.pluck(gridConfig, "tickStep"),
223
+ tickStep: kvector.map(gridConfig, (g) => g.tickStep),
219
224
  labelStep: 1,
220
- unityLabels: _.pluck(gridConfig, "unityLabel"),
225
+ unityLabels: kvector.map(gridConfig, (g) => g.unityLabel),
221
226
  isMobile: this.props.isMobile,
222
227
  });
223
228
  graphie.label(
@@ -233,7 +238,7 @@ class Graph extends React.Component<Props> {
233
238
  } else if (this.props.markings === "grid") {
234
239
  graphie.graphInit({
235
240
  range: range,
236
- scale: _.pluck(gridConfig, "scale"),
241
+ scale: kvector.map(gridConfig, (g) => g.scale),
237
242
  gridStep: this.props.gridStep,
238
243
  axes: false,
239
244
  ticks: false,
@@ -243,7 +248,7 @@ class Graph extends React.Component<Props> {
243
248
  } else if (this.props.markings === "none") {
244
249
  graphie.init({
245
250
  range: range,
246
- scale: _.pluck(gridConfig, "scale"),
251
+ scale: kvector.map(gridConfig, (g) => g.scale),
247
252
  isMobile: this.props.isMobile,
248
253
  });
249
254
  }
@@ -303,6 +308,7 @@ class Graph extends React.Component<Props> {
303
308
  : null;
304
309
  /* eslint-enable indent */
305
310
 
311
+ // @ts-expect-error - Property 'addMouseLayer' does not exist on type 'Graphie'.
306
312
  graphie.addMouseLayer({
307
313
  onClick: this.props.onClick,
308
314
  onMouseDown: onMouseDown,
@@ -329,16 +335,15 @@ class Graph extends React.Component<Props> {
329
335
  }
330
336
  };
331
337
 
332
- _getGridConfig: () => any = () => {
333
- const self = this;
334
- return _.map(self.props.step, function (step, i) {
335
- return Util.gridDimensionConfig(
338
+ _getGridConfig: () => [GridDimensions, GridDimensions] = () => {
339
+ return kvector.map(this.props.step, (step, i) =>
340
+ Util.gridDimensionConfig(
336
341
  step,
337
- self.props.range[i],
338
- self.props.box[i],
339
- self.props.gridStep[i],
340
- );
341
- });
342
+ this.props.range[i],
343
+ this.props.box[i],
344
+ this.props.gridStep[i],
345
+ ),
346
+ );
342
347
  };
343
348
 
344
349
  _updateProtractor: () => void = () => {
@@ -7,6 +7,7 @@ import InteractiveUtil from "../interactive2/interactive-util";
7
7
  import {Errors, Log} from "../logging/log";
8
8
  import Util from "../util";
9
9
  import GraphUtils from "../util/graph-utils";
10
+ import {Graphie as GraphieDrawingContext} from "../util/graphie";
10
11
 
11
12
  import GraphieClasses from "./graphie-classes";
12
13
  import Movables from "./graphie-movables";
@@ -59,8 +60,17 @@ type DefaultProps = {
59
60
  addMouseLayer: Props["addMouseLayer"];
60
61
  };
61
62
 
63
+ interface Movable {
64
+ remove(): void;
65
+ }
66
+
62
67
  class Graphie extends React.Component<Props> {
63
68
  graphieDivRef = React.createRef<HTMLDivElement>();
69
+ _graphie: GraphieDrawingContext = new GraphieDrawingContext(
70
+ document.createElement("div"),
71
+ );
72
+ _movables: Record<string, Movable> = {};
73
+ movables: Record<string, Movable> = {};
64
74
 
65
75
  static defaultProps: DefaultProps = {
66
76
  range: [
@@ -120,7 +130,6 @@ class Graphie extends React.Component<Props> {
120
130
  * Use it for good and not evil.
121
131
  */
122
132
  getGraphie: () => any = () => {
123
- // @ts-expect-error - TS2339 - Property '_graphie' does not exist on type 'Graphie'.
124
133
  return this._graphie;
125
134
  };
126
135
 
@@ -151,10 +160,11 @@ class Graphie extends React.Component<Props> {
151
160
  ];
152
161
  };
153
162
 
154
- _scale: () => ReadonlyArray<number> = () => {
163
+ // @ts-expect-error - TS2322: Type '() => number[]' is not assignable to type '() => Coord'.
164
+ _scale: () => Coord = () => {
155
165
  const box = this._box();
156
166
  const range = this._range();
157
- return _.map(box, (pixelDim, i) => {
167
+ return box.map((pixelDim, i) => {
158
168
  const unitDim = range[i][1] - range[i][0];
159
169
  return pixelDim / unitDim;
160
170
  });
@@ -164,9 +174,10 @@ class Graphie extends React.Component<Props> {
164
174
  this._removeMovables();
165
175
 
166
176
  const graphieDiv = ReactDOM.findDOMNode(this.graphieDivRef.current);
167
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'empty' does not exist on type 'JQueryStatic'.
168
- $(graphieDiv).empty();
169
- // @ts-expect-error - TS2339 - Property '_graphie' does not exist on type 'Graphie'.
177
+ if (graphieDiv == null || graphieDiv instanceof Text) {
178
+ throw new Error("No graphie container div found");
179
+ }
180
+ graphieDiv.innerHTML = "";
170
181
  const graphie = (this._graphie = createGraphie(graphieDiv));
171
182
 
172
183
  // This has to be called before addMouseLayer. You can re-init
@@ -178,6 +189,7 @@ class Graphie extends React.Component<Props> {
178
189
  });
179
190
  // Only add the mouselayer if we actually want one.
180
191
  if (this.props.addMouseLayer) {
192
+ // @ts-expect-error - TS2339: Property 'addMouseLayer' does not exist on type 'Graphie'.
181
193
  graphie.addMouseLayer({
182
194
  onClick: this.props.onClick,
183
195
  onMouseDown: this.props.onMouseDown,
@@ -187,13 +199,13 @@ class Graphie extends React.Component<Props> {
187
199
  });
188
200
  }
189
201
 
202
+ // @ts-expect-error - TS2339: Property 'snap' does not exist on type 'Graphie'.
190
203
  graphie.snap = this.props.options.snapStep || [1, 1];
191
204
 
192
205
  if (this.props.responsive) {
193
206
  // Overwrite fixed styles set in init()
194
207
  // TODO(alex): Either make this component always responsive by
195
208
  // itself, or always wrap it in other components so that it is.
196
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2554 - Expected 2 arguments, but got 1.
197
209
  $(graphieDiv).css({width: "100%", height: "100%"});
198
210
  graphie.raphael.setSize("100%", "100%");
199
211
  }
@@ -212,9 +224,7 @@ class Graphie extends React.Component<Props> {
212
224
 
213
225
  _removeMovables: () => void = () => {
214
226
  // _.invoke works even when this._movables is undefined
215
- // @ts-expect-error - TS2339 - Property '_movables' does not exist on type 'Graphie'.
216
227
  _.invoke(this._movables, "remove");
217
- // @ts-expect-error - TS2339 - Property '_movables' does not exist on type 'Graphie'.
218
228
  this._movables = {};
219
229
  };
220
230
 
@@ -333,7 +343,6 @@ class Graphie extends React.Component<Props> {
333
343
  }
334
344
 
335
345
  if (ref) {
336
- // @ts-expect-error - TS2339 - Property 'movables' does not exist on type 'Graphie'.
337
346
  this.movables[ref] = newMovables[key];
338
347
  }
339
348
 
@@ -343,15 +352,11 @@ class Graphie extends React.Component<Props> {
343
352
 
344
353
  // Sort of like react diffing, but for movables
345
354
  _updateMovables: () => void = () => {
346
- // @ts-expect-error - TS2339 - Property '_graphie' does not exist on type 'Graphie'.
347
355
  const graphie = this._graphie;
348
356
 
349
- // @ts-expect-error - TS2339 - Property '_movables' does not exist on type 'Graphie'.
350
357
  const oldMovables = this._movables;
351
358
  const newMovables: Record<string, any> = {};
352
- // @ts-expect-error - TS2339 - Property '_movables' does not exist on type 'Graphie'.
353
359
  this._movables = newMovables;
354
- // @ts-expect-error - TS2339 - Property 'movables' does not exist on type 'Graphie'.
355
360
  this.movables = {};
356
361
 
357
362
  // @ts-expect-error - TS2345 - Argument of type 'ReactNode' is not assignable to parameter of type 'readonly any[]'.
package/src/init.ts CHANGED
@@ -21,10 +21,7 @@ const init = function (options: PerseusOptions): Promise<undefined> {
21
21
  Widgets.registerWidgets(basicWidgets);
22
22
  Widgets.registerWidgets(extraWidgets);
23
23
 
24
- // This section replaces widgets
25
- // When it's time to replace the transformer widget
26
- // uncomment this line
27
- // Widgets.replaceWidget("transformer", "deprecated-standin");
24
+ Widgets.replaceWidget("transformer", "deprecated-standin");
28
25
 
29
26
  // Pass skipMathJax: true if MathJax is already loaded and configured.
30
27
  const skipMathJax = options.skipMathJax;
@@ -1036,11 +1036,11 @@ export type PerseusInteractionGraph = {
1036
1036
  // The Axis ranges. e.g. [[-10, 10], [-10, 10]]
1037
1037
  range: [Range, Range];
1038
1038
  // The steps in the grid. default [1, 1]
1039
- gridStep: Readonly<[number, number]>;
1039
+ gridStep: [number, number];
1040
1040
  // What to show on the graph. "graph", "grid", or "none"
1041
1041
  markings: string;
1042
1042
  // The snap steps. default [0.5, 0.5]
1043
- snapStep?: Readonly<[number, number]>;
1043
+ snapStep?: [number, number];
1044
1044
  // Whether the grid is valid or not. Do the numbers all make sense?
1045
1045
  // NOTE(jeremy) The editor for this widget sometimes stores the graph
1046
1046
  // editor validation error message into this field. It seems innocuous
@@ -1058,7 +1058,7 @@ export type PerseusInteractionGraph = {
1058
1058
  // How many ticks to show on the ruler. e.g. 1, 2, 4, 8, 10, 16
1059
1059
  rulerTicks?: number;
1060
1060
  // This controls the number (and position) of the tick marks for the X and Y axis. e.g. [1, 1]
1061
- tickStep: Readonly<[number, number]>;
1061
+ tickStep: [number, number];
1062
1062
  };
1063
1063
 
1064
1064
  export type PerseusInteractionElement =
package/src/types.ts CHANGED
@@ -411,9 +411,13 @@ export type WidgetExports<
411
411
  > = Readonly<{
412
412
  name: string;
413
413
  displayName: string;
414
+
415
+ // Widgets should provide _one_ of these two properties only!
414
416
  // TODO: figure out how to ensure that the component returned supports
415
417
  // the `validate` method.
416
418
  getWidget?: () => T;
419
+ widget: T;
420
+
417
421
  accessible?: boolean | ((props: any) => boolean);
418
422
  /** Supresses widget from showing up in the dropdown in the content editor */
419
423
  hidden?: boolean;
@@ -449,8 +453,6 @@ export type WidgetExports<
449
453
  propUpgrades?: {
450
454
  [key: string]: (arg1: any) => any;
451
455
  }; // OldProps => NewProps,
452
-
453
- widget: T;
454
456
  }>;
455
457
 
456
458
  export type PerseusWidgetMap = {
@@ -40,7 +40,7 @@ function createFakeRaphaelSet() {
40
40
  }
41
41
 
42
42
  function createAndInitGraphie(): Graphie {
43
- const graphie = GraphUtils.createGraphie();
43
+ const graphie = GraphUtils.createGraphie(document.createElement("div"));
44
44
  graphie.raphael = createMockRaphael();
45
45
 
46
46
  // The graph is 50px by 50px
@@ -1244,20 +1244,6 @@ describe("Graphie drawing tools", () => {
1244
1244
  });
1245
1245
  });
1246
1246
 
1247
- describe("GraphUtils", () => {
1248
- describe("snapCoord", () => {
1249
- it("snaps to the nearest integer coordinates", () => {
1250
- expect(GraphUtils.snapCoord([0.1, 0.9], [1, 1])).toEqual([0, 1]);
1251
- });
1252
-
1253
- it("snaps to the nearest half", () => {
1254
- expect(GraphUtils.snapCoord([0.4, 2.2], [0.5, 0.5])).toEqual([
1255
- 0.5, 2,
1256
- ]);
1257
- });
1258
- });
1259
- });
1260
-
1261
1247
  describe("normalizeRange", () => {
1262
1248
  it("does nothing to a range specified as [[xMin, xMax], [yMin, yMax]]", () => {
1263
1249
  expect(
@@ -91,7 +91,7 @@ interface LabelMethod {
91
91
  }
92
92
 
93
93
  export class Graphie {
94
- el: HTMLElement;
94
+ el: Element;
95
95
  #bounds?: GraphBounds;
96
96
  #drawingTransform?: DrawingTransform;
97
97
  raphael?: any;
@@ -111,7 +111,7 @@ export class Graphie {
111
111
  xpixels?: number;
112
112
  ypixels?: number;
113
113
 
114
- constructor(el: HTMLElement) {
114
+ constructor(el: Element) {
115
115
  this.el = el;
116
116
  $(el).css("position", "relative");
117
117
  this.raphael = Raphael(el);
@@ -180,7 +180,7 @@ export class Graphie {
180
180
  grid?: boolean;
181
181
  gridRange?: [Interval, Interval] | Coord;
182
182
  scale: Coord | number;
183
- axes?: true;
183
+ axes?: boolean;
184
184
  axisArrows?: "<->" | "->" | true | "";
185
185
  axisOpacity?: number;
186
186
  axisCenter?: Coord;
@@ -269,8 +269,8 @@ export class Graphie {
269
269
  unityLabels = [unityLabels, unityLabels];
270
270
  }
271
271
 
272
- const minusIgnorer = function (lf: any) {
273
- return function (a) {
272
+ const minusIgnorer = function (lf: (a: number) => string) {
273
+ return function (a: number) {
274
274
  return (lf(a) + "").replace(/-(\d)/g, "\\llap{-}$1");
275
275
  };
276
276
  };
@@ -580,7 +580,7 @@ export class Graphie {
580
580
  return this.#bounds;
581
581
  }
582
582
 
583
- style(attrs: any, fn: any) {
583
+ style<T>(attrs: any, fn?: (this: Graphie) => T): T | undefined {
584
584
  const processed = this.processAttributes(attrs);
585
585
 
586
586
  if (typeof fn === "function") {
@@ -983,7 +983,7 @@ export class Graphie {
983
983
  };
984
984
 
985
985
  // @ts-expect-error - TS2339 - Property 'processText' does not exist on type 'JQuery<HTMLElement>'.
986
- $span.processText = function (text: any) {
986
+ $span.processText = function (text: string) {
987
987
  $span.html(text);
988
988
  const width = span.scrollWidth;
989
989
  const height = span.scrollHeight;
@@ -1098,7 +1098,7 @@ export class Graphie {
1098
1098
  .join("");
1099
1099
  };
1100
1100
 
1101
- svgParabolaPath = (a: any, b: any, c: any) => {
1101
+ svgParabolaPath = (a: number, b: number, c: number) => {
1102
1102
  const computeParabola = function (x) {
1103
1103
  return (a * x + b) * x + c;
1104
1104
  };
@@ -1346,7 +1346,7 @@ export class Graphie {
1346
1346
  return this.drawingTransform().unscaleVector(point);
1347
1347
  };
1348
1348
 
1349
- private processAttributes(attrs: any) {
1349
+ private processAttributes(attrs: Record<string, any> | undefined) {
1350
1350
  const transformers = {
1351
1351
  scale: (scale) => {
1352
1352
  this.drawingTransform().setScale(scale);
@@ -1515,14 +1515,14 @@ const setLabelMargins = function (span: HTMLElement, size: Coord): void {
1515
1515
  }
1516
1516
  };
1517
1517
 
1518
- const GraphUtils: any = {
1518
+ const GraphUtils = {
1519
1519
  Graphie,
1520
1520
 
1521
- createGraphie: function (el: any): Graphie {
1521
+ createGraphie: function (el: Element): Graphie {
1522
1522
  return new Graphie(el);
1523
1523
  },
1524
1524
 
1525
- unscaledSvgPath: function (points) {
1525
+ unscaledSvgPath: function (points: (Coord | true)[]): string {
1526
1526
  // If this is an empty closed path, return "" instead of "z", which
1527
1527
  // would give an error
1528
1528
  if (points[0] === true) {
@@ -1538,22 +1538,12 @@ const GraphUtils: any = {
1538
1538
  .join("");
1539
1539
  },
1540
1540
 
1541
- getDistance: function (point1, point2) {
1541
+ getDistance: function (point1: Coord, point2: Coord): number {
1542
1542
  return kpoint.distanceToPoint(point1, point2);
1543
1543
  },
1544
1544
 
1545
- /**
1546
- * Round the given coordinates to a given snap value
1547
- * (e.g., nearest 0.2 increment)
1548
- */
1549
- snapCoord: function (coord, snap) {
1550
- return coord.map(function (val, i) {
1551
- return KhanMath.roundToNearest(snap[i], val);
1552
- });
1553
- },
1554
-
1555
1545
  // Find the angle in degrees between two or three points
1556
- findAngle: function (point1, point2, vertex) {
1546
+ findAngle: function (point1: Coord, point2: Coord, vertex?: Coord) {
1557
1547
  if (vertex === undefined) {
1558
1548
  const x = point1[0] - point2[0];
1559
1549
  const y = point1[1] - point2[1];
@@ -3982,8 +3982,8 @@ _.extend(MovableAngle.prototype, {
3982
3982
 
3983
3983
  // Drag ray control points to move each ray individually
3984
3984
  _.each([0, 2], function (i) {
3985
- points[i].onMove = function (x: any, y) {
3986
- const newPoint = [x, y];
3985
+ points[i].onMove = function (x: number, y: number) {
3986
+ const newPoint: Coord = [x, y];
3987
3987
  const vertex = points[1].coord;
3988
3988
 
3989
3989
  // @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'never[]'.
@@ -182,7 +182,7 @@ exports[`rendering supports mobile rendering: mobile render 1`] = `
182
182
  class="mq-textarea"
183
183
  >
184
184
  <span
185
- aria-label="Math Input:"
185
+ aria-label="Math input box:"
186
186
  />
187
187
  </span>
188
188
  <span
@@ -44,7 +44,7 @@ exports[`Numeric input widget styles differently on mobile: mobile render 1`] =
44
44
  class="mq-textarea"
45
45
  >
46
46
  <span
47
- aria-label="Math Input:"
47
+ aria-label="Math input box:"
48
48
  />
49
49
  </span>
50
50
  <span
@@ -7,6 +7,7 @@
7
7
 
8
8
  import Color from "@khanacademy/wonder-blocks-color";
9
9
  import {View, type StyleType} from "@khanacademy/wonder-blocks-core";
10
+ import * as i18n from "@khanacademy/wonder-blocks-i18n";
10
11
  import {StyleSheet} from "aphrodite";
11
12
  import * as React from "react";
12
13
 
@@ -127,6 +128,7 @@ export default class Marker extends React.Component<Props> {
127
128
  answerStyles,
128
129
  hovered,
129
130
  focused,
131
+ label,
130
132
  } = this.props;
131
133
 
132
134
  // We cannot make dropdown openers untabbable, so we isolate tabbing
@@ -141,6 +143,8 @@ export default class Marker extends React.Component<Props> {
141
143
  styles.marker,
142
144
  active && !markerDisabled && styles.markerActive,
143
145
  ]}
146
+ // already translated in: /widgets/graded-group.tsx
147
+ aria-label={markerDisabled ? i18n._("Correct!") : label}
144
148
  >
145
149
  {this.renderIcon()}
146
150
  </View>
@@ -598,16 +598,11 @@ export class LabelImage extends React.Component<
598
598
  }
599
599
  // cannot change answer choices once question is answered
600
600
  disabled={disabled}
601
- opener={({opened, text}) => (
601
+ opener={({opened}) => (
602
602
  <Clickable
603
603
  role="button"
604
+ aria-expanded={opened}
604
605
  key={`marker-${marker.x}.${marker.y}`}
605
- aria-label={
606
- // already translated in: /widgets/graded-group.tsx
607
- showCorrectness === "correct"
608
- ? i18n._("Correct!")
609
- : marker.label
610
- }
611
606
  >
612
607
  {({hovered, focused, pressed}) => (
613
608
  <Marker