@khanacademy/perseus 5.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/dist/components/fixed-to-responsive.d.ts +27 -1
  3. package/dist/components/fixed-to-responsive.js.flow +27 -1
  4. package/dist/components/graph.d.ts +42 -26
  5. package/dist/components/graph.js.flow +42 -28
  6. package/dist/components/graphie.d.ts +34 -22
  7. package/dist/components/graphie.js.flow +37 -24
  8. package/dist/components/hud.d.ts +8 -14
  9. package/dist/components/hud.js.flow +7 -14
  10. package/dist/components/inline-icon.d.ts +9 -19
  11. package/dist/components/inline-icon.js.flow +26 -13
  12. package/dist/components/lint.d.ts +41 -13
  13. package/dist/components/lint.js.flow +42 -13
  14. package/dist/components/math-output.d.ts +15 -11
  15. package/dist/components/math-output.js.flow +15 -11
  16. package/dist/components/sortable.d.ts +17 -9
  17. package/dist/components/sortable.js.flow +22 -9
  18. package/dist/components/svg-image.d.ts +5 -3
  19. package/dist/components/svg-image.js.flow +5 -3
  20. package/dist/components/tooltip.d.ts +45 -4
  21. package/dist/components/tooltip.js.flow +44 -31
  22. package/dist/es/index.css +0 -3
  23. package/dist/es/index.js +478 -649
  24. package/dist/es/index.js.map +1 -1
  25. package/dist/index.css +0 -3
  26. package/dist/index.js +482 -646
  27. package/dist/index.js.map +1 -1
  28. package/dist/perseus-types.d.ts +11 -9
  29. package/dist/perseus-types.js.flow +11 -9
  30. package/dist/renderer.d.ts +2 -2
  31. package/dist/renderer.js.flow +1 -3
  32. package/dist/styles/shared.d.ts +0 -1
  33. package/dist/styles/shared.js.flow +0 -1
  34. package/dist/types.d.ts +0 -10
  35. package/dist/types.js.flow +0 -13
  36. package/dist/util/a11y.d.ts +0 -1
  37. package/dist/util/a11y.js.flow +0 -1
  38. package/dist/util/interactive.d.ts +2 -0
  39. package/dist/util/interactive.js.flow +2 -0
  40. package/dist/util.d.ts +3 -3
  41. package/dist/util.js.flow +4 -3
  42. package/dist/widgets/grapher.d.ts +1 -1
  43. package/dist/widgets/grapher.js.flow +12 -3
  44. package/dist/widgets/matcher.d.ts +7 -3
  45. package/dist/widgets/matcher.js.flow +7 -3
  46. package/dist/widgets/number-line.d.ts +1 -1
  47. package/dist/widgets/number-line.js.flow +1 -1
  48. package/package.json +2 -2
  49. package/src/__tests__/__snapshots__/item-renderer.test.tsx.snap +151 -159
  50. package/src/__tests__/__snapshots__/renderer.test.tsx.snap +358 -394
  51. package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +169 -189
  52. package/src/components/__stories__/lint.stories.tsx +56 -21
  53. package/src/components/__stories__/sortable.stories.tsx +5 -5
  54. package/src/components/__stories__/tooltip.stories.tsx +52 -0
  55. package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +114 -30
  56. package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +172 -204
  57. package/src/components/__tests__/sortable.test.tsx +54 -16
  58. package/src/components/__tests__/sorter.test.tsx +12 -9
  59. package/src/components/fixed-to-responsive.tsx +43 -38
  60. package/src/components/graph.tsx +95 -81
  61. package/src/components/graphie.tsx +62 -32
  62. package/src/components/hud.tsx +104 -115
  63. package/src/components/inline-icon.tsx +15 -32
  64. package/src/components/input-with-examples.tsx +4 -4
  65. package/src/components/lint.tsx +47 -41
  66. package/src/components/math-output.tsx +17 -11
  67. package/src/components/simple-keypad-input.tsx +2 -2
  68. package/src/components/sortable.tsx +134 -94
  69. package/src/components/svg-image.tsx +10 -11
  70. package/src/components/tooltip.tsx +189 -171
  71. package/src/interactive2/types.ts +2 -2
  72. package/src/mixins/provide-keypad.tsx +2 -2
  73. package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +708 -764
  74. package/src/perseus-types.ts +13 -9
  75. package/src/renderer.tsx +11 -22
  76. package/src/types.ts +0 -18
  77. package/src/util/interactive.ts +18 -5
  78. package/src/util/tex.ts +13 -77
  79. package/src/util.ts +3 -4
  80. package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +2 -2
  81. package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +717 -773
  82. package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +28 -36
  83. package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +52 -60
  84. package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +100 -108
  85. package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +212 -260
  86. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +613 -641
  87. package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +249 -261
  88. package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +671 -735
  89. package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +2676 -2684
  90. package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +938 -1002
  91. package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +28 -36
  92. package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +227 -255
  93. package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +353 -357
  94. package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +255 -259
  95. package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +2401 -2433
  96. package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +600 -756
  97. package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +420 -428
  98. package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +762 -770
  99. package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +373 -393
  100. package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +116 -148
  101. package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +289 -301
  102. package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +1679 -1711
  103. package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +2692 -2960
  104. package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +90 -98
  105. package/src/widgets/__tests__/matcher.test.tsx +33 -9
  106. package/src/widgets/expression.tsx +9 -6
  107. package/src/widgets/grapher.tsx +3 -3
  108. package/src/widgets/image.tsx +2 -2
  109. package/src/widgets/interactive-graph.tsx +5 -5
  110. package/src/widgets/matcher.tsx +43 -24
  111. package/src/widgets/number-line.tsx +1 -1
  112. package/src/widgets/simulator.tsx +4 -6
  113. package/{tsconfig.json → tsconfig-build.json} +6 -6
  114. package/tsconfig-build.tsbuildinfo +1 -0
  115. package/tsconfig.tsbuildinfo +0 -1
