@khanacademy/perseus 4.0.2 → 6.0.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 (249) hide show
  1. package/CHANGELOG.md +57 -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/highlighting/highlightable-content.d.ts +4 -4
  9. package/dist/components/highlighting/highlightable-content.js.flow +4 -7
  10. package/dist/components/highlighting/ui/highlight-renderer.d.ts +6 -6
  11. package/dist/components/highlighting/ui/highlight-renderer.js.flow +6 -8
  12. package/dist/components/highlighting/ui/highlight-set-renderer.d.ts +5 -5
  13. package/dist/components/highlighting/ui/highlight-set-renderer.js.flow +5 -8
  14. package/dist/components/highlighting/ui/highlight-tooltip.d.ts +2 -2
  15. package/dist/components/highlighting/ui/highlight-tooltip.js.flow +2 -4
  16. package/dist/components/highlighting/ui/highlighting-ui.d.ts +2 -2
  17. package/dist/components/highlighting/ui/highlighting-ui.js.flow +2 -2
  18. package/dist/components/highlighting/ui/selection-tracker.d.ts +5 -5
  19. package/dist/components/highlighting/ui/selection-tracker.js.flow +5 -7
  20. package/dist/components/highlighting/word-indexer.d.ts +2 -2
  21. package/dist/components/highlighting/word-indexer.js.flow +2 -2
  22. package/dist/components/hud.d.ts +8 -14
  23. package/dist/components/hud.js.flow +7 -14
  24. package/dist/components/inline-icon.d.ts +27 -3
  25. package/dist/components/inline-icon.js.flow +26 -3
  26. package/dist/components/lint.d.ts +41 -13
  27. package/dist/components/lint.js.flow +42 -13
  28. package/dist/components/math-output.d.ts +15 -11
  29. package/dist/components/math-output.js.flow +15 -11
  30. package/dist/components/simple-keypad-input.d.ts +1 -1
  31. package/dist/components/simple-keypad-input.js.flow +1 -1
  32. package/dist/components/sortable.d.ts +17 -9
  33. package/dist/components/sortable.js.flow +22 -9
  34. package/dist/components/svg-image.d.ts +5 -3
  35. package/dist/components/svg-image.js.flow +5 -3
  36. package/dist/components/tex-buttons.d.ts +2 -2
  37. package/dist/components/tex-buttons.js.flow +2 -2
  38. package/dist/components/tooltip.d.ts +45 -4
  39. package/dist/components/tooltip.js.flow +44 -31
  40. package/dist/error-boundary.d.ts +4 -4
  41. package/dist/error-boundary.js.flow +4 -6
  42. package/dist/es/index.css +0 -3
  43. package/dist/es/index.js +484 -658
  44. package/dist/es/index.js.map +1 -1
  45. package/dist/index.css +0 -3
  46. package/dist/index.js +488 -655
  47. package/dist/index.js.map +1 -1
  48. package/dist/perseus-types.d.ts +11 -10
  49. package/dist/perseus-types.js.flow +11 -10
  50. package/dist/renderer.d.ts +2 -2
  51. package/dist/renderer.js.flow +1 -3
  52. package/dist/styles/shared.d.ts +0 -1
  53. package/dist/styles/shared.js.flow +0 -1
  54. package/dist/types.d.ts +0 -10
  55. package/dist/types.js.flow +0 -13
  56. package/dist/util/a11y.d.ts +0 -1
  57. package/dist/util/a11y.js.flow +0 -1
  58. package/dist/util/interactive.d.ts +2 -0
  59. package/dist/util/interactive.js.flow +2 -0
  60. package/dist/util.d.ts +3 -3
  61. package/dist/util.js.flow +4 -3
  62. package/dist/widgets/__stories__/test-keypad-context-wrapper.d.ts +2 -2
  63. package/dist/widgets/__stories__/test-keypad-context-wrapper.js.flow +2 -4
  64. package/dist/widgets/expression.d.ts +2 -2
  65. package/dist/widgets/expression.js.flow +2 -2
  66. package/dist/widgets/grapher.d.ts +1 -1
  67. package/dist/widgets/grapher.js.flow +12 -3
  68. package/dist/widgets/interaction/element-container.d.ts +5 -4
  69. package/dist/widgets/interaction/element-container.js.flow +6 -11
  70. package/dist/widgets/label-image/marker.d.ts +4 -4
  71. package/dist/widgets/label-image/marker.js.flow +4 -6
  72. package/dist/widgets/matcher.d.ts +7 -3
  73. package/dist/widgets/matcher.js.flow +7 -3
  74. package/dist/widgets/number-line.d.ts +1 -1
  75. package/dist/widgets/number-line.js.flow +1 -1
  76. package/dist/widgets/numeric-input.d.ts +0 -2
  77. package/dist/widgets/numeric-input.js.flow +0 -4
  78. package/dist/widgets/radio/base-radio.d.ts +7 -1
  79. package/dist/widgets/radio/base-radio.js.flow +7 -1
  80. package/dist/widgets/radio/choice-icon/choice-icon.d.ts +1 -1
  81. package/dist/widgets/radio/choice-icon/choice-icon.js.flow +1 -1
  82. package/dist/widgets/radio/choice-icon/cross-out-line.d.ts +2 -2
  83. package/dist/widgets/radio/choice-icon/cross-out-line.js.flow +2 -2
  84. package/dist/widgets/radio/focus-ring.d.ts +8 -1
  85. package/dist/widgets/radio/focus-ring.js.flow +8 -1
  86. package/dist/widgets/radio/option-status.d.ts +2 -2
  87. package/dist/widgets/radio/option-status.js.flow +2 -2
  88. package/dist/widgets/video-transcript-link.d.ts +1 -1
  89. package/dist/widgets/video-transcript-link.js.flow +1 -1
  90. package/package.json +4 -4
  91. package/src/__stories__/item-renderer.stories.tsx +2 -6
  92. package/src/__stories__/server-item-renderer.stories.tsx +2 -6
  93. package/src/__tests__/__snapshots__/item-renderer.test.tsx.snap +151 -159
  94. package/src/__tests__/__snapshots__/renderer.test.tsx.snap +358 -394
  95. package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +169 -189
  96. package/src/components/__stories__/button-group.stories.tsx +2 -6
  97. package/src/components/__stories__/fixed-to-responsive.stories.tsx +14 -16
  98. package/src/components/__stories__/graph.stories.tsx +3 -5
  99. package/src/components/__stories__/graphie.stories.tsx +3 -5
  100. package/src/components/__stories__/hud.stories.tsx +2 -6
  101. package/src/components/__stories__/icon.stories.tsx +1 -1
  102. package/src/components/__stories__/image-loader.stories.tsx +4 -4
  103. package/src/components/__stories__/info-tip.stories.tsx +2 -6
  104. package/src/components/__stories__/inline-icon.stories.tsx +4 -8
  105. package/src/components/__stories__/input-with-examples.stories.tsx +6 -10
  106. package/src/components/__stories__/lint.stories.tsx +62 -27
  107. package/src/components/__stories__/math-input.stories.tsx +4 -8
  108. package/src/components/__stories__/math-output.stories.tsx +3 -5
  109. package/src/components/__stories__/multi-button-group.stories.tsx +2 -6
  110. package/src/components/__stories__/number-input.stories.tsx +6 -8
  111. package/src/components/__stories__/prop-check-box.stories.tsx +9 -9
  112. package/src/components/__stories__/range-input.stories.tsx +4 -6
  113. package/src/components/__stories__/simple-keypad-input.stories.tsx +2 -4
  114. package/src/components/__stories__/sortable.stories.tsx +20 -20
  115. package/src/components/__stories__/stub-tag-editor.stories.tsx +5 -9
  116. package/src/components/__stories__/svg-image.stories.tsx +10 -18
  117. package/src/components/__stories__/tex.stories.tsx +1 -3
  118. package/src/components/__stories__/text-buttons.stories.tsx +10 -22
  119. package/src/components/__stories__/text-input.stories.tsx +4 -10
  120. package/src/components/__stories__/text-list-editor.stories.tsx +1 -3
  121. package/src/components/__stories__/tooltip.stories.tsx +52 -0
  122. package/src/components/__stories__/zoomable-tex.stories.tsx +6 -4
  123. package/src/components/__stories__/zoomable.stories.tsx +1 -3
  124. package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +114 -30
  125. package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +172 -204
  126. package/src/components/__tests__/sortable.test.tsx +54 -16
  127. package/src/components/__tests__/sorter.test.tsx +12 -9
  128. package/src/components/fixed-to-responsive.tsx +43 -38
  129. package/src/components/graph.tsx +95 -81
  130. package/src/components/graphie.tsx +62 -32
  131. package/src/components/highlighting/highlightable-content.tsx +4 -7
  132. package/src/components/highlighting/ui/highlight-renderer.tsx +6 -9
  133. package/src/components/highlighting/ui/highlight-set-renderer.tsx +5 -8
  134. package/src/components/highlighting/ui/highlight-tooltip.tsx +2 -2
  135. package/src/components/highlighting/ui/highlighting-ui.tsx +2 -2
  136. package/src/components/highlighting/ui/selection-tracker.tsx +5 -8
  137. package/src/components/highlighting/word-indexer.tsx +2 -2
  138. package/src/components/hud.tsx +104 -115
  139. package/src/components/inline-icon.tsx +17 -34
  140. package/src/components/input-with-examples.tsx +4 -4
  141. package/src/components/lint.tsx +47 -41
  142. package/src/components/math-output.tsx +17 -11
  143. package/src/components/simple-keypad-input.tsx +4 -4
  144. package/src/components/sortable.tsx +134 -94
  145. package/src/components/svg-image.tsx +10 -11
  146. package/src/components/tex-buttons.tsx +2 -2
  147. package/src/components/tooltip.tsx +189 -171
  148. package/src/components/visibility-observer/__stories__/visibility-observer.stories.tsx +1 -3
  149. package/src/error-boundary.tsx +4 -7
  150. package/src/interactive2/types.ts +2 -2
  151. package/src/multi-items/__stories__/multi-renderer.stories.tsx +1 -1
  152. package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +708 -764
  153. package/src/multi-items/__tests__/multi-renderer.test.tsx +2 -3
  154. package/src/perseus-types.ts +13 -12
  155. package/src/renderer.tsx +11 -22
  156. package/src/types.ts +0 -18
  157. package/src/util/graphie.ts +3 -3
  158. package/src/util/interactive.ts +18 -5
  159. package/src/util/tex.ts +13 -77
  160. package/src/util.ts +3 -4
  161. package/src/widgets/__stories__/categorizer.stories.tsx +1 -1
  162. package/src/widgets/__stories__/cs-program.stories.tsx +1 -1
  163. package/src/widgets/__stories__/definition.stories.tsx +3 -7
  164. package/src/widgets/__stories__/dropdown.stories.tsx +1 -1
  165. package/src/widgets/__stories__/explanation.stories.tsx +2 -2
  166. package/src/widgets/__stories__/expression.stories.tsx +5 -11
  167. package/src/widgets/__stories__/graded-group-set.stories.tsx +1 -1
  168. package/src/widgets/__stories__/graded-group.stories.tsx +1 -1
  169. package/src/widgets/__stories__/grapher.stories.tsx +7 -21
  170. package/src/widgets/__stories__/group.stories.tsx +1 -1
  171. package/src/widgets/__stories__/iframe.stories.tsx +1 -1
  172. package/src/widgets/__stories__/image.stories.tsx +1 -1
  173. package/src/widgets/__stories__/input-number.stories.tsx +3 -12
  174. package/src/widgets/__stories__/interaction.stories.tsx +1 -1
  175. package/src/widgets/__stories__/interactive-graph.stories.tsx +9 -9
  176. package/src/widgets/__stories__/matcher.stories.tsx +1 -1
  177. package/src/widgets/__stories__/matrix.stories.tsx +1 -1
  178. package/src/widgets/__stories__/number-line.stories.tsx +1 -1
  179. package/src/widgets/__stories__/numeric-input.stories.tsx +3 -5
  180. package/src/widgets/__stories__/orderer.stories.tsx +1 -1
  181. package/src/widgets/__stories__/passage-ref.stories.tsx +2 -2
  182. package/src/widgets/__stories__/passage.stories.tsx +3 -9
  183. package/src/widgets/__stories__/radio.stories.tsx +3 -5
  184. package/src/widgets/__stories__/sorter.stories.tsx +1 -1
  185. package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +2 -4
  186. package/src/widgets/__stories__/transformer.stories.tsx +1 -1
  187. package/src/widgets/__stories__/unit.stories.tsx +1 -3
  188. package/src/widgets/__stories__/video-transcript-link.stories.tsx +2 -6
  189. package/src/widgets/__stories__/video.stories.tsx +1 -1
  190. package/src/widgets/__testdata__/group.testdata.ts +0 -2
  191. package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +717 -773
  192. package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +28 -36
  193. package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +52 -60
  194. package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +100 -108
  195. package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +212 -260
  196. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +613 -641
  197. package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +249 -261
  198. package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +671 -735
  199. package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +2676 -2684
  200. package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +938 -1002
  201. package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +28 -36
  202. package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +227 -255
  203. package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +353 -357
  204. package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +255 -259
  205. package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +2401 -2433
  206. package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +600 -756
  207. package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +420 -428
  208. package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +762 -770
  209. package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +373 -393
  210. package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +116 -148
  211. package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +289 -301
  212. package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +1679 -1711
  213. package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +2692 -2960
  214. package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +90 -98
  215. package/src/widgets/__tests__/group.test.tsx +0 -2
  216. package/src/widgets/__tests__/matcher.test.tsx +33 -9
  217. package/src/widgets/__tests__/radio/focus-ring.test.tsx +0 -1
  218. package/src/widgets/expression.tsx +12 -9
  219. package/src/widgets/grapher.tsx +3 -3
  220. package/src/widgets/image.tsx +2 -2
  221. package/src/widgets/interaction/element-container.tsx +7 -8
  222. package/src/widgets/interactive-graph.tsx +5 -5
  223. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +2 -4
  224. package/src/widgets/label-image/__stories__/marker.stories.tsx +9 -19
  225. package/src/widgets/label-image/marker.tsx +4 -4
  226. package/src/widgets/matcher.tsx +43 -24
  227. package/src/widgets/number-line.tsx +1 -1
  228. package/src/widgets/numeric-input.tsx +0 -3
  229. package/src/widgets/passage/passage-markdown.tsx +2 -2
  230. package/src/widgets/radio/__stories__/base-radio.stories.tsx +11 -19
  231. package/src/widgets/radio/__stories__/choice-icon.stories.tsx +9 -11
  232. package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +1 -1
  233. package/src/widgets/radio/__stories__/choice.stories.tsx +4 -4
  234. package/src/widgets/radio/__stories__/focus-ring.stories.tsx +1 -1
  235. package/src/widgets/radio/__stories__/option-status.stories.tsx +2 -4
  236. package/src/widgets/radio/base-radio.tsx +1 -1
  237. package/src/widgets/radio/choice-icon/choice-icon.tsx +5 -5
  238. package/src/widgets/radio/choice-icon/cross-out-line.tsx +1 -3
  239. package/src/widgets/radio/choice-none-above.tsx +2 -2
  240. package/src/widgets/radio/choice.tsx +1 -3
  241. package/src/widgets/radio/focus-ring.tsx +1 -1
  242. package/src/widgets/radio/option-status.tsx +2 -4
  243. package/src/widgets/radio/widget.tsx +0 -1
  244. package/src/widgets/reaction-diagram.tsx +2 -2
  245. package/src/widgets/simulator.tsx +4 -6
  246. package/src/widgets/video-transcript-link.tsx +1 -1
  247. package/{tsconfig.json → tsconfig-build.json} +6 -6
  248. package/tsconfig-build.tsbuildinfo +1 -0
  249. package/tsconfig.tsbuildinfo +0 -1
