@khanacademy/perseus 19.1.5 → 19.1.7

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 (489) hide show
  1. package/dist/components/graph.d.ts +0 -1
  2. package/dist/components/graphie.d.ts +0 -1
  3. package/dist/es/index.js +319 -212
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.js +338 -222
  6. package/dist/index.js.map +1 -1
  7. package/dist/interactive2/movable-point.d.ts +195 -1
  8. package/dist/interactive2/movable.d.ts +1 -1
  9. package/dist/interactive2/types.d.ts +4 -2
  10. package/dist/interactive2.d.ts +2 -1
  11. package/dist/server-item-renderer.d.ts +2 -2
  12. package/dist/util/graphie.d.ts +12 -2
  13. package/dist/widgets/expression.d.ts +6 -6
  14. package/package.json +11 -8
  15. package/.babelrc.js +0 -8
  16. package/.eslintrc.js +0 -12
  17. package/CHANGELOG.md +0 -1432
  18. package/src/__stories__/article-renderer.stories.tsx +0 -100
  19. package/src/__stories__/hints-renderer.stories.tsx +0 -55
  20. package/src/__stories__/server-item-renderer.stories.tsx +0 -44
  21. package/src/__testdata__/article-renderer.testdata.ts +0 -212
  22. package/src/__testdata__/graphie.testdata.ts +0 -51
  23. package/src/__testdata__/renderer.testdata.ts +0 -274
  24. package/src/__testdata__/server-item-renderer.testdata.ts +0 -171
  25. package/src/__tests__/__snapshots__/perseus-markdown.test.ts.snap +0 -507
  26. package/src/__tests__/__snapshots__/renderer.test.tsx.snap +0 -525
  27. package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +0 -285
  28. package/src/__tests__/a11y.test.ts +0 -303
  29. package/src/__tests__/article-renderer.test.tsx +0 -130
  30. package/src/__tests__/error-boundary.test.tsx +0 -76
  31. package/src/__tests__/extract-perseus-data.test.ts +0 -1027
  32. package/src/__tests__/init.test.ts +0 -10
  33. package/src/__tests__/jipt-paragraphs.test.ts +0 -32
  34. package/src/__tests__/mock-asset-loading-widget.tsx +0 -53
  35. package/src/__tests__/mock-widget.tsx +0 -33
  36. package/src/__tests__/perseus-markdown.test.ts +0 -764
  37. package/src/__tests__/renderability.test.ts +0 -480
  38. package/src/__tests__/renderer-api.test.tsx +0 -302
  39. package/src/__tests__/renderer.test.tsx +0 -1816
  40. package/src/__tests__/server-item-renderer.test.tsx +0 -582
  41. package/src/__tests__/test-items/image-item.ts +0 -24
  42. package/src/__tests__/test-items/input-number-1-item.ts +0 -26
  43. package/src/__tests__/test-items/input-number-2-item.ts +0 -38
  44. package/src/__tests__/test-items/table-item.ts +0 -29
  45. package/src/__tests__/tex-wrangler.test.ts +0 -82
  46. package/src/__tests__/util.test.ts +0 -40
  47. package/src/__tests__/widget-container.test.tsx +0 -126
  48. package/src/__tests__/widgets.test.ts +0 -91
  49. package/src/a11y.ts +0 -45
  50. package/src/all-widgets.ts +0 -9
  51. package/src/article-renderer.tsx +0 -237
  52. package/src/asset-context.ts +0 -30
  53. package/src/basic-widgets.ts +0 -16
  54. package/src/components/__stories__/button-group.stories.tsx +0 -55
  55. package/src/components/__stories__/fixed-to-responsive.stories.tsx +0 -141
  56. package/src/components/__stories__/graph.stories.tsx +0 -28
  57. package/src/components/__stories__/graphie.stories.tsx +0 -33
  58. package/src/components/__stories__/hud.stories.tsx +0 -35
  59. package/src/components/__stories__/icon.stories.tsx +0 -63
  60. package/src/components/__stories__/image-loader.stories.tsx +0 -63
  61. package/src/components/__stories__/info-tip.stories.tsx +0 -31
  62. package/src/components/__stories__/inline-icon.stories.tsx +0 -40
  63. package/src/components/__stories__/input-with-examples.stories.tsx +0 -53
  64. package/src/components/__stories__/lint.stories.tsx +0 -86
  65. package/src/components/__stories__/math-input.stories.tsx +0 -43
  66. package/src/components/__stories__/math-output.stories.tsx +0 -23
  67. package/src/components/__stories__/multi-button-group.stories.tsx +0 -66
  68. package/src/components/__stories__/number-input.stories.tsx +0 -41
  69. package/src/components/__stories__/prop-check-box.stories.tsx +0 -65
  70. package/src/components/__stories__/range-input.stories.tsx +0 -29
  71. package/src/components/__stories__/simple-keypad-input.stories.tsx +0 -27
  72. package/src/components/__stories__/sortable.stories.tsx +0 -77
  73. package/src/components/__stories__/stub-tag-editor.stories.tsx +0 -45
  74. package/src/components/__stories__/svg-image.stories.tsx +0 -74
  75. package/src/components/__stories__/tex.stories.tsx +0 -23
  76. package/src/components/__stories__/text-input.stories.tsx +0 -33
  77. package/src/components/__stories__/text-list-editor.stories.tsx +0 -32
  78. package/src/components/__stories__/tooltip.stories.tsx +0 -52
  79. package/src/components/__stories__/zoomable-tex.stories.tsx +0 -41
  80. package/src/components/__stories__/zoomable.stories.tsx +0 -49
  81. package/src/components/__testdata__/sorter.testdata.ts +0 -19
  82. package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +0 -163
  83. package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +0 -265
  84. package/src/components/__tests__/math-input.test.tsx +0 -147
  85. package/src/components/__tests__/number-input.test.tsx +0 -128
  86. package/src/components/__tests__/sortable.test.tsx +0 -269
  87. package/src/components/__tests__/sorter.test.tsx +0 -114
  88. package/src/components/__tests__/zoomable.test.tsx +0 -399
  89. package/src/components/button-group.tsx +0 -130
  90. package/src/components/constants.ts +0 -14
  91. package/src/components/fixed-to-responsive.tsx +0 -169
  92. package/src/components/graph.tsx +0 -444
  93. package/src/components/graphie-classes.ts +0 -153
  94. package/src/components/graphie-movables.ts +0 -338
  95. package/src/components/graphie.tsx +0 -400
  96. package/src/components/highlighting/highlightable-content.tsx +0 -240
  97. package/src/components/highlighting/highlights.ts +0 -207
  98. package/src/components/highlighting/ranges.ts +0 -304
  99. package/src/components/highlighting/types.ts +0 -73
  100. package/src/components/highlighting/ui/highlight-renderer.tsx +0 -172
  101. package/src/components/highlighting/ui/highlight-set-renderer.tsx +0 -185
  102. package/src/components/highlighting/ui/highlight-tooltip.tsx +0 -141
  103. package/src/components/highlighting/ui/highlighting-ui.tsx +0 -143
  104. package/src/components/highlighting/ui/selection-tracker.tsx +0 -186
  105. package/src/components/highlighting/ui/types.ts +0 -21
  106. package/src/components/highlighting/ui/util.ts +0 -165
  107. package/src/components/highlighting/word-indexer.tsx +0 -152
  108. package/src/components/hud.tsx +0 -167
  109. package/src/components/icon.tsx +0 -141
  110. package/src/components/image-loader.tsx +0 -177
  111. package/src/components/info-tip/info-tip.tsx +0 -144
  112. package/src/components/info-tip.tsx +0 -39
  113. package/src/components/inline-icon.tsx +0 -60
  114. package/src/components/input-with-examples.tsx +0 -249
  115. package/src/components/lint.tsx +0 -459
  116. package/src/components/math-input.tsx +0 -474
  117. package/src/components/math-output.tsx +0 -134
  118. package/src/components/multi-button-group.tsx +0 -135
  119. package/src/components/number-input.tsx +0 -249
  120. package/src/components/prop-check-box.tsx +0 -79
  121. package/src/components/range-input.tsx +0 -60
  122. package/src/components/simple-keypad-input.tsx +0 -88
  123. package/src/components/sortable.tsx +0 -958
  124. package/src/components/stub-tag-editor.tsx +0 -53
  125. package/src/components/svg-image.tsx +0 -779
  126. package/src/components/tex.tsx +0 -67
  127. package/src/components/text-input.tsx +0 -129
  128. package/src/components/text-list-editor.tsx +0 -166
  129. package/src/components/tooltip.tsx +0 -410
  130. package/src/components/visibility-observer/__stories__/visibility-observer.stories.tsx +0 -141
  131. package/src/components/visibility-observer/create-visibility-observer.ts +0 -108
  132. package/src/components/visibility-observer/get-scroll-parent.ts +0 -46
  133. package/src/components/visibility-observer/visibility-observer.tsx +0 -124
  134. package/src/components/zoomable-tex.tsx +0 -78
  135. package/src/components/zoomable.tsx +0 -304
  136. package/src/components.ts +0 -15
  137. package/src/definition-context.tsx +0 -59
  138. package/src/dependencies.ts +0 -40
  139. package/src/error-boundary.tsx +0 -70
  140. package/src/extra-widgets.ts +0 -75
  141. package/src/hint-renderer.tsx +0 -151
  142. package/src/hints-renderer.tsx +0 -372
  143. package/src/icon-paths.ts +0 -119
  144. package/src/index.ts +0 -171
  145. package/src/init.ts +0 -56
  146. package/src/interaction-tracker.ts +0 -62
  147. package/src/interactive2/__tests__/movable-mock.ts +0 -55
  148. package/src/interactive2/__tests__/movable-point.test.ts +0 -144
  149. package/src/interactive2/interactive-util.test.ts +0 -93
  150. package/src/interactive2/interactive-util.ts +0 -159
  151. package/src/interactive2/movable-helper-methods.ts +0 -166
  152. package/src/interactive2/movable-line-options.ts +0 -419
  153. package/src/interactive2/movable-line.ts +0 -307
  154. package/src/interactive2/movable-point-options.ts +0 -224
  155. package/src/interactive2/movable-point.tsx +0 -585
  156. package/src/interactive2/movable-polygon-options.ts +0 -389
  157. package/src/interactive2/movable-polygon.ts +0 -360
  158. package/src/interactive2/movable.test.ts +0 -249
  159. package/src/interactive2/movable.ts +0 -437
  160. package/src/interactive2/objective_.ts +0 -79
  161. package/src/interactive2/types.ts +0 -17
  162. package/src/interactive2/wrapped-defaults.ts +0 -87
  163. package/src/interactive2/wrapped-ellipse.ts +0 -94
  164. package/src/interactive2/wrapped-line.ts +0 -116
  165. package/src/interactive2/wrapped-path.ts +0 -51
  166. package/src/interactive2.ts +0 -70
  167. package/src/item-version.ts +0 -10
  168. package/src/jipt-paragraphs.ts +0 -49
  169. package/src/jquery.mobile.vmouse.js +0 -545
  170. package/src/loading-context.ts +0 -21
  171. package/src/logging/log.test.ts +0 -39
  172. package/src/logging/log.ts +0 -97
  173. package/src/mixins/__tests__/widget-prop-denylist.test.ts +0 -21
  174. package/src/mixins/changeable.ts +0 -133
  175. package/src/mixins/editor-jsonify.ts +0 -13
  176. package/src/mixins/widget-jsonify-deprecated.ts +0 -23
  177. package/src/mixins/widget-prop-denylist.ts +0 -48
  178. package/src/multi-items/__stories__/multi-renderer.stories.tsx +0 -83
  179. package/src/multi-items/__testdata__/multi-renderer.testdata.ts +0 -172
  180. package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +0 -1164
  181. package/src/multi-items/__tests__/items.test.ts +0 -240
  182. package/src/multi-items/__tests__/multi-renderer.test.tsx +0 -914
  183. package/src/multi-items/__tests__/prop-type-builders.test.ts +0 -133
  184. package/src/multi-items/__tests__/shapes.test.ts +0 -43
  185. package/src/multi-items/__tests__/trees.test.ts +0 -317
  186. package/src/multi-items/item-types.ts +0 -56
  187. package/src/multi-items/items.ts +0 -176
  188. package/src/multi-items/multi-renderer.tsx +0 -569
  189. package/src/multi-items/prop-type-builders.ts +0 -106
  190. package/src/multi-items/shape-types.ts +0 -52
  191. package/src/multi-items/shapes.ts +0 -52
  192. package/src/multi-items/tree-types.ts +0 -47
  193. package/src/multi-items/trees.ts +0 -360
  194. package/src/multi-items.ts +0 -75
  195. package/src/perseus-api.tsx +0 -188
  196. package/src/perseus-env.ts +0 -27
  197. package/src/perseus-error.ts +0 -17
  198. package/src/perseus-markdown.tsx +0 -405
  199. package/src/perseus-types.ts +0 -1366
  200. package/src/perseus-version.ts +0 -9
  201. package/src/question-paragraph.tsx +0 -34
  202. package/src/renderability.ts +0 -109
  203. package/src/renderer.tsx +0 -2000
  204. package/src/server-item-renderer.tsx +0 -495
  205. package/src/sigfigs.ts +0 -490
  206. package/src/styles/articles.less +0 -749
  207. package/src/styles/constants.ts +0 -94
  208. package/src/styles/global-constants.ts +0 -343
  209. package/src/styles/global-styles.ts +0 -306
  210. package/src/styles/khan-exercise.css +0 -1468
  211. package/src/styles/media-queries.ts +0 -47
  212. package/src/styles/perseus-renderer.less +0 -732
  213. package/src/styles/shared.ts +0 -130
  214. package/src/styles/util.less +0 -47
  215. package/src/styles/variables.boostrap.less +0 -277
  216. package/src/styles/variables.less +0 -56
  217. package/src/styles/variables.shared.less +0 -340
  218. package/src/styles/widgets/categorizer.less +0 -38
  219. package/src/styles/widgets/dropdown.less +0 -3
  220. package/src/styles/widgets/expression.less +0 -65
  221. package/src/styles/widgets/graded-group.less +0 -36
  222. package/src/styles/widgets/grapher.less +0 -12
  223. package/src/styles/widgets/group.less +0 -19
  224. package/src/styles/widgets/image.less +0 -54
  225. package/src/styles/widgets/interactive-graph.less +0 -64
  226. package/src/styles/widgets/label-image.less +0 -57
  227. package/src/styles/widgets/matcher.less +0 -8
  228. package/src/styles/widgets/matrix.less +0 -126
  229. package/src/styles/widgets/measurer.less +0 -20
  230. package/src/styles/widgets/orderer.less +0 -98
  231. package/src/styles/widgets/passage.less +0 -154
  232. package/src/styles/widgets/plotter.less +0 -31
  233. package/src/styles/widgets/radio.less +0 -58
  234. package/src/styles/widgets/reaction-diagram.less +0 -35
  235. package/src/styles/widgets/sequence.less +0 -5
  236. package/src/styles/widgets/sortable.less +0 -113
  237. package/src/styles/widgets/table.less +0 -57
  238. package/src/styles/widgets/unit.less +0 -15
  239. package/src/tex-wrangler.ts +0 -182
  240. package/src/translation-linter.ts +0 -126
  241. package/src/traversal.ts +0 -138
  242. package/src/types.ts +0 -513
  243. package/src/util/a11y.ts +0 -23
  244. package/src/util/answer-types.test.ts +0 -114
  245. package/src/util/answer-types.ts +0 -876
  246. package/src/util/colors.ts +0 -93
  247. package/src/util/drawing-transform.test.ts +0 -67
  248. package/src/util/drawing-transform.ts +0 -102
  249. package/src/util/extract-perseus-data.ts +0 -539
  250. package/src/util/fix-passage-refs.ts +0 -121
  251. package/src/util/geometry.test.ts +0 -75
  252. package/src/util/geometry.ts +0 -312
  253. package/src/util/graph-bounds.ts +0 -23
  254. package/src/util/graph-utils.ts +0 -15
  255. package/src/util/graphie.test.ts +0 -1277
  256. package/src/util/graphie.ts +0 -1576
  257. package/src/util/interactive.ts +0 -4174
  258. package/src/util/interval.ts +0 -4
  259. package/src/util/katex-preprocess.ts +0 -14
  260. package/src/util/math.test.ts +0 -11
  261. package/src/util/math.ts +0 -294
  262. package/src/util/mobile-native-utils.test.ts +0 -22
  263. package/src/util/mobile-native-utils.ts +0 -12
  264. package/src/util/parse-perseus-json.test.ts +0 -10
  265. package/src/util/parse-perseus-json.ts +0 -13
  266. package/src/util/react-render.tsx +0 -27
  267. package/src/util/register-all-widgets-for-testing.ts +0 -13
  268. package/src/util/scroll-utils.ts +0 -155
  269. package/src/util/sizing-utils.ts +0 -46
  270. package/src/util/tex.ts +0 -73
  271. package/src/util/url-utils.ts +0 -34
  272. package/src/util.graphie.test.ts +0 -45
  273. package/src/util.graphie.ts +0 -59
  274. package/src/util.ts +0 -966
  275. package/src/version.ts +0 -10
  276. package/src/widget-container.tsx +0 -199
  277. package/src/widgets/__stories__/categorizer.stories.tsx +0 -14
  278. package/src/widgets/__stories__/cs-program.stories.tsx +0 -14
  279. package/src/widgets/__stories__/definition.stories.tsx +0 -114
  280. package/src/widgets/__stories__/dropdown.stories.tsx +0 -14
  281. package/src/widgets/__stories__/explanation.stories.tsx +0 -18
  282. package/src/widgets/__stories__/expression.stories.tsx +0 -145
  283. package/src/widgets/__stories__/graded-group-set.stories.tsx +0 -31
  284. package/src/widgets/__stories__/graded-group.stories.tsx +0 -31
  285. package/src/widgets/__stories__/grapher.stories.tsx +0 -46
  286. package/src/widgets/__stories__/group.stories.tsx +0 -14
  287. package/src/widgets/__stories__/iframe.stories.tsx +0 -14
  288. package/src/widgets/__stories__/image.stories.tsx +0 -85
  289. package/src/widgets/__stories__/input-number.stories.tsx +0 -101
  290. package/src/widgets/__stories__/interaction.stories.tsx +0 -14
  291. package/src/widgets/__stories__/interactive-graph.stories.tsx +0 -60
  292. package/src/widgets/__stories__/label-image.stories.tsx +0 -130
  293. package/src/widgets/__stories__/matcher.stories.tsx +0 -14
  294. package/src/widgets/__stories__/matrix.stories.tsx +0 -14
  295. package/src/widgets/__stories__/number-line.stories.tsx +0 -14
  296. package/src/widgets/__stories__/numeric-input.stories.tsx +0 -105
  297. package/src/widgets/__stories__/orderer.stories.tsx +0 -18
  298. package/src/widgets/__stories__/passage-ref.stories.tsx +0 -33
  299. package/src/widgets/__stories__/passage.stories.tsx +0 -39
  300. package/src/widgets/__stories__/plotter.stories.tsx +0 -27
  301. package/src/widgets/__stories__/radio.stories.tsx +0 -86
  302. package/src/widgets/__stories__/random-widgets.stories.tsx +0 -59
  303. package/src/widgets/__stories__/sorter.stories.tsx +0 -14
  304. package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +0 -66
  305. package/src/widgets/__stories__/unit.stories.tsx +0 -28
  306. package/src/widgets/__stories__/video-transcript-link.stories.tsx +0 -23
  307. package/src/widgets/__stories__/video.stories.tsx +0 -22
  308. package/src/widgets/__testdata__/base-radio.testdata.ts +0 -21
  309. package/src/widgets/__testdata__/categorizer.testdata.ts +0 -89
  310. package/src/widgets/__testdata__/cs-program.testdata.ts +0 -27
  311. package/src/widgets/__testdata__/dropdown.testdata.ts +0 -71
  312. package/src/widgets/__testdata__/explanation.testdata.ts +0 -85
  313. package/src/widgets/__testdata__/expression.testdata.ts +0 -198
  314. package/src/widgets/__testdata__/graded-group-set.testdata.ts +0 -356
  315. package/src/widgets/__testdata__/graded-group.testdata.ts +0 -77
  316. package/src/widgets/__testdata__/grapher.testdata.ts +0 -374
  317. package/src/widgets/__testdata__/group.testdata.ts +0 -153
  318. package/src/widgets/__testdata__/iframe.testdata.ts +0 -35
  319. package/src/widgets/__testdata__/image.testdata.ts +0 -36
  320. package/src/widgets/__testdata__/input-number.testdata.ts +0 -72
  321. package/src/widgets/__testdata__/interaction.testdata.ts +0 -262
  322. package/src/widgets/__testdata__/interactive-graph-random.testdata.ts +0 -269
  323. package/src/widgets/__testdata__/interactive-graph.testdata.ts +0 -644
  324. package/src/widgets/__testdata__/label-image.testdata.ts +0 -308
  325. package/src/widgets/__testdata__/matcher.testdata.ts +0 -33
  326. package/src/widgets/__testdata__/matrix.testdata.ts +0 -28
  327. package/src/widgets/__testdata__/number-line.testdata.ts +0 -30
  328. package/src/widgets/__testdata__/numeric-input.testdata.ts +0 -265
  329. package/src/widgets/__testdata__/orderer.testdata.ts +0 -123
  330. package/src/widgets/__testdata__/passage-ref.testdata.ts +0 -101
  331. package/src/widgets/__testdata__/passage.testdata.ts +0 -95
  332. package/src/widgets/__testdata__/plotter.testdata.ts +0 -36
  333. package/src/widgets/__testdata__/radio.testdata.ts +0 -324
  334. package/src/widgets/__testdata__/randomizers.ts +0 -51
  335. package/src/widgets/__testdata__/sorter.testdata.ts +0 -19
  336. package/src/widgets/__testdata__/video.testdata.ts +0 -61
  337. package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +0 -940
  338. package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +0 -67
  339. package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +0 -97
  340. package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +0 -133
  341. package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +0 -425
  342. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +0 -729
  343. package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +0 -339
  344. package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +0 -801
  345. package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +0 -2673
  346. package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +0 -1211
  347. package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +0 -61
  348. package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +0 -378
  349. package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +0 -495
  350. package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +0 -292
  351. package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +0 -2889
  352. package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +0 -883
  353. package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +0 -514
  354. package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +0 -814
  355. package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +0 -470
  356. package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +0 -243
  357. package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +0 -434
  358. package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +0 -1956
  359. package/src/widgets/__tests__/__snapshots__/plotter.test.tsx.snap +0 -827
  360. package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +0 -4237
  361. package/src/widgets/__tests__/__snapshots__/unit.test.tsx.snap +0 -20
  362. package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +0 -153
  363. package/src/widgets/__tests__/categorizer.test.ts +0 -203
  364. package/src/widgets/__tests__/cs-program.test.ts +0 -43
  365. package/src/widgets/__tests__/definition.test.ts +0 -136
  366. package/src/widgets/__tests__/dropdown.test.ts +0 -105
  367. package/src/widgets/__tests__/explanation.test.ts +0 -198
  368. package/src/widgets/__tests__/expression-mobile.test.tsx +0 -363
  369. package/src/widgets/__tests__/expression.test.tsx +0 -484
  370. package/src/widgets/__tests__/graded-group-set-jipt.test.ts +0 -30
  371. package/src/widgets/__tests__/graded-group-set.test.ts +0 -288
  372. package/src/widgets/__tests__/graded-group.test.ts +0 -232
  373. package/src/widgets/__tests__/grapher.cypress.ts +0 -576
  374. package/src/widgets/__tests__/grapher.test.ts +0 -33
  375. package/src/widgets/__tests__/group.test.tsx +0 -510
  376. package/src/widgets/__tests__/iframe.test.ts +0 -45
  377. package/src/widgets/__tests__/image.test.ts +0 -62
  378. package/src/widgets/__tests__/input-number.test.ts +0 -354
  379. package/src/widgets/__tests__/interaction.test.ts +0 -31
  380. package/src/widgets/__tests__/interactive-graph.cypress.ts +0 -815
  381. package/src/widgets/__tests__/interactive-graph.test.ts +0 -106
  382. package/src/widgets/__tests__/matcher.test.tsx +0 -176
  383. package/src/widgets/__tests__/matrix.test.ts +0 -82
  384. package/src/widgets/__tests__/number-line.test.ts +0 -79
  385. package/src/widgets/__tests__/numeric-input.test.ts +0 -575
  386. package/src/widgets/__tests__/orderer.test.ts +0 -73
  387. package/src/widgets/__tests__/passage-ref.test.ts +0 -168
  388. package/src/widgets/__tests__/passage.test.tsx +0 -224
  389. package/src/widgets/__tests__/plotter.test.tsx +0 -69
  390. package/src/widgets/__tests__/radio/base-radio.test.tsx +0 -470
  391. package/src/widgets/__tests__/radio/choice-icon.test.tsx +0 -90
  392. package/src/widgets/__tests__/radio/choice.test.tsx +0 -310
  393. package/src/widgets/__tests__/radio/focus-ring.test.tsx +0 -22
  394. package/src/widgets/__tests__/radio/option-status.test.tsx +0 -77
  395. package/src/widgets/__tests__/radio.test.ts +0 -807
  396. package/src/widgets/__tests__/randomizers.test.ts +0 -53
  397. package/src/widgets/__tests__/renderQuestion.tsx +0 -101
  398. package/src/widgets/__tests__/unit.test.tsx +0 -168
  399. package/src/widgets/__tests__/video.test.ts +0 -69
  400. package/src/widgets/categorizer.tsx +0 -344
  401. package/src/widgets/cs-program.tsx +0 -227
  402. package/src/widgets/definition.tsx +0 -121
  403. package/src/widgets/deprecated-standin/__stories__/deprecated-standin.stories.tsx +0 -30
  404. package/src/widgets/deprecated-standin/__tests__/__snapshots__/deprecated-standin.test.ts.snap +0 -70
  405. package/src/widgets/deprecated-standin/__tests__/deprecated-standin.test.ts +0 -93
  406. package/src/widgets/deprecated-standin/index.tsx +0 -58
  407. package/src/widgets/dropdown.tsx +0 -142
  408. package/src/widgets/explanation.tsx +0 -317
  409. package/src/widgets/expression.tsx +0 -707
  410. package/src/widgets/graded-group-answer-bar.tsx +0 -142
  411. package/src/widgets/graded-group-set.tsx +0 -338
  412. package/src/widgets/graded-group.tsx +0 -471
  413. package/src/widgets/grapher/util.tsx +0 -799
  414. package/src/widgets/grapher.tsx +0 -660
  415. package/src/widgets/group.tsx +0 -195
  416. package/src/widgets/iframe.tsx +0 -195
  417. package/src/widgets/image.tsx +0 -312
  418. package/src/widgets/input-number.tsx +0 -412
  419. package/src/widgets/interaction/arrow-picker.tsx +0 -38
  420. package/src/widgets/interaction/color-picker.tsx +0 -69
  421. package/src/widgets/interaction/dash-picker.tsx +0 -45
  422. package/src/widgets/interaction/element-container.tsx +0 -100
  423. package/src/widgets/interaction.tsx +0 -826
  424. package/src/widgets/interactive-graph.tsx +0 -2597
  425. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -91
  426. package/src/widgets/label-image/__stories__/answer-pill.stories.tsx +0 -62
  427. package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -171
  428. package/src/widgets/label-image/__tests__/answer-pill.test.tsx +0 -75
  429. package/src/widgets/label-image/__tests__/hide-answers-toggle.test.tsx +0 -39
  430. package/src/widgets/label-image/answer-choices.tsx +0 -88
  431. package/src/widgets/label-image/answer-pill.tsx +0 -103
  432. package/src/widgets/label-image/hide-answers-toggle.tsx +0 -40
  433. package/src/widgets/label-image/marker.tsx +0 -268
  434. package/src/widgets/label-image/strings.ts +0 -5
  435. package/src/widgets/label-image/types.ts +0 -27
  436. package/src/widgets/label-image.test.ts +0 -928
  437. package/src/widgets/label-image.tsx +0 -819
  438. package/src/widgets/lights-puzzle.tsx +0 -359
  439. package/src/widgets/matcher.tsx +0 -298
  440. package/src/widgets/matrix.tsx +0 -634
  441. package/src/widgets/measurer.tsx +0 -222
  442. package/src/widgets/molecule/__tests__/layout.test.ts +0 -162
  443. package/src/widgets/molecule/__tests__/parser.test.ts +0 -155
  444. package/src/widgets/molecule/molecule-drawing.ts +0 -173
  445. package/src/widgets/molecule/molecule-layout.ts +0 -362
  446. package/src/widgets/molecule/smiles-parser.ts +0 -296
  447. package/src/widgets/molecule.tsx +0 -172
  448. package/src/widgets/number-line.tsx +0 -862
  449. package/src/widgets/numeric-input.tsx +0 -576
  450. package/src/widgets/orderer.tsx +0 -786
  451. package/src/widgets/passage/__tests__/passage-markdown.test.ts +0 -376
  452. package/src/widgets/passage/passage-markdown.tsx +0 -475
  453. package/src/widgets/passage-ref-target.tsx +0 -76
  454. package/src/widgets/passage-ref.tsx +0 -213
  455. package/src/widgets/passage.tsx +0 -582
  456. package/src/widgets/plotter.tsx +0 -1194
  457. package/src/widgets/radio/__stories__/base-radio.stories.tsx +0 -196
  458. package/src/widgets/radio/__stories__/choice-icon.stories.tsx +0 -166
  459. package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +0 -40
  460. package/src/widgets/radio/__stories__/choice.stories.tsx +0 -137
  461. package/src/widgets/radio/__stories__/focus-ring.stories.tsx +0 -43
  462. package/src/widgets/radio/__stories__/option-status.stories.tsx +0 -103
  463. package/src/widgets/radio/base-radio.tsx +0 -511
  464. package/src/widgets/radio/choice-a11y-text.ts +0 -61
  465. package/src/widgets/radio/choice-icon/choice-icon.tsx +0 -218
  466. package/src/widgets/radio/choice-icon/cross-out-line.tsx +0 -51
  467. package/src/widgets/radio/choice-icon/shared-styles.ts +0 -15
  468. package/src/widgets/radio/choice-none-above.tsx +0 -56
  469. package/src/widgets/radio/choice.jsx.fixture.ts +0 -45
  470. package/src/widgets/radio/choice.tsx +0 -359
  471. package/src/widgets/radio/focus-ring.tsx +0 -57
  472. package/src/widgets/radio/option-status.tsx +0 -98
  473. package/src/widgets/radio/util.test.ts +0 -18
  474. package/src/widgets/radio/util.ts +0 -31
  475. package/src/widgets/radio/widget.tsx +0 -520
  476. package/src/widgets/radio.ts +0 -157
  477. package/src/widgets/reaction-diagram.tsx +0 -144
  478. package/src/widgets/sequence.tsx +0 -142
  479. package/src/widgets/simulator.tsx +0 -829
  480. package/src/widgets/sorter.tsx +0 -155
  481. package/src/widgets/table.tsx +0 -393
  482. package/src/widgets/unit.tsx +0 -374
  483. package/src/widgets/video-transcript-link.test.tsx +0 -213
  484. package/src/widgets/video-transcript-link.tsx +0 -84
  485. package/src/widgets/video.tsx +0 -135
  486. package/src/widgets.ts +0 -489
  487. package/src/zoom.ts +0 -555
  488. package/tsconfig-build.json +0 -26
  489. package/tsconfig-build.tsbuildinfo +0 -1