@@ -2,160 +2,152 @@
2
2
 
3
3
  exports[`video widget should snapshot on mobile: first mobile render 1`] = `
4
4
  <div>
5
- <span
6
- class="mock-KatexProvider"
5
+ <div
6
+ class="perseus-renderer perseus-renderer-responsive"
7
7
  >
8
8
  <div
9
- class="perseus-renderer perseus-renderer-responsive"
9
+ class="paragraph"
10
+ data-perseus-paragraph-index="0"
10
11
  >
11
12
  <div
12
13
  class="paragraph"
13
- data-perseus-paragraph-index="0"
14
14
  >
15
- <div
16
- class="paragraph"
17
- >
18
- Watch the Biogeography: Where Life Lives video to find the answer.
19
- </div>
15
+ Watch the Biogeography: Where Life Lives video to find the answer.
20
16
  </div>
17
+ </div>
18
+ <div
19
+ class="paragraph"
20
+ data-perseus-paragraph-index="1"
21
+ >
21
22
  <div
22
23
  class="paragraph"
23
- data-perseus-paragraph-index="1"
24
24
  >
25
25
  <div
26
- class="paragraph"
26
+ class="perseus-widget-container widget-nohighlight widget-block"
27
27
  >
28
28
  <div
29
- class="perseus-widget-container widget-nohighlight widget-block"
29
+ class="default_xu2jcg"
30
30
  >
31
31
  <div
32
- class="default_xu2jcg"
32
+ class="fixed-to-responsive"
33
+ style="max-width: 1280px; max-height: 720px;"
33
34
  >
34
35
  <div
35
- class="fixed-to-responsive"
36
- style="max-width: 1280px; max-height: 720px;"
36
+ style="padding-bottom: 56.25%;"
37
+ />
38
+ <div
39
+ class="default_xu2jcg-o_O-srOnly_19bpjuy"
37
40
  >
38
- <div
39
- style="padding-bottom: 56.25%;"
40
- />
41
- <div
42
- class="default_xu2jcg-o_O-srOnly_19bpjuy"
43
- >
44
- Khan Academy video wrapper
45
- </div>
46
- <iframe
47
- allowfullscreen=""
48
- class="perseus-video-widget"
49
- height="720"
50
- sandbox="allow-same-origin allow-scripts"
51
- src="https://www.khanacademy.org/embed_video?slug=biogeography-where-life-lives&internal_video_only=1"
52
- width="1280"
53
- />
41
+ Khan Academy video wrapper
54
42
  </div>
43
+ <iframe
44
+ allowfullscreen=""
45
+ class="perseus-video-widget"
46
+ height="720"
47
+ sandbox="allow-same-origin allow-scripts"
48
+ src="https://www.khanacademy.org/embed_video?slug=biogeography-where-life-lives&internal_video_only=1"
49
+ width="1280"
50
+ />
51
+ </div>
52
+ <div
53
+ class="default_xu2jcg-o_O-transcriptLink_18xwqfz"
54
+ >
55
+ <span
56
+ class="text_f1191h"
57
+ />
55
58
  <div
56
- class="default_xu2jcg-o_O-transcriptLink_18xwqfz"
59
+ aria-hidden="true"
60
+ class="default_xu2jcg-o_O-inlineStyles_sc01dy"
61
+ />
62
+ <a
63
+ class="shared_htyo3s-o_O-resting_nelfll visited-no-recolor"
64
+ href="/transcript/videoNotFound"
65
+ rel="noopener noreferrer"
66
+ target="_blank"
57
67
  >
58
- <span
59
- class="text_f1191h"
60
- />
61
- <div
62
- aria-hidden="true"
63
- class="default_xu2jcg-o_O-inlineStyles_sc01dy"
64
- />
65
- <a
66
- class="shared_htyo3s-o_O-resting_nelfll visited-no-recolor"
67
- href="/transcript/videoNotFound"
68
- rel="noopener noreferrer"
69
- target="_blank"
70
- >
71
- See video transcript
72
- </a>
73
- </div>
68
+ See video transcript
69
+ </a>
74
70
  </div>
75
71
  </div>
76
72
  </div>
77
73
  </div>
78
74
  </div>
79
- </span>
75
+ </div>
80
76
  </div>
81
77
  `;