@@ -23,9 +23,8 @@ import type {Item} from "../item-types";
23
23
  import type {Tree} from "../tree-types";
24
24
 
25
25
  // A little helper used in the render callback of a MultiRenderer.
26
- const SimpleLayout: React.FC<{
27
- renderers: any;
28
- }> = ({renderers}): React.ReactElement => {
26
+ type Props = {renderers: any};
27
+ const SimpleLayout = ({renderers}: Props): React.ReactElement => {
29
28
  if (renderers == null) {
30
29
  throw new Error("renderers was null");
31
30
  }
@@ -3,6 +3,9 @@
3
3
 
4
4
  import type {Coord} from "./interactive2/types";
5
5
 
6
+ export type Range = [number, number];
7
+ export type Size = [number, number];
8
+
6
9
  // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
7
10
  type Empty = Record<string, never>;
8
11
 
@@ -218,13 +221,14 @@ export type PerseusWidget =
218
221
  | UnitInputWidget
219
222
  | VideoWidget;
220
223
 
224
+ // A background image applied to various widgets.
221
225
  export type PerseusImageBackground = {
222
226
  // The URL of the image
223
227
  url: string | null | undefined;
224
228
  // The width of the image
225
- width: number;
229
+ width?: number;
226
230
  // The height of the image
227
- height: number;
231
+ height?: number;
228
232
  // The top offset of the image
229
233
  // NOTE: perseus_data.go says this is required, but nullable, even though
230
234
  // it isn't necessary at all.
@@ -475,10 +479,10 @@ export type PerseusImageWidgetOptions = {
475
479
  labels?: ReadonlyArray<PerseusImageLabel>;
476
480
  // The range on the image render for labels
477
481
  // NOTE: perseus_data.go says this is required even though it isn't necessary.
478
- range?: ReadonlyArray<ReadonlyArray<number>>;
482
+ range?: [Range, Range];
479
483
  // The box on the image render for labels. The same as backgroundImage.width and backgroundImage.height
480
484
  // NOTE: perseus_data.go says this is required even though it isn't necessary.
481
- box?: ReadonlyArray<number>;
485
+ box?: Size;
482
486
  };
483
487
 
484
488
  export type PerseusImageLabel = {
@@ -732,9 +736,6 @@ export type PerseusNumericInputWidgetOptions = {
732
736
  size: string;
733
737
  // A coefficient style number allows the student to use - for -1 and an empty string to mean 1.
734
738
  coefficient: boolean;
735
- // Whether we're asking for all correct solutions or only one
736
- // NOTE: perseus_data.go says this is required even though it isn't necessary.
737
- multipleNumberInput?: boolean;
738
739
  // Whether to right-align the text or not
739
740
  // NOTE: perseus_data.go says this is required even though it isn't necessary.
740
741
  rightAlign?: boolean;
@@ -1137,17 +1138,17 @@ export type PerseusInteractionGraph = {
1137
1138
  // "canvas", "graph"
1138
1139
  editableSettings?: ReadonlyArray<"canvas" | "graph">;
1139
1140
  // The Grid Canvas size. e.g. [400, 140]
1140
- box: ReadonlyArray<number>;
1141
+ box: Size;
1141
1142
  // The Axis labels. e.g. ["x", "y"]
1142
1143
  labels: ReadonlyArray<string>;
1143
1144
  // The Axis ranges. e.g. [[-10, 10], [-10, 10]]
1144
- range: ReadonlyArray<ReadonlyArray<number>>;
1145
+ range: [Range, Range];
1145
1146
  // The steps in the grid. default [1, 1]
1146
- gridStep: ReadonlyArray<number>;
1147
+ gridStep: Readonly<[number, number]>;
1147
1148
  // What to show on the graph. "graph", "grid", or "none"
1148
1149
  markings: string;
1149
1150
  // The snap steps. default [0.5, 0.5]
1150
- snapStep?: ReadonlyArray<number>;
1151
+ snapStep?: Readonly<[number, number]>;
1151
1152
  // Whether the grid is valid or not. Do the numbers all make sense?
1152
1153
  // NOTE(jeremy) The editor for this widget sometimes stores the graph
1153
1154
  // editor validation error message into this field. It seems innocuous
@@ -1165,7 +1166,7 @@ export type PerseusInteractionGraph = {
1165
1166
  // How many ticks to show on the ruler. e.g. 1, 2, 4, 8, 10, 16
1166
1167
  rulerTicks?: number;
1167
1168
  // This controls the number (and position) of the tick marks for the X and Y axis. e.g. [1, 1]
1168
- tickStep: ReadonlyArray<number>;
1169
+ tickStep: Readonly<[number, number]>;
1169
1170
  };
1170
1171
 
1171
1172
  export type PerseusInteractionElement =
package/src/renderer.tsx CHANGED
@@ -35,7 +35,6 @@ import type {
35
35
  FilterCriterion,
36
36
  FocusPath,
37
37
  LinterContextProps,
38
- PerseusDependencies,
39
38
  PerseusScore,
40
39
  WidgetInfo,
41
40
  WidgetProps,
@@ -223,10 +222,7 @@ class Renderer extends React.Component<Props, State> {
223
222
  // The i18n linter.
224
223
  _translationLinter: TranslationLinter;
225
224
 
226
- // @ts-expect-error [FEI-5003] - TS2564 - Property 'lastRenderedMarkdown' has no initializer and is not definitely assigned in the constructor.
227
- lastRenderedMarkdown: React.ReactElement<
228
- React.ComponentProps<PerseusDependencies["KatexProvider"]>
229
- >;
225
+ lastRenderedMarkdown: React.ReactNode;
230
226
  // @ts-expect-error [FEI-5003] - TS2564 - Property 'reuseMarkdown' has no initializer and is not definitely assigned in the constructor.
231
227
  reuseMarkdown: boolean;
232
228
  // @ts-expect-error [FEI-5003] - TS2564 - Property 'translationIndex' has no initializer and is not definitely assigned in the constructor.
@@ -1848,7 +1844,6 @@ class Renderer extends React.Component<Props, State> {
1848
1844
 
1849
1845
  render(): React.ReactNode {
1850
1846
  const apiOptions = this.getApiOptions();
1851
- const {KatexProvider} = getDependencies();
1852
1847
 
1853
1848
  if (this.reuseMarkdown) {
1854
1849
  return this.lastRenderedMarkdown;
@@ -1896,17 +1891,13 @@ class Renderer extends React.Component<Props, State> {
1896
1891
  // calls its before_dom_insert we can lookup this component by
1897
1892
  // this attribute and render the text with markdown.
1898
1893
  return (
1899
- <KatexProvider>
1900
- <DefinitionProvider>
1901
- <div
1902
- data-perseus-component-index={
1903
- this.translationIndex
1904
- }
1905
- >
1906
- {content}
1907
- </div>
1908
- </DefinitionProvider>
1909
- </KatexProvider>
1894
+ <DefinitionProvider>
1895
+ <div
1896
+ data-perseus-component-index={this.translationIndex}
1897
+ >
1898
+ {content}
1899
+ </div>
1900
+ </DefinitionProvider>
1910
1901
  );
1911
1902
  }
1912
1903
  }
@@ -1963,11 +1954,9 @@ class Renderer extends React.Component<Props, State> {
1963
1954
  });
1964
1955
 
1965
1956
  this.lastRenderedMarkdown = (
1966
- <KatexProvider>
1967
- <DefinitionProvider>
1968
- <div className={className}>{markdownContents}</div>
1969
- </DefinitionProvider>
1970
- </KatexProvider>
1957
+ <DefinitionProvider>
1958
+ <div className={className}>{markdownContents}</div>
1959
+ </DefinitionProvider>
1971
1960
  );
1972
1961
  return this.lastRenderedMarkdown;
1973
1962
  }
package/src/types.ts CHANGED
@@ -1,7 +1,3 @@
1
- // eslint-disable-next-line import/no-unresolved
2
- import katex from "katex";
3
- // eslint-disable-next-line import/no-unresolved
4
- import katexA11y from "katex/dist/contrib/render-a11y-string";
5
1
  import * as React from "react";
6
2
 
7
3
  import type {SerializedHighlightSet} from "./components/highlighting/types";
@@ -309,20 +305,6 @@ export type PerseusDependencies = {
309
305
  graphieMovablesJiptLabels: JiptLabelStore;
310
306
  svgImageJiptLabels: JiptLabelStore;
311
307
  rendererTranslationComponents: JiptTranslationComponents;
312
- // KaTeX related dependencies
313
- getKaTeX: () => Promise<katex>;
314
- getRenderA11yString: () => Promise<katexA11y>;
315
- loadMathjax: () => Promise<unknown>;
316
- logKaTeXError: (
317
- expression: string,
318
- error: Error,
319
- ) => Promise<Response | null | undefined>;
320
- KatexProvider: React.ComponentType<{
321
- children: React.ReactNode;
322
- }>;
323
- // TODO(kevinb): Update `getKaTeX` to return the version of `katex` that
324
- // webapp (or mobile) wants perseus to use.
325
- shouldUseFutureKaTeX: (flag: boolean) => void;
326
308
  TeX: React.ComponentType<TeXProps>;
327
309
  //misc
328
310
  staticUrl: StaticUrlFn;
@@ -1034,7 +1034,7 @@ GraphUtils.createGraphie = function (el: any) {
1034
1034
  * the function at i
1035
1035
  * @param {[]} rangeArray array of ranges over which the
1036
1036
  * corresponding functions are defined
1037
- * @return {Raphael set}
1037
+ * @return {Set<any>} set of paths
1038
1038
  */
1039
1039
  plotPiecewise: function (fnArray, rangeArray) {
1040
1040
  const paths = raphael.set();
@@ -1058,8 +1058,8 @@ GraphUtils.createGraphie = function (el: any) {
1058
1058
  * return a Raphael set of Raphael circle objects at those
1059
1059
  * coordinates
1060
1060
  *
1061
- * @param {Array of arrays} endpointArray
1062
- * @return {Raphael set}
1061
+ * @param {Array<[number, number]>} endpointArray
1062
+ * @return {Set<any>} set of circles
1063
1063
  */
1064
1064
  plotEndpointCircles: function (endpointArray) {
1065
1065
  const circles = raphael.set();
@@ -36,6 +36,8 @@ import KhanMath from "./math";
36
36
 
37
37
  import type {Coord} from "../interactive2/types";
38
38
 
39
+ export type MouseHandler = (position: Coord) => void;
40
+
39
41
  const {getCanUse3dTransform} = InteractiveUtil;
40
42
 
41
43
  function sum(array: any) {
@@ -109,7 +111,15 @@ _.extend(GraphUtils.Graphie.prototype, {
109
111
  // in the way of mouse events. This adds another SVG element on top
110
112
  // of everything else where we can add invisible shapes with mouse
111
113
  // handlers wherever we want.
112
- addMouseLayer: function (options) {
114
+ addMouseLayer: function (options: {
115
+ onClick?: MouseHandler;
116
+ onMouseMove?: MouseHandler;
117
+ onMouseDown?: MouseHandler;
118
+ onMouseOver?: MouseHandler;
119
+ onMouseOut?: MouseHandler;
120
+ allowScratchpad?: boolean;
121
+ setDrawingAreaAvailable?: (available: boolean) => void;
122
+ }) {
113
123
  const graph = this;
114
124
  options = _.extend(
115
125
  {
@@ -149,10 +159,11 @@ _.extend(GraphUtils.Graphie.prototype, {
149
159
  isClickingCanvas = true;
150
160
 
151
161
  if (options.onMouseMove) {
162
+ const handler = options.onMouseMove;
152
163
  $(document).bind("vmousemove.mouseLayer", function (e) {
153
164
  if (isClickingCanvas) {
154
165
  e.preventDefault();
155
- options.onMouseMove(graph.getMouseCoord(e));
166
+ handler(graph.getMouseCoord(e));
156
167
  }
157
168
  });
158
169
  }
@@ -170,18 +181,20 @@ _.extend(GraphUtils.Graphie.prototype, {
170
181
  }
171
182
  });
172
183
  if (options.onMouseOver) {
184
+ const handler = options.onMouseOver;
173
185
  $(graph.mouselayer.canvas).on("vmouseover", function (e) {
174
- options.onMouseOver(graph.getMouseCoord(e));
186
+ handler(graph.getMouseCoord(e));
175
187
  });
176
188
  }
177
189
  if (options.onMouseOut) {
190
+ const handler = options.onMouseOut;
178
191
  $(graph.mouselayer.canvas).on("vmouseout", function (e) {
179
- options.onMouseOut(graph.getMouseCoord(e));
192
+ handler(graph.getMouseCoord(e));
180
193
  });
181
194
  }
182
195
  }
183
196
  if (!options.allowScratchpad) {
184
- options.setDrawingAreaAvailable(false);
197
+ options.setDrawingAreaAvailable?.(false);
185
198
  }
186
199
 
187
200
  // Add mouse and visible wrapper layers for DOM-node-wrapped movables
package/src/util/tex.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import $ from "jquery";
2
+ import * as React from "react";
2
3
 
3
4
  import {getDependencies} from "../dependencies";
4
5
 
5
6
  import KhanMath from "./math";
7
+ import reactRender from "./react-render";
6
8
 
7
9
  declare const MathJax: any;
8
10
 
@@ -94,84 +96,18 @@ export default {
94
96
  // Store the formula that we're using
95
97
  $elem.attr("data-math-formula", text);
96
98
 
97
- const katex = await getDependencies().getKaTeX();
98
- // Try to process the nodes with KaTeX first
99
- try {
100
- // Don't use the `trust: true` setting with KaTeX. There is a
101
- // security issue with it as outlined in https://hackerone.com/reports/844216.
102
- // See https://khanacademy.atlassian.net/browse/FEI-2225 for
103
- // additional context.
104
- katex.render(text, $katexHolder[0], {colorIsTextColor: true});
105
- // If that worked, and we previously formatted with
106
- // mathjax, do some mathjax cleanup
107
- if ($elem.attr("data-math-type") === "mathjax") {
108
- // Remove the old mathjax stuff
109
- if (typeof MathJax !== "undefined") {
110
- const jax = MathJax.Hub.getJaxFor(script);
111
- if (jax) {
112
- const e = jax.SourceElement();
113
- if (
114
- e.previousSibling &&
115
- e.previousSibling.className
116
- ) {
117
- jax.Remove();
118
- }
119
- }
99
+ const {TeX} = await getDependencies();
100
+ // We use createElement instead of JSX here because we can't name this file tex.tsx;
101
+ // that name is already taken.
102
+ reactRender(
103
+ React.createElement(TeX, {children: text}),
104
+ $katexHolder[0],
105
+ () => {
106
+ if (callback) {
107
+ doCallback(elem, callback);
120
108
  }
121
- }
122
- $elem.attr("data-math-type", "katex");
123
- // Call the callback
124
- if (callback) {
125
- doCallback(elem, callback);
126
- }
127
- return;
128
- } catch (err: any) {
129
- getDependencies().logKaTeXError(text, err);
130
-
131
- if (err instanceof katex.ParseError) {
132
- throw err;
133
- }
134
- }
135
-
136
- // Otherwise, fallback to MathJax
137
-
138
- // (Note: we don't need to do any katex cleanup here, because
139
- // KaTeX is smart and cleans itself up)
140
- $elem.attr("data-math-type", "mathjax");
141
- // Update the script tag, or add one if necessary
142
- if (!script) {
143
- $mathjaxHolder.append(
144
- "<script type='math/tex'>" +
145
- text.replace(/<\//g, "< /") +
146
- "</script>",
147
- );
148
- } else {
149
- if ("text" in script) {
150
- // IE8, etc
151
- script.text = text;
152
- } else {
153
- script.textContent = text;
154
- }
155
- }
156
- if (typeof MathJax !== "undefined") {
157
- // Put the process, a debug log, and the callback into the
158
- // MathJax queue
159
- MathJax.Hub.Queue([
160
- "Reprocess",
161
- MathJax.Hub,
162
- $mathjaxHolder[0],
163
- ]);
164
- if (callback) {
165
- MathJax.Hub.Queue(function () {
166
- const cb = MathJax.Callback(function () {});
167
- doCallback(elem, function () {
168
- callback();
169
- cb();
170
- });
171
- return cb;
172
- });
173
- }
174
- }
109
+ },
110
+ );
175
111
  }
176
112
  },
177
113
 
package/src/util.ts CHANGED
@@ -5,6 +5,7 @@ import {Errors} from "./logging/log";
5
5
  import {PerseusError} from "./perseus-error";
6
6
  import KhanAnswerTypes from "./util/answer-types";
7
7
 
8
+ import type {Range} from "./perseus-types";
8
9
  import type {Widget, PerseusScore, KEScore} from "./types";
9
10
 
10
11
  type WordPosition = {
@@ -37,7 +38,7 @@ type QueryParams = {
37
38
  [param: string]: string;
38
39
  };
39
40
 
40
- type Position = {
41
+ export type Position = {
41
42
  top: number;
42
43
  left: number;
43
44
  };
@@ -495,8 +496,6 @@ function tickStepFromNumTicks(span: number, numTicks: number): number {
495
496
  return step;
496
497
  }
497
498
 
498
- type Range = [number, number]; // [min, max]
499
-
500
499
  const constrainTickStep = (step: number, range: Range): number => {
501
500
  const span = range[1] - range[0];
502
501
  const numTicks = span / step;
@@ -519,7 +518,7 @@ const constrainTickStep = (step: number, range: Range): number => {
519
518
  * Specifically, we aim for 10 or fewer ticks per graph axis.
520
519
  */
521
520
  function constrainedTickStepsFromTickSteps(
522
- tickSteps: Coordinates,
521
+ tickSteps: [number, number],
523
522
  ranges: [Range, Range],
524
523
  ): Coordinates {
525
524
  return [
@@ -9,6 +9,6 @@ export default {
9
9
 
10
10
  type StoryArgs = Record<any, any>;
11
11
 
12
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
12
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
13
13
  return <RendererWithDebugUI question={question1} />;
14
14
  };
@@ -9,6 +9,6 @@ export default {
9
9
 
10
10
  type StoryArgs = Record<any, any>;
11
11
 
12
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
12
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
13
13
  return <RendererWithDebugUI question={question1} />;
14
14
  };
@@ -94,18 +94,14 @@ const article = {
94
94
 
95
95
  type StoryArgs = Record<any, any>;
96
96
 
97
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
97
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
98
98
  return <RendererWithDebugUI question={question1} />;
99
99
  };
100
100
 
101
- export const MultipleDefinitions: React.FC<StoryArgs> = (
102
- args,
103
- ): React.ReactElement => {
101
+ export const MultipleDefinitions = (args: StoryArgs): React.ReactElement => {
104
102
  return <RendererWithDebugUI question={question2} />;
105
103
  };
106
104
 
107
- export const ArticleDefintion: React.FC<StoryArgs> = (
108
- args,
109
- ): React.ReactElement => {
105
+ export const ArticleDefintion = (args: StoryArgs): React.ReactElement => {
110
106
  return <ArticleRenderer json={article} useNewStyles />;
111
107
  };
@@ -9,6 +9,6 @@ export default {
9
9
 
10
10
  type StoryArgs = Record<any, any>;
11
11
 
12
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
12
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
13
13
  return <RendererWithDebugUI question={question1} />;
14
14
  };
@@ -9,10 +9,10 @@ export default {
9
9
 
10
10
  type StoryArgs = Record<any, any>;
11
11
 
12
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
12
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
13
13
  return <RendererWithDebugUI question={question1} />;
14
14
  };
15
15
 
16
- export const Question2: React.FC<StoryArgs> = (args): React.ReactElement => {
16
+ export const Question2 = (args: StoryArgs): React.ReactElement => {
17
17
  return <RendererWithDebugUI question={question2} />;
18
18
  };
@@ -45,9 +45,7 @@ const WrappedKeypadContext = (props: WrappedKeypadContextProps) => {
45
45
  );
46
46
  };
47
47
 
48
- export const DesktopKitchenSink: React.FC<StoryArgs> = (
49
- args,
50
- ): React.ReactElement => {
48
+ export const DesktopKitchenSink = (args: StoryArgs): React.ReactElement => {
51
49
  const reviewModeRubric = {
52
50
  functions: ["f", "g", "h"],
53
51
  times: true,
@@ -88,11 +86,11 @@ export const DesktopKitchenSink: React.FC<StoryArgs> = (
88
86
  );
89
87
  };
90
88
 
91
- export const Desktop: React.FC<StoryArgs> = (args): React.ReactElement => {
89
+ export const Desktop = (args: StoryArgs): React.ReactElement => {
92
90
  return <WrappedKeypadContext item={expressionItem3} customKeypad={false} />;
93
91
  };
94
92
 
95
- export const Mobile: React.FC<StoryArgs> = (args): React.ReactElement => {
93
+ export const Mobile = (args: StoryArgs): React.ReactElement => {
96
94
  return (
97
95
  <div>
98
96
  <p>
@@ -107,9 +105,7 @@ export const Mobile: React.FC<StoryArgs> = (args): React.ReactElement => {
107
105
  );
108
106
  };
109
107
 
110
- export const ExpressionItem2: React.FC<StoryArgs> = (
111
- args,
112
- ): React.ReactElement => {
108
+ export const ExpressionItem2 = (args: StoryArgs): React.ReactElement => {
113
109
  return (
114
110
  <WrappedKeypadContext
115
111
  item={expressionItem2}
@@ -118,9 +114,7 @@ export const ExpressionItem2: React.FC<StoryArgs> = (
118
114
  );
119
115
  };
120
116
 
121
- export const ExpressionItem3: React.FC<StoryArgs> = (
122
- args,
123
- ): React.ReactElement => {
117
+ export const ExpressionItem3 = (args: StoryArgs): React.ReactElement => {
124
118
  return (
125
119
  <WrappedKeypadContext
126
120
  item={expressionItem3}
@@ -12,7 +12,7 @@ type GradedGroupSetStory = {
12
12
  args: StoryArgs;
13
13
  };
14
14
 
15
- export const Article1: React.FC<StoryArgs> = (args): React.ReactElement => {
15
+ export const Article1 = (args: StoryArgs): React.ReactElement => {
16
16
  return (
17
17
  <RendererWithDebugUI
18
18
  apiOptions={{
@@ -12,7 +12,7 @@ type Story = {
12
12
  args: StoryArgs;
13
13
  };
14
14
 
15
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
15
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
16
16
  return (
17
17
  <RendererWithDebugUI
18
18
  question={question1}
@@ -17,44 +17,30 @@ export default {
17
17
 
18
18
  type StoryArgs = Record<any, any>;
19
19
 
20
- export const AbsoluteValueQuestion: React.FC<StoryArgs> = (
21
- args,
22
- ): React.ReactElement => {
20
+ export const AbsoluteValueQuestion = (args: StoryArgs): React.ReactElement => {
23
21
  return <RendererWithDebugUI question={absoluteValueQuestion} />;
24
22
  };
25
23
 
26
- export const ExponentialQuestion: React.FC<StoryArgs> = (
27
- args,
28
- ): React.ReactElement => {
24
+ export const ExponentialQuestion = (args: StoryArgs): React.ReactElement => {
29
25
  return <RendererWithDebugUI question={exponentialQuestion} />;
30
26
  };
31
27
 
32
- export const LinearQuestion: React.FC<StoryArgs> = (
33
- args,
34
- ): React.ReactElement => {
28
+ export const LinearQuestion = (args: StoryArgs): React.ReactElement => {
35
29
  return <RendererWithDebugUI question={linearQuestion} />;
36
30
  };
37
31
 
38
- export const LogarithmQuestion: React.FC<StoryArgs> = (
39
- args,
40
- ): React.ReactElement => {
32
+ export const LogarithmQuestion = (args: StoryArgs): React.ReactElement => {
41
33
  return <RendererWithDebugUI question={logarithmQuestion} />;
42
34
  };
43
35
 
44
- export const QuadraticQuestion: React.FC<StoryArgs> = (
45
- args,
46
- ): React.ReactElement => {
36
+ export const QuadraticQuestion = (args: StoryArgs): React.ReactElement => {
47
37
  return <RendererWithDebugUI question={quadraticQuestion} />;
48
38
  };
49
39
 
50
- export const SinusoidQuestion: React.FC<StoryArgs> = (
51
- args,
52
- ): React.ReactElement => {
40
+ export const SinusoidQuestion = (args: StoryArgs): React.ReactElement => {
53
41
  return <RendererWithDebugUI question={sinusoidQuestion} />;
54
42
  };
55
43
 
56
- export const ComplexQuestion: React.FC<StoryArgs> = (
57
- args,
58
- ): React.ReactElement => {
44
+ export const ComplexQuestion = (args: StoryArgs): React.ReactElement => {
59
45
  return <RendererWithDebugUI question={multipleAvailableTypesQuestion} />;
60
46
  };
@@ -9,6 +9,6 @@ export default {
9
9
 
10
10
  type StoryArgs = Record<any, any>;
11
11
 
12
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
12
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
13
13
  return <RendererWithDebugUI question={question1} />;
14
14
  };
@@ -9,6 +9,6 @@ export default {
9
9
 
10
10
  type StoryArgs = Record<any, any>;
11
11
 
12
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
12
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
13
13
  return <RendererWithDebugUI question={question1} />;
14
14
  };
@@ -16,7 +16,7 @@ type ImageStory = {
16
16
  args: StoryArgs;
17
17
  };
18
18
 
19
- export const Question1: React.FC<StoryArgs> = (args): React.ReactElement => {
19
+ export const Question1 = (args: StoryArgs): React.ReactElement => {
20
20
  const apiOptions: APIOptions = {
21
21
  isMobile: args.isMobile,
22
22
  };