@@ -1,707 +0,0 @@
1
- import * as KAS from "@khanacademy/kas";
2
- import {KeyArray, KeypadInput, KeypadType} from "@khanacademy/math-input";
3
- import {linterContextDefault} from "@khanacademy/perseus-linter";
4
- import {View} from "@khanacademy/wonder-blocks-core";
5
- import * as i18n from "@khanacademy/wonder-blocks-i18n";
6
- import Tooltip from "@khanacademy/wonder-blocks-tooltip";
7
- import classNames from "classnames";
8
- import * as React from "react";
9
- import _ from "underscore";
10
-
11
- import MathInput from "../components/math-input";
12
- import {useDependencies} from "../dependencies";
13
- import {Errors as PerseusErrors, Log} from "../logging/log";
14
- import * as Changeable from "../mixins/changeable";
15
- import {ApiOptions, ClassNames as ApiClassNames} from "../perseus-api";
16
- import a11y from "../util/a11y";
17
- import KhanAnswerTypes from "../util/answer-types";
18
-
19
- import type {DependenciesContext} from "../dependencies";
20
- import type {
21
- PerseusExpressionWidgetOptions,
22
- PerseusExpressionAnswerForm,
23
- } from "../perseus-types";
24
- import type {
25
- APIOptions,
26
- PerseusScore,
27
- WidgetExports,
28
- WidgetProps,
29
- } from "../types";
30
- import type {Keys as Key, KeypadConfiguration} from "@khanacademy/math-input";
31
- import type {PropsFor} from "@khanacademy/wonder-blocks-core";
32
-
33
- type InputPath = ReadonlyArray<string>;
34
-
35
- const ERROR_TITLE = i18n._("Oops!");
36
- const ERROR_MESSAGE = i18n._("Sorry, I don't understand that!");
37
-
38
- const anglicizeOperators = (tex: string): string => {
39
- // sen is used instead of sin in some languages, e.g. Portuguese.
40
- // To ensure that answers in various languages are graded correctly, we
41
- // convert operators to their Englishy forms.
42
- return tex.replace(/\\operatorname{sen}/g, "\\sin ");
43
- };
44
-
45
- const normalizeTex = (tex: string): string => {
46
- return anglicizeOperators(tex);
47
- };
48
-
49
- const deriveKeypadVersion = (apiOptions: APIOptions) => {
50
- // We can derive which version of the keypad is in use. This is
51
- // a bit tricky, but this code will be relatively short-lived
52
- // as we coalesce onto the new, v2 Keypad, at which point we
53
- // can remove this `virtualKeypadVersion` field entirely.
54
- return apiOptions.nativeKeypadProxy != null
55
- ? "REACT_NATIVE_KEYPAD"
56
- : "MATH_INPUT_KEYPAD_V2";
57
- };
58
-
59
- type Rubric = PerseusExpressionWidgetOptions;
60
-
61
- type RenderProps = {
62
- buttonSets: PerseusExpressionWidgetOptions["buttonSets"];
63
- buttonsVisible?: PerseusExpressionWidgetOptions["buttonsVisible"];
64
- functions: PerseusExpressionWidgetOptions["functions"];
65
- times: PerseusExpressionWidgetOptions["times"];
66
- keypadConfiguration: ReturnType<typeof keypadConfigurationForProps>;
67
- };
68
-
69
- type ExternalProps = WidgetProps<RenderProps, Rubric>;
70
-
71
- export type Props = ExternalProps &
72
- Partial<React.ContextType<typeof DependenciesContext>> & {
73
- apiOptions: NonNullable<ExternalProps["apiOptions"]>;
74
- buttonSets: NonNullable<ExternalProps["buttonSets"]>;
75
- functions: NonNullable<ExternalProps["functions"]>;
76
- linterContext: NonNullable<ExternalProps["linterContext"]>;
77
- onBlur: NonNullable<ExternalProps["onBlur"]>;
78
- onFocus: NonNullable<ExternalProps["onFocus"]>;
79
- times: NonNullable<ExternalProps["times"]>;
80
- value: string;
81
- };
82
-
83
- export type ExpressionState = {
84
- invalid: boolean;
85
- showErrorTooltip: boolean;
86
- showErrorStyle: boolean;
87
- };
88
-
89
- type DefaultProps = {
90
- apiOptions: Props["apiOptions"];
91
- buttonSets: Props["buttonSets"];
92
- functions: Props["functions"];
93
- linterContext: Props["linterContext"];
94
- onBlur: Props["onBlur"];
95
- onFocus: Props["onFocus"];
96
- times: Props["times"];
97
- value: Props["value"];
98
- };
99
-
100
- type OnInputErrorFunctionType = (
101
- arg1?: any,
102
- arg2?: any,
103
- arg3?: any,
104
- ) => boolean | null | undefined;
105
-
106
- // The new, MathQuill input expression widget
107
- export class Expression extends React.Component<Props, ExpressionState> {
108
- _isMounted = false;
109
-
110
- //#region Previously a class extension
111
- /* Content creators input a list of answers which are matched from top to
112
- * bottom. The intent is that they can include spcific solutions which should
113
- * be graded as correct or incorrect (or ungraded!) first, then get more
114
- * general.
115
- *
116
- * We iterate through each answer, trying to match it with the user's input
117
- * using the following angorithm:
118
- * - Try to parse the user's input. If it doesn't parse then return "not
119
- * graded".
120
- * - For each answer:
121
- * ~ Try to validate the user's input against the answer. The answer is
122
- * expected to parse.
123
- * ~ If the user's input validates (the validator judges it "correct"), we've
124
- * matched and can stop considering answers.
125
- * - If there were no matches or the matching answer is considered "ungraded",
126
- * show the user an error. TODO(joel) - what error?
127
- * - Otherwise, pass through the resulting points and message.
128
- */
129
- static validate(
130
- userInput: string,
131
- rubric: Rubric,
132
- // @ts-expect-error - TS2322 - Type '() => void' is not assignable to type 'OnInputErrorFunctionType'.
133
- onInputError: OnInputErrorFunctionType = function () {},
134
- ): PerseusScore {
135
- const options = _.clone(rubric);
136
- _.extend(options, {
137
- decimal_separator: i18n.getDecimalSeparator(),
138
- });
139
-
140
- const createValidator = (answer: PerseusExpressionAnswerForm) => {
141
- // We give options to KAS.parse here because it is parsing the
142
- // solution answer, not the student answer, and we don't want a
143
- // solution to work if the student is using a different language
144
- // (different from the content creation language, ie. English).
145
- const expression = KAS.parse(answer.value, rubric);
146
- // An answer may not be parsed if the expression was defined
147
- // incorrectly. For example if the answer is using a symbol defined
148
- // in the function variables list for the expression.
149
- if (!expression.parsed) {
150
- /* c8 ignore next */
151
- Log.error(
152
- "Unable to parse solution answer for expression",
153
- PerseusErrors.InvalidInput,
154
- {loggedMetadata: {rubric: JSON.stringify(rubric)}},
155
- );
156
- return null;
157
- }
158
- return KhanAnswerTypes.expression.createValidatorFunctional(
159
- expression.expr,
160
- _({}).extend(options, {
161
- simplify: answer.simplify,
162
- form: answer.form,
163
- }),
164
- );
165
- };
166
-
167
- // Find the first answer form that matches the user's input and that
168
- // is considered correct. Also, track whether the input is
169
- // considered "empty" for all answer forms, and keep the validation
170
- // result for the first answer form for which the user's input was
171
- // considered "ungraded".
172
- // (Terminology reminder: the answer forms are provided by the
173
- // assessment items; they are not the user's input. Each one might
174
- // represent a correct answer, an incorrect one (if the exercise
175
- // creator has predicted certain common wrong answers and wants to
176
- // provide guidance via a message), or an ungraded one (same idea,
177
- // but without giving the user an incorrect mark for the question).
178
- let matchingAnswerForm;
179
- let matchMessage;
180
- let allEmpty = true;
181
- let firstUngradedResult;
182
- for (const answerForm of rubric.answerForms || []) {
183
- const validate = createValidator(answerForm);
184
- if (!validate) {
185
- continue;
186
- }
187
-
188
- const result = validate(userInput);
189
-
190
- // Short-circuit as soon as the user's input matches some answer
191
- // (independently of whether the answer is correct)
192
- if (result.correct) {
193
- matchingAnswerForm = answerForm;
194
- matchMessage = result.message || "";
195
- break;
196
- }
197
-
198
- allEmpty = allEmpty && result.empty;
199
- // If this answer form is correct and the user's input is considered
200
- // "ungraded" for it, we'll want to keep the evaluation result for
201
- // later. If the user's input doesn't match any answer forms, we'll
202
- // show the message from this validation.
203
- if (
204
- answerForm.considered === "correct" &&
205
- result.ungraded &&
206
- !firstUngradedResult
207
- ) {
208
- firstUngradedResult = result;
209
- }
210
- }
211
-
212
- // Now check to see if we matched any answer form at all, and if
213
- // we did, whether it's considered correct, incorrect, or ungraded
214
- if (!matchingAnswerForm) {
215
- if (firstUngradedResult) {
216
- // While we didn't directly match with any answer form, we
217
- // did at some point get an "ungraded" validation result,
218
- // which might indicate e.g. a mismatch in variable casing.
219
- // We'll return "invalid", which will let the user try again
220
- // with no penalty, and the hopefully helpful validation
221
- // message.
222
- return {
223
- type: "invalid",
224
- message: firstUngradedResult.message,
225
- suppressAlmostThere:
226
- firstUngradedResult.suppressAlmostThere,
227
- };
228
- }
229
- if (allEmpty) {
230
- // If everything graded as empty, it's invalid.
231
- return {
232
- type: "invalid",
233
- message: null,
234
- };
235
- }
236
- // We fell through all the possibilities and we're not empty,
237
- // so the answer is considered incorrect.
238
- return {
239
- type: "points",
240
- earned: 0,
241
- total: 1,
242
- };
243
- }
244
- if (matchingAnswerForm.considered === "ungraded") {
245
- // We matched an ungraded answer form - return "invalid", which
246
- // will let the user try again with no penalty
247
- const apiResult = onInputError(
248
- null, // Reserved for some widget identifier
249
- userInput,
250
- matchMessage,
251
- );
252
- return {
253
- type: "invalid",
254
- message: apiResult === false ? null : matchMessage,
255
- };
256
- }
257
- // We matched a graded answer form, so we can now tell the user
258
- // whether their input was correct or incorrect, and hand out
259
- // points accordingly
260
- // TODO(eater): Seems silly to translate result to this
261
- // invalid/points thing and immediately translate it back in
262
- // ItemRenderer.scoreInput()
263
- return {
264
- type: "points",
265
- earned: matchingAnswerForm.considered === "correct" ? 1 : 0,
266
- total: 1,
267
- message: matchMessage,
268
- };
269
- }
270
-
271
- static getUserInputFromProps(props: Props): string {
272
- return normalizeTex(props.value);
273
- }
274
-
275
- static getOneCorrectAnswerFromRubric(
276
- rubric: Rubric,
277
- ): string | null | undefined {
278
- const correctAnswers = (rubric.answerForms || []).filter(
279
- (answerForm) => answerForm.considered === "correct",
280
- );
281
- if (correctAnswers.length === 0) {
282
- return;
283
- }
284
- return correctAnswers[0].value;
285
- }
286
- //#endregion
287
-
288
- static defaultProps: DefaultProps = {
289
- value: "",
290
- times: false,
291
- functions: [],
292
- buttonSets: ["basic", "trig", "prealgebra", "logarithms"],
293
- onFocus: () => {},
294
- onBlur: () => {},
295
- apiOptions: ApiOptions.defaults,
296
- linterContext: linterContextDefault,
297
- };
298
-
299
- displayName = "Expression";
300
-
301
- state: ExpressionState = {
302
- invalid: false,
303
- showErrorTooltip: false,
304
- showErrorStyle: false,
305
- };
306
-
307
- componentDidMount: () => void = () => {
308
- document.addEventListener("mousedown", this._handleMouseDown);
309
-
310
- // TODO(scottgrant): This is a hack to remove the deprecated call to
311
- // this.isMounted() but is still considered an anti-pattern.
312
- this._isMounted = true;
313
- };
314
-
315
- // Whenever the input value changes, attempt to parse it.
316
- //
317
- // Clear any errors if this parse succeeds, show an error within a second
318
- // if it fails.
319
- componentDidUpdate: (prevProps: Props) => void = (prevProps) => {
320
- if (
321
- !_.isEqual(this.props.value, prevProps.value) ||
322
- !_.isEqual(this.props.functions, prevProps.functions)
323
- ) {
324
- this.setState({
325
- invalid: false,
326
- showErrorTooltip: false,
327
- showErrorStyle: false,
328
- });
329
- if (!this.parse(this.props.value, this.props).parsed) {
330
- const apiResult = this.props.apiOptions.onInputError(
331
- null, // reserved for some widget identifier
332
- this.props.value,
333
- ERROR_MESSAGE,
334
- );
335
- if (apiResult !== false) {
336
- this.setState({
337
- invalid: true,
338
- });
339
- }
340
- }
341
- }
342
- };
343
-
344
- componentWillUnmount: () => void = () => {
345
- this._isMounted = false;
346
- };
347
-
348
- _handleMouseDown = () => {
349
- if (this._isMounted && this.state.showErrorTooltip) {
350
- this.setState({
351
- showErrorTooltip: false,
352
- });
353
- }
354
- };
355
-
356
- simpleValidate: (
357
- rubric: Rubric & {scoring?: boolean},
358
- onInputError: OnInputErrorFunctionType,
359
- ) => PerseusScore = ({scoring, ...rubric}, onInputError) => {
360
- const score = Expression.validate(
361
- this.getUserInput(),
362
- rubric,
363
- onInputError || function () {},
364
- );
365
-
366
- // "scoring" is a flag that indicates when we are checking answers.
367
- // otherwise, we may just be checking validity after changes.
368
- if (scoring && score.type !== "invalid") {
369
- this.props.analytics?.onAnalyticsEvent({
370
- type: "perseus:expression-evaluated",
371
- payload: {
372
- result:
373
- score.earned === score.total ? "correct" : "incorrect",
374
- virtualKeypadVersion: deriveKeypadVersion(
375
- this.props.apiOptions,
376
- ),
377
- },
378
- });
379
- }
380
-
381
- return score;
382
- };
383
-
384
- getUserInput: () => string = () => {
385
- return Expression.getUserInputFromProps(this.props);
386
- };
387
-
388
- change: (...args: any) => any | undefined = (...args: any) => {
389
- return Changeable.change.apply(this, args);
390
- };
391
-
392
- parse: (value: string, props: Props) => any = (
393
- value: string,
394
- props: Props,
395
- ) => {
396
- // TODO(jack): Disable icu for content creators here, or
397
- // make it so that solution answers with ','s or '.'s work
398
- const options = _.pick(props || this.props, "functions");
399
- _.extend(options, {
400
- decimal_separator: i18n.getDecimalSeparator(),
401
- });
402
- return KAS.parse(normalizeTex(value), options);
403
- };
404
-
405
- changeAndTrack: (e: any, cb: () => void) => void = (
406
- e: any,
407
- cb: () => void,
408
- ) => {
409
- this.change("value", e, cb);
410
- this.props.trackInteraction();
411
- };
412
-
413
- _handleFocus: () => void = () => {
414
- this.props.analytics?.onAnalyticsEvent({
415
- type: "perseus:expression-focused",
416
- payload: null,
417
- });
418
-
419
- /* c8 ignore next */
420
- this.props.onFocus([]);
421
- };
422
-
423
- _handleBlur: () => void = () => {
424
- /* c8 ignore next */
425
- this.props.onBlur([]);
426
- };
427
-
428
- focus: () => boolean = () => {
429
- if (this.props.apiOptions.customKeypad) {
430
- // eslint-disable-next-line react/no-string-refs
431
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
432
- this.refs.input.focus();
433
- } else {
434
- // The buttons are often on top of text you're trying to read, so
435
- // don't focus the editor automatically.
436
- }
437
-
438
- return true;
439
- };
440
-
441
- focusInputPath: (inputPath: InputPath) => void = (inputPath: InputPath) => {
442
- // eslint-disable-next-line react/no-string-refs
443
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
444
- this.refs.input.focus();
445
- };
446
-
447
- blurInputPath: (inputPath: InputPath) => void = (inputPath: InputPath) => {
448
- // eslint-disable-next-line react/no-string-refs
449
- // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
450
- this.refs.input.blur();
451
- };
452
-
453
- // HACK(joel)
454
- insert(keyPressed: Key) {
455
- // eslint-disable-next-line react/no-string-refs
456
- // @ts-expect-error - TS2339 - Property 'insert' does not exist on type 'ReactInstance'.
457
- this.refs.input.insert(keyPressed);
458
- }
459
-
460
- getInputPaths: () => ReadonlyArray<ReadonlyArray<any>> = () => {
461
- // The widget itself is an input, so we return a single empty list to
462
- // indicate this.
463
- /* c8 ignore next */
464
- return [[]];
465
- };
466
-
467
- // TODO(Nicole): I believe this is going away and won't be needed anymore
468
- getGrammarTypeForPath: (inputPath: string) => string = (
469
- inputPath: string,
470
- ) => {
471
- /* c8 ignore next */
472
- return "expression";
473
- };
474
-
475
- setInputValue: (path: string, newValue: string, cb: () => void) => void = (
476
- path: string,
477
- newValue: string,
478
- cb: () => void,
479
- ) => {
480
- this.props.onChange(
481
- {
482
- value: newValue,
483
- },
484
- cb,
485
- );
486
- };
487
-
488
- render():
489
- | React.ReactNode
490
- | React.ReactElement<React.ComponentProps<"div">> {
491
- if (this.props.apiOptions.customKeypad) {
492
- return (
493
- <KeypadInput
494
- // eslint-disable-next-line react/no-string-refs
495
- ref="input"
496
- value={this.props.value}
497
- keypadElement={this.props.keypadElement}
498
- onChange={this.changeAndTrack}
499
- onFocus={() => {
500
- // this.props.keypadElement should always be set
501
- // when apiOptions.customKeypad is set, but how
502
- // to convince TypeScript of this?
503
- this.props.keypadElement?.configure(
504
- this.props.keypadConfiguration,
505
- () => {
506
- if (this._isMounted) {
507
- this._handleFocus();
508
- }
509
- },
510
- );
511
- }}
512
- onBlur={this._handleBlur}
513
- />
514
- );
515
- }
516
-
517
- const className = classNames({
518
- "perseus-widget-expression": true,
519
- "show-error-tooltip": this.state.showErrorTooltip,
520
- });
521
-
522
- return (
523
- <div
524
- className={className}
525
- onBlur={() =>
526
- this.state.invalid &&
527
- this.setState({
528
- showErrorTooltip: true,
529
- showErrorStyle: true,
530
- })
531
- }
532
- onFocus={() =>
533
- this.setState({
534
- showErrorTooltip: false,
535
- })
536
- }
537
- >
538
- {/**
539
- * This is a visually hidden container for the error tooltip.
540
- https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alert_role#example_3_visually_hidden_alert_container_for_screen_reader_notifications
541
- */}
542
- <View style={a11y.srOnly} role="alert">
543
- {this.state.showErrorTooltip &&
544
- ERROR_TITLE + " " + ERROR_MESSAGE}
545
- </View>
546
- <Tooltip
547
- forceAnchorFocusivity={false}
548
- opened={this.state.showErrorTooltip}
549
- title={ERROR_TITLE}
550
- content={ERROR_MESSAGE}
551
- >
552
- <MathInput
553
- // eslint-disable-next-line react/no-string-refs
554
- ref="input"
555
- className={ApiClassNames.INTERACTIVE}
556
- value={this.props.value}
557
- onChange={this.changeAndTrack}
558
- convertDotToTimes={this.props.times}
559
- buttonSets={this.props.buttonSets}
560
- onFocus={this._handleFocus}
561
- onBlur={this._handleBlur}
562
- hasError={this.state.showErrorStyle}
563
- extraKeys={this.props.keypadConfiguration?.extraKeys}
564
- analytics={
565
- this.props.analytics ?? {
566
- onAnalyticsEvent: async () => {},
567
- }
568
- }
569
- />
570
- </Tooltip>
571
- </div>
572
- );
573
- }
574
- }
575
-
576
- /**
577
- * Determine the keypad configuration parameters for the input, based on the
578
- * provided properties.
579
- *
580
- * There are two configuration parameters to be passed to the keypad:
581
- * (1) The keypad type. For the Expression widget, we always use the
582
- * Expression keypad.
583
- * (2) The extra keys; namely, any variables or constants (like Pi) that need
584
- * to be included as keys on the keypad. These are scraped from the answer
585
- * forms.
586
- */
587
- const keypadConfigurationForProps = (
588
- widgetOptions: PerseusExpressionWidgetOptions,
589
- ): KeypadConfiguration => {
590
- // Always use the Expression keypad, regardless of the button sets that have
591
- // been enabled.
592
- const keypadType = KeypadType.EXPRESSION;
593
-
594
- // Extract any and all variables and constants from the answer forms.
595
- const uniqueExtraVariables: Partial<Record<Key, boolean>> = {};
596
- const uniqueExtraConstants: Partial<Record<Key, boolean>> = {};
597
- for (const answerForm of widgetOptions.answerForms) {
598
- const maybeExpr = KAS.parse(answerForm.value, widgetOptions);
599
- if (maybeExpr.parsed) {
600
- const expr = maybeExpr.expr;
601
-
602
- // The keypad expects Greek letters to be capitalized (e.g., it
603
- // requires `PI` instead of `pi`). Right now, it only supports Pi
604
- // and Theta, so we special-case.
605
- const isGreek = (symbol: any) =>
606
- symbol === "pi" || symbol === "theta";
607
- const toKey = (symbol: any) =>
608
- isGreek(symbol) ? symbol.toUpperCase() : symbol;
609
- const isKey = (key: string): key is Key =>
610
- KeyArray.includes(key as Key);
611
-
612
- for (const variable of expr.getVars()) {
613
- const maybeKey = toKey(variable);
614
- if (isKey(maybeKey)) {
615
- uniqueExtraVariables[maybeKey] = true;
616
- }
617
- }
618
- for (const constant of expr.getConsts()) {
619
- const maybeKey = toKey(constant);
620
- if (isKey(maybeKey)) {
621
- uniqueExtraConstants[maybeKey] = true;
622
- }
623
- }
624
- }
625
- }
626
-
627
- // TODO(charlie): Alert the keypad as to which of these symbols should be
628
- // treated as functions.
629
- const extraVariables = Object.keys(
630
- uniqueExtraVariables,
631
- ).sort() as ReadonlyArray<Key>;
632
-
633
- const extraConstants = Object.keys(
634
- uniqueExtraConstants,
635
- ).sort() as ReadonlyArray<Key>;
636
-
637
- let extraKeys = [...extraVariables, ...extraConstants];
638
- if (!extraKeys.length) {
639
- // If there are no extra symbols available, we include Pi anyway, so
640
- // that the "extra symbols" button doesn't appear empty.
641
- extraKeys = ["PI"];
642
- }
643
-
644
- return {keypadType, extraKeys, times: widgetOptions.times};
645
- };
646
-
647
- const propUpgrades = {
648
- /* c8 ignore next */
649
- "1": (v0props: any): PerseusExpressionWidgetOptions => ({
650
- times: v0props.times,
651
- buttonSets: v0props.buttonSets,
652
- functions: v0props.functions,
653
- buttonsVisible: v0props.buttonsVisible,
654
-
655
- answerForms: [
656
- {
657
- considered: "correct",
658
- form: v0props.form,
659
- simplify: v0props.simplify,
660
- value: v0props.value,
661
- },
662
- ],
663
- }),
664
- } as const;
665
-
666
- const ExpressionWithDependencies = React.forwardRef<
667
- Expression,
668
- Omit<PropsFor<typeof Expression>, keyof ReturnType<typeof useDependencies>>
669
- >((props, ref) => {
670
- const deps = useDependencies();
671
- return <Expression ref={ref} analytics={deps.analytics} {...props} />;
672
- });
673
-
674
- // HACK: Propogate "static" methods onto our wrapper component.
675
- // In the future we should adjust client apps to not depend on these static
676
- // methods and instead adjust Peresus to provide these facilities through
677
- // instance methods on our Renderers.
678
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type
679
- ExpressionWithDependencies.validate = Expression.validate;
680
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type
681
- ExpressionWithDependencies.getUserInputFromProps =
682
- Expression.getUserInputFromProps;
683
- // @ts-expect-error - TS2339 - Property 'validate' does not exist on type
684
- ExpressionWithDependencies.getOneCorrectAnswerFromRubric =
685
- Expression.getOneCorrectAnswerFromRubric;
686
-
687
- export default {
688
- name: "expression",
689
- displayName: "Expression / Equation",
690
- defaultAlignment: "inline-block",
691
- widget: ExpressionWithDependencies,
692
- transform: (widgetOptions: PerseusExpressionWidgetOptions): RenderProps => {
693
- const {times, functions, buttonSets, buttonsVisible} = widgetOptions;
694
- return {
695
- keypadConfiguration: keypadConfigurationForProps(widgetOptions),
696
- times,
697
- functions,
698
- buttonSets,
699
- buttonsVisible,
700
- };
701
- },
702
- version: {major: 1, minor: 0},
703
- propUpgrades: propUpgrades,
704
-
705
- // For use by the editor
706
- isLintable: true,
707
- } as WidgetExports<typeof ExpressionWithDependencies>;