82
78
 
83
79
  exports[`video widget should snapshot: first render 1`] = `
84
80
  <div>
85
- <span
86
- class="mock-KatexProvider"
81
+ <div
82
+ class="perseus-renderer perseus-renderer-responsive"
87
83
  >
88
84
  <div
89
- class="perseus-renderer perseus-renderer-responsive"
85
+ class="paragraph"
86
+ data-perseus-paragraph-index="0"
90
87
  >
91
88
  <div
92
89
  class="paragraph"
93
- data-perseus-paragraph-index="0"
94
90
  >
95
- <div
96
- class="paragraph"
97
- >
98
- Watch the Biogeography: Where Life Lives video to find the answer.
99
- </div>
91
+ Watch the Biogeography: Where Life Lives video to find the answer.
100
92
  </div>
93
+ </div>
94
+ <div
95
+ class="paragraph"
96
+ data-perseus-paragraph-index="1"
97
+ >
101
98
  <div
102
99
  class="paragraph"
103
- data-perseus-paragraph-index="1"
104
100
  >
105
101
  <div
106
- class="paragraph"
102
+ class="perseus-widget-container widget-nohighlight widget-block"
107
103
  >
108
104
  <div
109
- class="perseus-widget-container widget-nohighlight widget-block"
105
+ class="default_xu2jcg"
110
106
  >
111
107
  <div
112
- class="default_xu2jcg"
108
+ class="fixed-to-responsive"
109
+ style="max-width: 1280px; max-height: 720px;"
113
110
  >
114
111
  <div
115
- class="fixed-to-responsive"
116
- style="max-width: 1280px; max-height: 720px;"
112
+ style="padding-bottom: 56.25%;"
113
+ />
114
+ <div
115
+ class="default_xu2jcg-o_O-srOnly_19bpjuy"
117
116
  >
118
- <div
119
- style="padding-bottom: 56.25%;"
120
- />
121
- <div
122
- class="default_xu2jcg-o_O-srOnly_19bpjuy"
123
- >
124
- Khan Academy video wrapper
125
- </div>
126
- <iframe
127
- allowfullscreen=""
128
- class="perseus-video-widget"
129
- height="720"
130
- sandbox="allow-same-origin allow-scripts"
131
- src="https://www.khanacademy.org/embed_video?slug=biogeography-where-life-lives&internal_video_only=1"
132
- width="1280"
133
- />
117
+ Khan Academy video wrapper
134
118
  </div>
119
+ <iframe
120
+ allowfullscreen=""
121
+ class="perseus-video-widget"
122
+ height="720"
123
+ sandbox="allow-same-origin allow-scripts"
124
+ src="https://www.khanacademy.org/embed_video?slug=biogeography-where-life-lives&internal_video_only=1"
125
+ width="1280"
126
+ />
127
+ </div>
128
+ <div
129
+ class="default_xu2jcg-o_O-transcriptLink_18xwqfz"
130
+ >
131
+ <span
132
+ class="text_f1191h"
133
+ />
135
134
  <div
136
- class="default_xu2jcg-o_O-transcriptLink_18xwqfz"
135
+ aria-hidden="true"
136
+ class="default_xu2jcg-o_O-inlineStyles_sc01dy"
137
+ />
138
+ <a
139
+ class="shared_htyo3s-o_O-resting_nelfll visited-no-recolor"
140
+ href="/transcript/videoNotFound"
141
+ rel="noopener noreferrer"
142
+ target="_blank"
137
143
  >
138
- <span
139
- class="text_f1191h"
140
- />
141
- <div
142
- aria-hidden="true"
143
- class="default_xu2jcg-o_O-inlineStyles_sc01dy"
144
- />
145
- <a
146
- class="shared_htyo3s-o_O-resting_nelfll visited-no-recolor"
147
- href="/transcript/videoNotFound"
148
- rel="noopener noreferrer"
149
- target="_blank"
150
- >
151
- See video transcript
152
- </a>
153
- </div>
144
+ See video transcript
145
+ </a>
154
146
  </div>
155
147
  </div>
156
148
  </div>
157
149
  </div>
158
150
  </div>
159
- </span>
151
+ </div>
160
152
  </div>
161
153
  `;
@@ -1,4 +1,3 @@
1
- import getRenderA11yString from "katex/dist/contrib/render-a11y-string";
2
1
  import * as React from "react";
3
2
  import "@testing-library/jest-dom";
4
3
 
@@ -26,15 +25,18 @@ describe("matcher widget", () => {
26
25
 
27
26
  jest.spyOn(Dependencies, "getDependencies").mockReturnValue({
28
27
  ...testDependencies,
29
- getKaTeX: () => {
30
- return Promise.resolve({});
28
+ TeX: ({
29
+ children,
30
+ onRender: onLoad,
31
+ }: {
32
+ children: React.ReactNode;
33
+ onRender?: () => unknown;
34
+ }) => {
35
+ React.useLayoutEffect(() => {
36
+ onLoad?.();
37
+ }, [onLoad]);
38
+ return <span className="tex-mock">{children}</span>;
31
39
  },
32
- TeX: ({children}: {children: React.ReactNode}) => (
33
- <span className="tex-mock">{children}</span>
34
- ),
35
- // @ts-expect-error [FEI-5003] - TS2322 - Type 'Promise<any>' is not assignable to type '() => Promise<katexA11y>'.
36
- getRenderA11yString: Promise.resolve(getRenderA11yString),
37
- shouldUseFutureKaTeX: (flag: boolean) => {},
38
40
  });
39
41
  });
40
42
 
@@ -149,4 +151,26 @@ describe("matcher widget", () => {
149
151
  // Assert
150
152
  expect(renderer).toHaveBeenAnsweredIncorrectly();
151
153
  });
154
+
155
+ it("is scored incorrect if the math renderer hasn't loaded yet", () => {
156
+ // Arrange: stub the TeX renderer to never call its onRender prop,
157
+ // which is how the matcher knows the math renderer is ready.
158
+ jest.spyOn(Dependencies, "getDependencies").mockReturnValue({
159
+ ...testDependencies,
160
+ TeX: () => {
161
+ return null;
162
+ },
163
+ });
164
+
165
+ const apiOptions: APIOptions = {
166
+ isMobile: false,
167
+ };
168
+ const {renderer} = renderQuestion(question1, apiOptions);
169
+
170
+ // Act
171
+ renderer.guessAndScore();
172
+
173
+ // Assert
174
+ expect(renderer).toHaveBeenAnsweredIncorrectly();
175
+ });
152
176
  });
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable react/prop-types */
2
2
  import * as KAS from "@khanacademy/kas";
3
- import {KeypadInput, KeypadTypes} from "@khanacademy/math-input";
3
+ import {KeypadInput, KeypadType} from "@khanacademy/math-input";
4
4
  import {linterContextDefault} from "@khanacademy/perseus-linter";
5
5
  import * as i18n from "@khanacademy/wonder-blocks-i18n";
6
6
  import classNames from "classnames";
@@ -9,7 +9,10 @@ import _ from "underscore";
9
9
 
10
10
  import InlineIcon from "../components/inline-icon";
11
11
  import MathInput from "../components/math-input";
12
- import Tooltip from "../components/tooltip";
12
+ import Tooltip, {
13
+ HorizontalDirection,
14
+ VerticalDirection,
15
+ } from "../components/tooltip";
13
16
  import {iconExclamationSign} from "../icon-paths";
14
17
  import {Errors as PerseusErrors, Log} from "../logging/log";
15
18
  import * as Changeable from "../mixins/changeable";
@@ -478,9 +481,9 @@ export class Expression extends React.Component<Props, ExpressionState> {
478
481
  <span className="error-tooltip" role="tooltip">
479
482
  <Tooltip
480
483
  className="error-text-container"
481
- horizontalPosition="right"
482
- horizontalAlign="left"
483
- verticalPosition="top"
484
+ horizontalPosition={HorizontalDirection.Right}
485
+ horizontalAlign={HorizontalDirection.Left}
486
+ verticalPosition={VerticalDirection.Top}
484
487
  arrowSize={10}
485
488
  borderColor="#fcc335"
486
489
  show={this.state.showErrorText}
@@ -549,7 +552,7 @@ const keypadConfigurationForProps = (
549
552
  ) => {
550
553
  // Always use the Expression keypad, regardless of the button sets that have
551
554
  // been enabled.
552
- const keypadType = KeypadTypes.EXPRESSION;
555
+ const keypadType = KeypadType.EXPRESSION;
553
556
 
554
557
  // Extract any and all variables and constants from the answer forms.
555
558
  const uniqueExtraVariables: Record<string, any> = {};
@@ -476,15 +476,15 @@ class Grapher extends React.Component<Props> {
476
476
  _calculateMobileTickStep(
477
477
  gridStep: JSX.LibraryManagedAttributes<
478
478
  typeof Graphie,
479
- React.ComponentProps<typeof Graphie>
479
+ Required<React.ComponentProps<typeof Graphie>>
480
480
  >["gridStep"],
481
481
  step: JSX.LibraryManagedAttributes<
482
482
  typeof Graphie,
483
- React.ComponentProps<typeof Graphie>
483
+ Required<React.ComponentProps<typeof Graphie>>
484
484
  >["step"],
485
485
  ranges: JSX.LibraryManagedAttributes<
486
486
  typeof Graphie,
487
- React.ComponentProps<typeof Graphie>
487
+ Required<React.ComponentProps<typeof Graphie>>
488
488
  >["ranges"],
489
489
  ): any {
490
490
  const tickStep = Util.constrainedTickStepsFromTickSteps(step, ranges);
@@ -12,7 +12,7 @@ import Renderer from "../renderer";
12
12
  import {baseUnitPx} from "../styles/constants";
13
13
  import mediaQueries from "../styles/media-queries";
14
14
 
15
- import type {PerseusImageWidgetOptions} from "../perseus-types";
15
+ import type {Range, PerseusImageWidgetOptions} from "../perseus-types";
16
16
  import type {
17
17
  ChangeFn,
18
18
  PerseusScore,
@@ -21,7 +21,7 @@ import type {
21
21
  } from "../types";
22
22
 
23
23
  const defaultBoxSize = 400;
24
- const defaultRange = [0, 10];
24
+ const defaultRange: Range = [0, 10];
25
25
  const defaultBackgroundImage = {
26
26
  url: null,
27
27
  width: 0,
@@ -43,7 +43,7 @@ const TRASH_ICON_URI =
43
43
 
44
44
  const defaultBackgroundImage = {
45
45
  url: null,
46
- } as const;
46
+ };
47
47
 
48
48
  const eq = Util.eq;
49
49
  const deepEq = Util.deepEq;
@@ -417,7 +417,6 @@ class InteractiveGraph extends React.Component<Props, State> {
417
417
  [-10, 10],
418
418
  ],
419
419
  step: [1, 1],
420
- // @ts-expect-error [FEI-5003] - TS2739 - Type '{ readonly url: null; }' is missing the following properties from type 'PerseusImageBackground': width, height
421
420
  backgroundImage: defaultBackgroundImage,
422
421
  markings: "graph",
423
422
  showTooltips: false,
@@ -1984,9 +1983,10 @@ class InteractiveGraph extends React.Component<Props, State> {
1984
1983
  instructions = undefined;
1985
1984
  }
1986
1985
 
1987
- const onMouseDown = this.isClickToAddPoints()
1988
- ? this.handleAddPointsMouseDown
1989
- : null;
1986
+ let onMouseDown;
1987
+ if (this.isClickToAddPoints()) {
1988
+ onMouseDown = this.handleAddPointsMouseDown;
1989
+ }
1990
1990
 
1991
1991
  const gridStep =
1992
1992
  this.props.gridStep ||
@@ -9,7 +9,7 @@ import PropTypes from "prop-types";
9
9
  import * as React from "react";
10
10
  import _ from "underscore";
11
11
 
12
- import Sortable from "../components/sortable";
12
+ import Sortable, {Layout} from "../components/sortable";
13
13
  import {getDependencies} from "../dependencies";
14
14
  import {ApiOptions} from "../perseus-api";
15
15
  import Renderer from "../renderer";
@@ -21,6 +21,12 @@ import type {WidgetExports} from "../types";
21
21
  const {shuffle, seededRNG} = Util;
22
22
  const HACKY_CSS_CLASSNAME = "perseus-widget-matcher";
23
23
 
24
+ type State = {
25
+ leftHeight: number;
26
+ rightHeight: number;
27
+ texRendererLoaded: boolean;
28
+ };
29
+
24
30
  class Matcher extends React.Component<any, any> {
25
31
  static propTypes = {
26
32
  apiOptions: ApiOptions.propTypes,
@@ -46,27 +52,40 @@ class Matcher extends React.Component<any, any> {
46
52
  linterContext: linterContextDefault,
47
53
  };
48
54
 
49
- state: any = {
55
+ state: State = {
50
56
  leftHeight: 0,
51
57
  rightHeight: 0,
52
- katex: null,
58
+ texRendererLoaded: false,
53
59
  };
54
60
 
55
- componentDidMount() {
56
- getDependencies()
57
- .getKaTeX()
58
- .then((katex) => this.setState({katex}));
59
- }
60
-
61
- render(): React.ReactNode {
62
- // We don't render the Matcher until KaTeX has fully loaded, in case
63
- // the sortables are rendering KaTeX content. This is un-optimal as
64
- // we end up loading KaTeX even when we may not need it, however it
65
- // helps to ensure that the dimensions of the sortables (and thus the
66
- // Matcher) will be correct when they render, if their contents are
67
- // KaTeX-derived.
68
- if (!this.state.katex) {
69
- return <CircularSpinner />;
61
+ render(): React.ReactElement {
62
+ // To minimize layout shift, we display a spinner until our math
63
+ // renderer is ready to render the math inside the matcher. To
64
+ // do this, we:
65
+ // - render a dummy TeX component to force the math renderer to load
66
+ // - display a spinner until the TeX component calls its onRender
67
+ // callback, signifying that the math is rendered (from which we can
68
+ // infer that the math renderer has loaded)
69
+ //
70
+ // If we didn't do this, the user might see a matcher with empty
71
+ // columns on first render, and then the math would pop in a few
72
+ // moments later once the rendering library loaded.
73
+ if (!this.state.texRendererLoaded) {
74
+ const {TeX} = getDependencies();
75
+ return (
76
+ <>
77
+ <CircularSpinner />
78
+ <div style={{display: "none"}}>
79
+ <TeX
80
+ onRender={() => {
81
+ this.setState({texRendererLoaded: true});
82
+ }}
83
+ >
84
+ 1
85
+ </TeX>
86
+ </div>
87
+ </>
88
+ );
70
89
  }
71
90
 
72
91
  // Use the same random() function to shuffle both columns sequentially
@@ -123,7 +142,7 @@ class Matcher extends React.Component<any, any> {
123
142
  <td className={css(styles.column)}>
124
143
  <Sortable
125
144
  options={left}
126
- layout="vertical"
145
+ layout={Layout.VERTICAL}
127
146
  padding={this.props.padding}
128
147
  disabled={!this.props.orderMatters}
129
148
  constraints={constraints}
@@ -139,7 +158,7 @@ class Matcher extends React.Component<any, any> {
139
158
  <Sortable
140
159
  // @ts-expect-error [FEI-5003] - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
141
160
  options={right}
142
- layout="vertical"
161
+ layout={Layout.VERTICAL}
143
162
  padding={this.props.padding}
144
163
  constraints={constraints}
145
164
  onMeasure={this.onMeasureRight}
@@ -172,10 +191,10 @@ class Matcher extends React.Component<any, any> {
172
191
  };
173
192
 
174
193
  getUserInput: () => any = () => {
175
- // If KaTeX hasn't loaded then we won't be able to get the contents
176
- // of the sortables on the left and right, so we just return empty
177
- // arrays until we render for the first time.
178
- if (!this.state.katex) {
194
+ // If the math renderer hasn't loaded then we won't be able to get the
195
+ // contents of the sortables on the left and right, so we just return
196
+ // empty arrays until we render for the first time.
197
+ if (!this.state.texRendererLoaded) {
179
198
  return {
180
199
  left: [],
181
200
  right: [],
@@ -192,7 +192,7 @@ const TickMarks: any = Graphie.createSimpleClass((graphie, props) => {
192
192
  });
193
193
 
194
194
  type Props = ChangeableProps & {
195
- range: ReadonlyArray<number>;
195
+ range: [number, number];
196
196
  labelRange: ReadonlyArray<number | null>;
197
197
  labelStyle: string;
198
198
  labelTicks: boolean;
@@ -8,7 +8,6 @@ import _ from "underscore";
8
8
 
9
9
  import Graphie from "../components/graphie";
10
10
  import InfoTip from "../components/info-tip";
11
- import MathOutput from "../components/math-output";
12
11
  import NumberInput from "../components/number-input";
13
12
  import InteractiveUtil from "../interactive2/interactive-util";
14
13
  import * as Changeable from "../mixins/changeable";
@@ -17,6 +16,7 @@ import Util from "../util";
17
16
  import KhanColors from "../util/colors";
18
17
  import KhanMath from "../util/math";
19
18
 
19
+ import type {Range} from "../perseus-types";
20
20
  import type {WidgetExports} from "../types";
21
21
 
22
22
  const {assert} = InteractiveUtil;
@@ -231,9 +231,7 @@ class Histogram extends React.Component<any, any> {
231
231
  range: range,
232
232
  data: data,
233
233
  scale: [
234
- // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Coordinates'.
235
234
  Util.scaleFromExtent(range[0], this.props.box[0]),
236
- // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Coordinates'.
237
235
  Util.scaleFromExtent(range[1], this.props.box[1]),
238
236
  ],
239
237
  } as const;
@@ -352,8 +350,8 @@ class Histogram extends React.Component<any, any> {
352
350
  };
353
351
 
354
352
  /* Convenience functions that help calculate props based on other props. */
355
- _range = (props) => {
356
- const defaultRange = [
353
+ _range = (props): [Range, Range] => {
354
+ const defaultRange: [Range, Range] = [
357
355
  [0, 100],
358
356
  [-1, 10],
359
357
  ];
@@ -361,7 +359,7 @@ class Histogram extends React.Component<any, any> {
361
359
  return props.data ? this._getRangeForData(props.data) : defaultRange;
362
360
  };
363
361
 
364
- _getRangeForData = (data: any) => {
362
+ _getRangeForData = (data: any): [Range, Range] => {
365
363
  // Find first/last non-zero entry and add some padding
366
364
  const padding = 10;
367
365
  const firstIndex = _.indexOf(
@@ -15,11 +15,11 @@
15
15
  }
16
16
  },
17
17
  "references": [
18
- {"path": "../kas"},
19
- {"path": "../kmath"},
20
- {"path": "../math-input"},
21
- {"path": "../perseus-linter"},
22
- {"path": "../pure-markdown"},
23
- {"path": "../simple-markdown"},
18
+ {"path": "../kas/tsconfig-build.json"},
19
+ {"path": "../kmath/tsconfig-build.json"},
20
+ {"path": "../math-input/tsconfig-build.json"},
21
+ {"path": "../perseus-linter/tsconfig-build.json"},
22
+ {"path": "../pure-markdown/tsconfig-build.json"},
23
+ {"path": "../simple-markdown/tsconfig-build.json"},
24
24
  ]
25
25
  }