@khanacademy/perseus 2.1.0 → 4.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 (1212) hide show
  1. package/.babelrc.js +1 -1
  2. package/.eslintrc.js +1 -0
  3. package/CHANGELOG.md +22 -0
  4. package/dist/__tests__/mock-asset-loading-widget.d.ts +59 -0
  5. package/dist/__tests__/mock-asset-loading-widget.js.flow +70 -0
  6. package/dist/__tests__/mock-widget.d.ts +30 -0
  7. package/dist/__tests__/mock-widget.js.flow +39 -0
  8. package/dist/__tests__/test-items/image-item.d.ts +14 -0
  9. package/dist/__tests__/test-items/image-item.js.flow +20 -0
  10. package/dist/__tests__/test-items/input-number-1-item.d.ts +9 -0
  11. package/dist/__tests__/test-items/input-number-1-item.js.flow +15 -0
  12. package/dist/__tests__/test-items/input-number-2-item.d.ts +9 -0
  13. package/dist/__tests__/test-items/input-number-2-item.js.flow +15 -0
  14. package/dist/__tests__/test-items/table-item.d.ts +9 -0
  15. package/dist/__tests__/test-items/table-item.js.flow +15 -0
  16. package/dist/a11y.d.ts +5 -0
  17. package/dist/a11y.js.flow +11 -0
  18. package/dist/all-widgets.d.ts +22 -0
  19. package/dist/all-widgets.js.flow +33 -0
  20. package/dist/article-renderer.d.ts +54 -0
  21. package/dist/article-renderer.js.flow +69 -0
  22. package/dist/asset-context.d.ts +14 -0
  23. package/dist/asset-context.js.flow +15 -0
  24. package/dist/basic-widgets.d.ts +22 -0
  25. package/dist/basic-widgets.js.flow +33 -0
  26. package/dist/components/button-group.d.ts +27 -0
  27. package/dist/components/button-group.js.flow +33 -0
  28. package/dist/components/constants.d.ts +7 -0
  29. package/dist/components/constants.js.flow +13 -0
  30. package/dist/components/fixed-to-responsive.d.ts +2 -0
  31. package/dist/components/fixed-to-responsive.js.flow +8 -0
  32. package/dist/components/graph.d.ts +44 -0
  33. package/dist/components/graph.js.flow +52 -0
  34. package/dist/components/graphie-classes.d.ts +13 -0
  35. package/dist/components/graphie-classes.js.flow +19 -0
  36. package/dist/components/graphie-movables.d.ts +16 -0
  37. package/dist/components/graphie-movables.js.flow +22 -0
  38. package/dist/components/graphie.d.ts +44 -0
  39. package/dist/components/graphie.js.flow +56 -0
  40. package/dist/components/highlighting/highlightable-content.d.ts +39 -0
  41. package/dist/components/highlighting/highlightable-content.js.flow +59 -0
  42. package/dist/components/highlighting/highlights.d.ts +30 -0
  43. package/dist/components/highlighting/highlights.js.flow +54 -0
  44. package/dist/components/highlighting/ranges.d.ts +42 -0
  45. package/dist/components/highlighting/ranges.js.flow +60 -0
  46. package/dist/components/highlighting/types.d.ts +64 -0
  47. package/dist/components/highlighting/types.js.flow +70 -0
  48. package/dist/components/highlighting/ui/highlight-renderer.d.ts +34 -0
  49. package/dist/components/highlighting/ui/highlight-renderer.js.flow +45 -0
  50. package/dist/components/highlighting/ui/highlight-set-renderer.d.ts +34 -0
  51. package/dist/components/highlighting/ui/highlight-set-renderer.js.flow +44 -0
  52. package/dist/components/highlighting/ui/highlight-tooltip.d.ts +16 -0
  53. package/dist/components/highlighting/ui/highlight-tooltip.js.flow +24 -0
  54. package/dist/components/highlighting/ui/highlighting-ui.d.ts +19 -0
  55. package/dist/components/highlighting/ui/highlighting-ui.js.flow +30 -0
  56. package/dist/components/highlighting/ui/selection-tracker.d.ts +47 -0
  57. package/dist/components/highlighting/ui/selection-tracker.js.flow +56 -0
  58. package/dist/components/highlighting/ui/types.d.ts +13 -0
  59. package/dist/components/highlighting/ui/types.js.flow +22 -0
  60. package/dist/components/highlighting/ui/util.d.ts +28 -0
  61. package/dist/components/highlighting/ui/util.js.flow +42 -0
  62. package/dist/components/highlighting/word-indexer.d.ts +28 -0
  63. package/dist/components/highlighting/word-indexer.js.flow +21 -0
  64. package/dist/components/hud.d.ts +15 -0
  65. package/dist/components/hud.js.flow +21 -0
  66. package/dist/components/icon.d.ts +56 -0
  67. package/dist/components/icon.js.flow +31 -0
  68. package/dist/components/image-loader.d.ts +52 -0
  69. package/dist/components/image-loader.js.flow +49 -0
  70. package/dist/components/info-tip/info-tip.d.ts +14 -0
  71. package/dist/components/info-tip/info-tip.js.flow +20 -0
  72. package/dist/components/info-tip.d.ts +18 -0
  73. package/dist/components/info-tip.js.flow +18 -0
  74. package/dist/components/inline-icon.d.ts +10 -0
  75. package/dist/components/inline-icon.js.flow +16 -0
  76. package/dist/components/input-with-examples.d.ts +52 -0
  77. package/dist/components/input-with-examples.js.flow +58 -0
  78. package/dist/components/lint.d.ts +23 -0
  79. package/dist/components/lint.js.flow +29 -0
  80. package/dist/components/math-input.d.ts +40 -0
  81. package/dist/components/math-input.js.flow +46 -0
  82. package/dist/components/math-output.d.ts +23 -0
  83. package/dist/components/math-output.js.flow +29 -0
  84. package/dist/components/multi-button-group.d.ts +29 -0
  85. package/dist/components/multi-button-group.js.flow +35 -0
  86. package/dist/components/number-input.d.ts +34 -0
  87. package/dist/components/number-input.js.flow +42 -0
  88. package/dist/components/prop-check-box.d.ts +2 -0
  89. package/dist/components/prop-check-box.js.flow +8 -0
  90. package/dist/components/range-input.d.ts +14 -0
  91. package/dist/components/range-input.js.flow +20 -0
  92. package/dist/components/simple-keypad-input.d.ts +19 -0
  93. package/dist/components/simple-keypad-input.js.flow +16 -0
  94. package/dist/components/sortable.d.ts +68 -0
  95. package/dist/components/sortable.js.flow +78 -0
  96. package/dist/components/stub-tag-editor.d.ts +25 -0
  97. package/dist/components/stub-tag-editor.js.flow +18 -0
  98. package/dist/components/svg-image.d.ts +74 -0
  99. package/dist/components/svg-image.js.flow +83 -0
  100. package/dist/components/tex-buttons.d.ts +20 -0
  101. package/dist/components/tex-buttons.js.flow +26 -0
  102. package/dist/components/tex.d.ts +25 -0
  103. package/dist/components/tex.js.flow +25 -0
  104. package/dist/components/text-input.d.ts +33 -0
  105. package/dist/components/text-input.js.flow +39 -0
  106. package/dist/components/text-list-editor.d.ts +16 -0
  107. package/dist/components/text-list-editor.js.flow +22 -0
  108. package/dist/components/tooltip.d.ts +32 -0
  109. package/dist/components/tooltip.js.flow +38 -0
  110. package/dist/components/visibility-observer/create-visibility-observer.d.ts +34 -0
  111. package/dist/components/visibility-observer/create-visibility-observer.js.flow +23 -0
  112. package/dist/components/visibility-observer/get-scroll-parent.d.ts +1 -0
  113. package/dist/components/visibility-observer/get-scroll-parent.js.flow +7 -0
  114. package/dist/components/visibility-observer/visibility-observer.d.ts +31 -0
  115. package/dist/components/visibility-observer/visibility-observer.js.flow +36 -0
  116. package/dist/components/zoomable-tex.d.ts +18 -0
  117. package/dist/components/zoomable-tex.js.flow +18 -0
  118. package/dist/components/zoomable.d.ts +64 -0
  119. package/dist/components/zoomable.js.flow +70 -0
  120. package/dist/components.d.ts +16 -0
  121. package/dist/components.js.flow +22 -0
  122. package/dist/definition-context.d.ts +21 -0
  123. package/dist/definition-context.js.flow +25 -0
  124. package/dist/dependencies.d.ts +3 -0
  125. package/dist/dependencies.js.flow +9 -0
  126. package/dist/error-boundary.d.ts +13 -0
  127. package/dist/error-boundary.js.flow +21 -0
  128. package/dist/es/index.js +23239 -26937
  129. package/dist/es/index.js.map +1 -1
  130. package/dist/extra-widgets.d.ts +22 -0
  131. package/dist/extra-widgets.js.flow +33 -0
  132. package/dist/hint-renderer.d.ts +23 -0
  133. package/dist/hint-renderer.js.flow +32 -0
  134. package/dist/hints-renderer.d.ts +29 -0
  135. package/dist/hints-renderer.js.flow +41 -0
  136. package/dist/icon-paths.d.ts +117 -0
  137. package/dist/icon-paths.js.flow +123 -0
  138. package/dist/index.d.ts +103 -2
  139. package/dist/index.js +13063 -16571
  140. package/dist/index.js.flow +133 -2
  141. package/dist/index.js.map +1 -1
  142. package/dist/init.d.ts +14 -0
  143. package/dist/init.js.flow +20 -0
  144. package/dist/interaction-tracker.d.ts +23 -0
  145. package/dist/interaction-tracker.js.flow +33 -0
  146. package/dist/interactive2/__tests__/movable-mock.d.ts +5 -0
  147. package/dist/interactive2/__tests__/movable-mock.js.flow +11 -0
  148. package/dist/interactive2/interactive-util.d.ts +31 -0
  149. package/dist/interactive2/interactive-util.js.flow +50 -0
  150. package/dist/interactive2/movable-helper-methods.d.ts +9 -0
  151. package/dist/interactive2/movable-helper-methods.js.flow +15 -0
  152. package/dist/interactive2/movable-line-options.d.ts +34 -0
  153. package/dist/interactive2/movable-line-options.js.flow +44 -0
  154. package/dist/interactive2/movable-line.d.ts +2 -0
  155. package/dist/interactive2/movable-line.js.flow +8 -0
  156. package/dist/interactive2/movable-point-options.d.ts +34 -0
  157. package/dist/interactive2/movable-point-options.js.flow +44 -0
  158. package/dist/interactive2/movable-point.d.ts +2 -0
  159. package/dist/interactive2/movable-point.js.flow +8 -0
  160. package/dist/interactive2/movable-polygon-options.d.ts +40 -0
  161. package/dist/interactive2/movable-polygon-options.js.flow +47 -0
  162. package/dist/interactive2/movable-polygon.d.ts +2 -0
  163. package/dist/interactive2/movable-polygon.js.flow +8 -0
  164. package/dist/interactive2/movable.d.ts +2 -0
  165. package/dist/interactive2/movable.js.flow +8 -0
  166. package/dist/interactive2/objective_.d.ts +13 -0
  167. package/dist/interactive2/objective_.js.flow +25 -0
  168. package/dist/interactive2/types.d.ts +2 -0
  169. package/dist/interactive2/types.js.flow +8 -0
  170. package/dist/interactive2/wrapped-defaults.d.ts +5 -0
  171. package/dist/interactive2/wrapped-defaults.js.flow +11 -0
  172. package/dist/interactive2/wrapped-ellipse.d.ts +3 -0
  173. package/dist/interactive2/wrapped-ellipse.js.flow +14 -0
  174. package/dist/interactive2/wrapped-line.d.ts +3 -0
  175. package/dist/interactive2/wrapped-line.js.flow +14 -0
  176. package/dist/interactive2/wrapped-path.d.ts +3 -0
  177. package/dist/interactive2/wrapped-path.js.flow +13 -0
  178. package/dist/interactive2.d.ts +10 -0
  179. package/dist/interactive2.js.flow +16 -0
  180. package/dist/item-renderer.d.ts +117 -0
  181. package/dist/item-renderer.js.flow +136 -0
  182. package/dist/item-version.d.ts +4 -0
  183. package/dist/item-version.js.flow +11 -0
  184. package/dist/jipt-paragraphs.d.ts +8 -0
  185. package/dist/jipt-paragraphs.js.flow +14 -0
  186. package/dist/keypad-context.d.ts +20 -0
  187. package/dist/keypad-context.js.flow +18 -0
  188. package/dist/loading-context.d.ts +14 -0
  189. package/dist/loading-context.js.flow +12 -0
  190. package/dist/logging/log.d.ts +55 -0
  191. package/dist/logging/log.js.flow +62 -0
  192. package/dist/mixins/changeable.d.ts +30 -0
  193. package/dist/mixins/changeable.js.flow +33 -0
  194. package/dist/mixins/editor-jsonify.d.ts +4 -0
  195. package/dist/mixins/editor-jsonify.js.flow +10 -0
  196. package/dist/mixins/provide-keypad.d.ts +36 -0
  197. package/dist/mixins/provide-keypad.js.flow +33 -0
  198. package/dist/mixins/widget-jsonify-deprecated.d.ts +5 -0
  199. package/dist/mixins/widget-jsonify-deprecated.js.flow +11 -0
  200. package/dist/mixins/widget-prop-denylist.d.ts +14 -0
  201. package/dist/mixins/widget-prop-denylist.js.flow +20 -0
  202. package/dist/multi-items/item-types.d.ts +32 -0
  203. package/dist/multi-items/items.d.ts +53 -0
  204. package/dist/multi-items/items.js.flow +66 -0
  205. package/dist/multi-items/multi-renderer.d.ts +152 -0
  206. package/dist/multi-items/multi-renderer.js.flow +213 -0
  207. package/dist/multi-items/prop-type-builders.d.ts +20 -0
  208. package/dist/multi-items/prop-type-builders.js.flow +22 -0
  209. package/dist/multi-items/shape-types.d.ts +47 -0
  210. package/dist/multi-items/shape-types.js.flow +60 -0
  211. package/dist/multi-items/shapes.d.ts +23 -0
  212. package/dist/multi-items/shapes.js.flow +25 -0
  213. package/dist/multi-items/tree-types.d.ts +34 -0
  214. package/dist/multi-items/tree-types.js.flow +45 -0
  215. package/dist/multi-items/trees.d.ts +146 -0
  216. package/dist/multi-items/trees.js.flow +147 -0
  217. package/dist/multi-items.d.ts +73 -0
  218. package/dist/multi-items.js.flow +36 -0
  219. package/dist/perseus-api.d.ts +128 -0
  220. package/dist/perseus-api.js.flow +139 -0
  221. package/dist/perseus-env.d.ts +3 -0
  222. package/dist/perseus-env.js.flow +6 -0
  223. package/dist/perseus-error.d.ts +11 -0
  224. package/dist/perseus-error.js.flow +16 -0
  225. package/dist/perseus-markdown.d.ts +11 -0
  226. package/dist/perseus-markdown.js.flow +20 -0
  227. package/dist/perseus-types.d.ts +776 -0
  228. package/dist/perseus-types.js.flow +1032 -0
  229. package/dist/question-paragraph.d.ts +11 -0
  230. package/dist/question-paragraph.js.flow +17 -0
  231. package/dist/renderability.d.ts +10 -0
  232. package/dist/renderability.js.flow +19 -0
  233. package/dist/renderer.d.ts +254 -0
  234. package/dist/renderer.js.flow +327 -0
  235. package/dist/server-item-renderer.d.ts +113 -0
  236. package/dist/server-item-renderer.js.flow +136 -0
  237. package/dist/sigfigs.d.ts +32 -0
  238. package/dist/sigfigs.js.flow +41 -0
  239. package/dist/styles/constants.d.ts +56 -0
  240. package/dist/styles/constants.js.flow +62 -0
  241. package/dist/styles/global-constants.d.ts +342 -0
  242. package/dist/styles/global-constants.js.flow +348 -0
  243. package/dist/styles/global-styles.d.ts +47 -0
  244. package/dist/styles/global-styles.js.flow +53 -0
  245. package/dist/styles/media-queries.d.ts +29 -0
  246. package/dist/styles/media-queries.js.flow +35 -0
  247. package/dist/styles/shared.d.ts +3 -0
  248. package/dist/styles/shared.js.flow +9 -0
  249. package/dist/tex-wrangler.d.ts +7 -0
  250. package/dist/tex-wrangler.js.flow +13 -0
  251. package/dist/translation-linter.d.ts +21 -0
  252. package/dist/translation-linter.js.flow +32 -0
  253. package/dist/traversal.d.ts +15 -0
  254. package/dist/traversal.js.flow +26 -0
  255. package/dist/types.d.ts +262 -0
  256. package/dist/types.js.flow +337 -0
  257. package/dist/util/a11y.d.ts +3 -0
  258. package/dist/util/a11y.js.flow +9 -0
  259. package/dist/util/answer-types.d.ts +34 -0
  260. package/dist/util/answer-types.js.flow +49 -0
  261. package/dist/util/colors.d.ts +89 -0
  262. package/dist/util/colors.js.flow +95 -0
  263. package/dist/util/fix-passage-refs.d.ts +2 -0
  264. package/dist/util/fix-passage-refs.js.flow +8 -0
  265. package/dist/util/graph-utils.d.ts +12 -0
  266. package/dist/util/graph-utils.js.flow +9 -0
  267. package/dist/util/graphie.d.ts +2 -0
  268. package/dist/util/graphie.js.flow +8 -0
  269. package/dist/util/interactive.d.ts +9 -0
  270. package/dist/util/interactive.js.flow +9 -0
  271. package/dist/util/katex-preprocess.d.ts +6 -0
  272. package/dist/util/katex-preprocess.js.flow +12 -0
  273. package/dist/util/math.d.ts +28 -0
  274. package/dist/util/math.js.flow +62 -0
  275. package/dist/util/mobile-native-utils.d.ts +7 -0
  276. package/dist/util/mobile-native-utils.js.flow +12 -0
  277. package/dist/util/react-render.d.ts +2 -0
  278. package/dist/util/react-render.js.flow +12 -0
  279. package/dist/util/register-all-widgets-for-testing.d.ts +1 -0
  280. package/dist/util/register-all-widgets-for-testing.js.flow +7 -0
  281. package/dist/util/scroll-utils.d.ts +10 -0
  282. package/dist/util/scroll-utils.js.flow +19 -0
  283. package/dist/util/sizing-utils.d.ts +9 -0
  284. package/dist/util/sizing-utils.js.flow +20 -0
  285. package/dist/util/tex.d.ts +6 -0
  286. package/dist/util/tex.js.flow +17 -0
  287. package/dist/util/url-utils.d.ts +6 -0
  288. package/dist/util/url-utils.js.flow +11 -0
  289. package/dist/util.d.ts +247 -0
  290. package/dist/util.js.flow +320 -0
  291. package/dist/version.d.ts +11 -0
  292. package/dist/version.js.flow +17 -0
  293. package/dist/widget-container.d.ts +27 -0
  294. package/dist/widget-container.js.flow +33 -0
  295. package/dist/widgets/__tests__/renderQuestion.d.ts +13 -0
  296. package/dist/widgets/__tests__/renderQuestion.js.flow +28 -0
  297. package/dist/widgets/categorizer.d.ts +55 -0
  298. package/dist/widgets/categorizer.js.flow +70 -0
  299. package/dist/widgets/cs-program.d.ts +48 -0
  300. package/dist/widgets/cs-program.js.flow +54 -0
  301. package/dist/widgets/definition.d.ts +42 -0
  302. package/dist/widgets/definition.js.flow +57 -0
  303. package/dist/widgets/dropdown.d.ts +51 -0
  304. package/dist/widgets/dropdown.js.flow +63 -0
  305. package/dist/widgets/explanation.d.ts +49 -0
  306. package/dist/widgets/explanation.js.flow +58 -0
  307. package/dist/widgets/expression.d.ts +90 -0
  308. package/dist/widgets/expression.js.flow +115 -0
  309. package/dist/widgets/graded-group-answer-bar.d.ts +13 -0
  310. package/dist/widgets/graded-group-answer-bar.js.flow +24 -0
  311. package/dist/widgets/graded-group-set.d.ts +52 -0
  312. package/dist/widgets/graded-group-set.js.flow +65 -0
  313. package/dist/widgets/graded-group.d.ts +66 -0
  314. package/dist/widgets/graded-group.js.flow +78 -0
  315. package/dist/widgets/grapher/util.d.ts +19 -0
  316. package/dist/widgets/grapher/util.js.flow +38 -0
  317. package/dist/widgets/grapher.d.ts +63 -0
  318. package/dist/widgets/grapher.js.flow +93 -0
  319. package/dist/widgets/group.d.ts +51 -0
  320. package/dist/widgets/group.js.flow +60 -0
  321. package/dist/widgets/iframe.d.ts +52 -0
  322. package/dist/widgets/iframe.js.flow +53 -0
  323. package/dist/widgets/image.d.ts +59 -0
  324. package/dist/widgets/image.js.flow +73 -0
  325. package/dist/widgets/input-number.d.ts +75 -0
  326. package/dist/widgets/input-number.js.flow +94 -0
  327. package/dist/widgets/interaction/arrow-picker.d.ts +12 -0
  328. package/dist/widgets/interaction/arrow-picker.js.flow +21 -0
  329. package/dist/widgets/interaction/color-picker.d.ts +14 -0
  330. package/dist/widgets/interaction/color-picker.js.flow +23 -0
  331. package/dist/widgets/interaction/dash-picker.d.ts +12 -0
  332. package/dist/widgets/interaction/dash-picker.js.flow +21 -0
  333. package/dist/widgets/interaction/element-container.d.ts +21 -0
  334. package/dist/widgets/interaction/element-container.js.flow +33 -0
  335. package/dist/widgets/interaction.d.ts +51 -0
  336. package/dist/widgets/interaction.js.flow +60 -0
  337. package/dist/widgets/interactive-graph.d.ts +180 -0
  338. package/dist/widgets/interactive-graph.js.flow +242 -0
  339. package/dist/widgets/label-image/answer-choices.d.ts +51 -0
  340. package/dist/widgets/label-image/answer-choices.js.flow +55 -0
  341. package/dist/widgets/label-image/marker.d.ts +28 -0
  342. package/dist/widgets/label-image/marker.js.flow +33 -0
  343. package/dist/widgets/label-image/types.d.ts +14 -0
  344. package/dist/widgets/label-image/types.js.flow +23 -0
  345. package/dist/widgets/label-image.d.ts +113 -0
  346. package/dist/widgets/label-image.js.flow +142 -0
  347. package/dist/widgets/lights-puzzle.d.ts +47 -0
  348. package/dist/widgets/lights-puzzle.js.flow +58 -0
  349. package/dist/widgets/matcher.d.ts +82 -0
  350. package/dist/widgets/matcher.js.flow +101 -0
  351. package/dist/widgets/matrix.d.ts +65 -0
  352. package/dist/widgets/matrix.js.flow +80 -0
  353. package/dist/widgets/measurer.d.ts +21 -0
  354. package/dist/widgets/measurer.js.flow +30 -0
  355. package/dist/widgets/molecule/molecule-drawing.d.ts +5 -0
  356. package/dist/widgets/molecule/molecule-drawing.js.flow +11 -0
  357. package/dist/widgets/molecule/molecule-layout.d.ts +82 -0
  358. package/dist/widgets/molecule/molecule-layout.js.flow +96 -0
  359. package/dist/widgets/molecule/smiles-parser.d.ts +19 -0
  360. package/dist/widgets/molecule/smiles-parser.js.flow +26 -0
  361. package/dist/widgets/molecule.d.ts +51 -0
  362. package/dist/widgets/molecule.js.flow +60 -0
  363. package/dist/widgets/number-line.d.ts +90 -0
  364. package/dist/widgets/number-line.js.flow +102 -0
  365. package/dist/widgets/numeric-input.d.ts +80 -0
  366. package/dist/widgets/numeric-input.js.flow +109 -0
  367. package/dist/widgets/orderer.d.ts +69 -0
  368. package/dist/widgets/orderer.js.flow +81 -0
  369. package/dist/widgets/passage/passage-markdown.d.ts +22 -0
  370. package/dist/widgets/passage/passage-markdown.js.flow +33 -0
  371. package/dist/widgets/passage-ref-target.d.ts +41 -0
  372. package/dist/widgets/passage-ref-target.js.flow +52 -0
  373. package/dist/widgets/passage-ref.d.ts +65 -0
  374. package/dist/widgets/passage-ref.js.flow +85 -0
  375. package/dist/widgets/passage.d.ts +125 -0
  376. package/dist/widgets/passage.js.flow +157 -0
  377. package/dist/widgets/plotter.d.ts +68 -0
  378. package/dist/widgets/plotter.js.flow +78 -0
  379. package/dist/widgets/radio/base-radio.d.ts +38 -0
  380. package/dist/widgets/radio/base-radio.js.flow +44 -0
  381. package/dist/widgets/radio/choice-a11y-text.d.ts +2 -0
  382. package/dist/widgets/radio/choice-a11y-text.js.flow +14 -0
  383. package/dist/widgets/radio/choice-icon/choice-icon.d.ts +16 -0
  384. package/dist/widgets/radio/choice-icon/choice-icon.js.flow +22 -0
  385. package/dist/widgets/radio/choice-icon/cross-out-line.d.ts +9 -0
  386. package/dist/widgets/radio/choice-icon/cross-out-line.js.flow +16 -0
  387. package/dist/widgets/radio/choice-icon/shared-styles.d.ts +5 -0
  388. package/dist/widgets/radio/choice-icon/shared-styles.js.flow +11 -0
  389. package/dist/widgets/radio/choice-none-above.d.ts +6 -0
  390. package/dist/widgets/radio/choice-none-above.js.flow +16 -0
  391. package/dist/widgets/radio/choice.d.ts +23 -0
  392. package/dist/widgets/radio/choice.js.flow +32 -0
  393. package/dist/widgets/radio/choice.jsx.fixture.d.ts +1 -0
  394. package/dist/widgets/radio/choice.jsx.fixture.js.flow +7 -0
  395. package/dist/widgets/radio/focus-ring.d.ts +12 -0
  396. package/dist/widgets/radio/focus-ring.js.flow +15 -0
  397. package/dist/widgets/radio/option-status.d.ts +17 -0
  398. package/dist/widgets/radio/option-status.js.flow +16 -0
  399. package/dist/widgets/radio/util.d.ts +6 -0
  400. package/dist/widgets/radio/util.js.flow +12 -0
  401. package/dist/widgets/radio/widget.d.ts +62 -0
  402. package/dist/widgets/radio/widget.js.flow +80 -0
  403. package/dist/widgets/radio.d.ts +22 -0
  404. package/dist/widgets/radio.js.flow +31 -0
  405. package/dist/widgets/reaction-diagram.d.ts +37 -0
  406. package/dist/widgets/reaction-diagram.js.flow +46 -0
  407. package/dist/widgets/sequence.d.ts +79 -0
  408. package/dist/widgets/sequence.js.flow +100 -0
  409. package/dist/widgets/simulator.d.ts +89 -0
  410. package/dist/widgets/simulator.js.flow +106 -0
  411. package/dist/widgets/sorter.d.ts +82 -0
  412. package/dist/widgets/sorter.js.flow +101 -0
  413. package/dist/widgets/table.d.ts +56 -0
  414. package/dist/widgets/table.js.flow +67 -0
  415. package/dist/widgets/transformer.d.ts +94 -0
  416. package/dist/widgets/transformer.js.flow +127 -0
  417. package/dist/widgets/unit.d.ts +77 -0
  418. package/dist/widgets/unit.js.flow +93 -0
  419. package/dist/widgets/video-transcript-link.d.ts +12 -0
  420. package/dist/widgets/video-transcript-link.js.flow +15 -0
  421. package/dist/widgets/video.d.ts +48 -0
  422. package/dist/widgets/video.js.flow +57 -0
  423. package/dist/widgets.d.ts +73 -0
  424. package/dist/widgets.js.flow +108 -0
  425. package/dist/zoom.d.ts +1 -0
  426. package/dist/zoom.js.flow +7 -0
  427. package/package.json +8 -8
  428. package/src/__stories__/hints-renderer.stories.tsx +58 -0
  429. package/src/__stories__/item-renderer.stories.tsx +29 -0
  430. package/src/__stories__/server-item-renderer.stories.tsx +29 -0
  431. package/src/__testdata__/graphie.testdata.ts +51 -0
  432. package/src/__testdata__/item-renderer.testdata.ts +160 -0
  433. package/src/__testdata__/renderer.testdata.ts +122 -0
  434. package/src/__tests__/a11y.test.ts +303 -0
  435. package/src/__tests__/item-renderer.test.tsx +891 -0
  436. package/src/__tests__/jipt-paragraphs.test.ts +32 -0
  437. package/src/__tests__/mock-asset-loading-widget.tsx +56 -0
  438. package/src/__tests__/mock-widget.tsx +33 -0
  439. package/src/__tests__/perseus-markdown.test.ts +764 -0
  440. package/src/__tests__/renderability.test.ts +480 -0
  441. package/src/__tests__/renderer-api.test.tsx +328 -0
  442. package/src/__tests__/renderer.test.tsx +1802 -0
  443. package/src/__tests__/server-item-renderer.test.tsx +518 -0
  444. package/src/__tests__/test-items/image-item.ts +24 -0
  445. package/src/__tests__/test-items/input-number-1-item.ts +26 -0
  446. package/src/__tests__/test-items/input-number-2-item.ts +38 -0
  447. package/src/__tests__/test-items/table-item.ts +29 -0
  448. package/src/__tests__/tex-wrangler.test.ts +82 -0
  449. package/src/__tests__/util.test.ts +40 -0
  450. package/src/a11y.ts +45 -0
  451. package/src/all-widgets.ts +9 -0
  452. package/src/article-renderer.tsx +215 -0
  453. package/src/asset-context.ts +30 -0
  454. package/src/basic-widgets.ts +16 -0
  455. package/src/components/__stories__/button-group.stories.tsx +59 -0
  456. package/src/components/__stories__/fixed-to-responsive.stories.tsx +143 -0
  457. package/src/components/__stories__/graph.stories.tsx +30 -0
  458. package/src/components/__stories__/graphie.stories.tsx +35 -0
  459. package/src/components/__stories__/hud.stories.tsx +39 -0
  460. package/src/components/__stories__/icon.stories.tsx +63 -0
  461. package/src/components/__stories__/image-loader.stories.tsx +62 -0
  462. package/src/components/__stories__/info-tip.stories.tsx +35 -0
  463. package/src/components/__stories__/inline-icon.stories.tsx +44 -0
  464. package/src/components/__stories__/input-with-examples.stories.tsx +57 -0
  465. package/src/components/__stories__/lint.stories.tsx +51 -0
  466. package/src/components/__stories__/math-input.stories.tsx +34 -0
  467. package/src/components/__stories__/math-output.stories.tsx +25 -0
  468. package/src/components/__stories__/multi-button-group.stories.tsx +70 -0
  469. package/src/components/__stories__/number-input.stories.tsx +43 -0
  470. package/src/components/__stories__/prop-check-box.stories.tsx +65 -0
  471. package/src/components/__stories__/range-input.stories.tsx +31 -0
  472. package/src/components/__stories__/simple-keypad-input.stories.tsx +29 -0
  473. package/src/components/__stories__/sortable.stories.tsx +77 -0
  474. package/src/components/__stories__/stub-tag-editor.stories.tsx +49 -0
  475. package/src/components/__stories__/svg-image.stories.tsx +82 -0
  476. package/src/components/__stories__/tex.stories.tsx +25 -0
  477. package/src/components/__stories__/text-buttons.stories.tsx +66 -0
  478. package/src/components/__stories__/text-input.stories.tsx +39 -0
  479. package/src/components/__stories__/text-list-editor.stories.tsx +34 -0
  480. package/src/components/__stories__/zoomable-tex.stories.tsx +39 -0
  481. package/src/components/__stories__/zoomable.stories.tsx +43 -0
  482. package/src/components/__testdata__/sorter.testdata.ts +19 -0
  483. package/src/components/__tests__/number-input.test.tsx +128 -0
  484. package/src/components/__tests__/sortable.test.tsx +234 -0
  485. package/src/components/__tests__/sorter.test.tsx +111 -0
  486. package/src/components/__tests__/zoomable.test.tsx +399 -0
  487. package/src/components/button-group.tsx +130 -0
  488. package/src/components/constants.ts +14 -0
  489. package/src/components/fixed-to-responsive.tsx +165 -0
  490. package/src/components/graph.tsx +421 -0
  491. package/src/components/graphie-classes.ts +153 -0
  492. package/src/components/graphie-movables.ts +338 -0
  493. package/src/components/graphie.tsx +357 -0
  494. package/src/components/highlighting/highlightable-content.tsx +243 -0
  495. package/src/components/highlighting/highlights.ts +207 -0
  496. package/src/components/highlighting/ranges.ts +304 -0
  497. package/src/components/highlighting/types.ts +73 -0
  498. package/src/components/highlighting/ui/highlight-renderer.tsx +175 -0
  499. package/src/components/highlighting/ui/highlight-set-renderer.tsx +188 -0
  500. package/src/components/highlighting/ui/highlight-tooltip.tsx +141 -0
  501. package/src/components/highlighting/ui/highlighting-ui.tsx +153 -0
  502. package/src/components/highlighting/ui/selection-tracker.tsx +189 -0
  503. package/src/components/highlighting/ui/types.ts +21 -0
  504. package/src/components/highlighting/ui/util.ts +165 -0
  505. package/src/components/highlighting/word-indexer.tsx +156 -0
  506. package/src/components/hud.tsx +178 -0
  507. package/src/components/icon.tsx +140 -0
  508. package/src/components/image-loader.tsx +176 -0
  509. package/src/components/info-tip/info-tip.tsx +144 -0
  510. package/src/components/info-tip.tsx +40 -0
  511. package/src/components/inline-icon.tsx +77 -0
  512. package/src/components/input-with-examples.tsx +249 -0
  513. package/src/components/lint.tsx +453 -0
  514. package/src/components/math-input.tsx +299 -0
  515. package/src/components/math-output.tsx +128 -0
  516. package/src/components/multi-button-group.tsx +135 -0
  517. package/src/components/number-input.tsx +250 -0
  518. package/src/components/prop-check-box.tsx +80 -0
  519. package/src/components/range-input.tsx +60 -0
  520. package/src/components/simple-keypad-input.tsx +88 -0
  521. package/src/components/sortable.tsx +914 -0
  522. package/src/components/stub-tag-editor.tsx +53 -0
  523. package/src/components/svg-image.tsx +777 -0
  524. package/src/components/tex-buttons.tsx +321 -0
  525. package/src/components/tex.tsx +67 -0
  526. package/src/components/text-input.tsx +128 -0
  527. package/src/components/text-list-editor.tsx +169 -0
  528. package/src/components/tooltip.tsx +392 -0
  529. package/src/components/visibility-observer/__stories__/visibility-observer.stories.tsx +143 -0
  530. package/src/components/visibility-observer/create-visibility-observer.ts +108 -0
  531. package/src/components/visibility-observer/get-scroll-parent.ts +46 -0
  532. package/src/components/visibility-observer/visibility-observer.tsx +124 -0
  533. package/src/components/zoomable-tex.tsx +78 -0
  534. package/src/components/zoomable.tsx +300 -0
  535. package/src/components.ts +16 -0
  536. package/src/definition-context.tsx +60 -0
  537. package/src/dependencies.ts +21 -0
  538. package/src/error-boundary.tsx +50 -0
  539. package/src/extra-widgets.ts +75 -0
  540. package/src/hint-renderer.tsx +149 -0
  541. package/src/hints-renderer.tsx +377 -0
  542. package/src/icon-paths.ts +119 -0
  543. package/src/index.ts +158 -0
  544. package/src/init.ts +54 -0
  545. package/src/interaction-tracker.ts +61 -0
  546. package/src/interactive2/__tests__/movable-mock.ts +43 -0
  547. package/src/interactive2/__tests__/movable-point.test.ts +145 -0
  548. package/src/interactive2/interactive-util.ts +155 -0
  549. package/src/interactive2/movable-helper-methods.ts +161 -0
  550. package/src/interactive2/movable-line-options.ts +419 -0
  551. package/src/interactive2/movable-line.ts +318 -0
  552. package/src/interactive2/movable-point-options.ts +212 -0
  553. package/src/interactive2/movable-point.tsx +593 -0
  554. package/src/interactive2/movable-polygon-options.ts +390 -0
  555. package/src/interactive2/movable-polygon.ts +368 -0
  556. package/src/interactive2/movable.ts +275 -0
  557. package/src/interactive2/objective_.ts +79 -0
  558. package/src/interactive2/types.ts +2 -0
  559. package/src/interactive2/wrapped-defaults.ts +87 -0
  560. package/src/interactive2/wrapped-ellipse.ts +94 -0
  561. package/src/interactive2/wrapped-line.ts +116 -0
  562. package/src/interactive2/wrapped-path.ts +51 -0
  563. package/src/interactive2.ts +73 -0
  564. package/src/item-renderer.tsx +514 -0
  565. package/src/item-version.ts +10 -0
  566. package/src/jipt-paragraphs.ts +49 -0
  567. package/src/jquery.mobile.vmouse.js +0 -1
  568. package/src/keypad-context.ts +34 -0
  569. package/src/loading-context.ts +21 -0
  570. package/src/logging/log.test.ts +39 -0
  571. package/src/logging/log.ts +97 -0
  572. package/src/mixins/__tests__/widget-prop-denylist.test.ts +21 -0
  573. package/src/mixins/changeable.ts +133 -0
  574. package/src/mixins/editor-jsonify.ts +13 -0
  575. package/src/mixins/provide-keypad.tsx +144 -0
  576. package/src/mixins/widget-jsonify-deprecated.ts +23 -0
  577. package/src/mixins/widget-prop-denylist.ts +48 -0
  578. package/src/multi-items/__stories__/multi-renderer.stories.tsx +87 -0
  579. package/src/multi-items/__testdata__/multi-renderer.testdata.ts +172 -0
  580. package/src/multi-items/__tests__/items.test.ts +250 -0
  581. package/src/multi-items/__tests__/multi-renderer.test.tsx +910 -0
  582. package/src/multi-items/__tests__/prop-type-builders.test.ts +133 -0
  583. package/src/multi-items/__tests__/shapes.test.ts +43 -0
  584. package/src/multi-items/__tests__/trees.test.ts +325 -0
  585. package/src/multi-items/item-types.js.flow +55 -0
  586. package/src/multi-items/item-types.ts +56 -0
  587. package/src/multi-items/items.ts +176 -0
  588. package/src/multi-items/multi-renderer.tsx +564 -0
  589. package/src/multi-items/prop-type-builders.ts +106 -0
  590. package/src/multi-items/shape-types.ts +52 -0
  591. package/src/multi-items/shapes.ts +52 -0
  592. package/src/multi-items/tree-types.ts +47 -0
  593. package/src/multi-items/trees.ts +360 -0
  594. package/src/multi-items.ts +75 -0
  595. package/src/perseus-api.tsx +188 -0
  596. package/src/perseus-env.ts +27 -0
  597. package/src/perseus-error.ts +17 -0
  598. package/src/perseus-markdown.tsx +407 -0
  599. package/src/perseus-types.ts +1474 -0
  600. package/src/question-paragraph.tsx +29 -0
  601. package/src/renderability.ts +109 -0
  602. package/src/renderer.tsx +1992 -0
  603. package/src/server-item-renderer.tsx +465 -0
  604. package/src/sigfigs.ts +490 -0
  605. package/src/styles/constants.ts +94 -0
  606. package/src/styles/global-constants.ts +343 -0
  607. package/src/styles/global-styles.ts +306 -0
  608. package/src/styles/media-queries.ts +47 -0
  609. package/src/styles/shared.ts +130 -0
  610. package/src/tex-wrangler.ts +182 -0
  611. package/src/translation-linter.ts +126 -0
  612. package/src/traversal.ts +138 -0
  613. package/src/types.ts +468 -0
  614. package/src/util/a11y.ts +23 -0
  615. package/src/util/answer-types.test.ts +114 -0
  616. package/src/util/answer-types.ts +876 -0
  617. package/src/util/colors.ts +93 -0
  618. package/src/util/fix-passage-refs.ts +121 -0
  619. package/src/util/graph-utils.ts +15 -0
  620. package/src/util/graphie.ts +1617 -0
  621. package/src/util/interactive.ts +4191 -0
  622. package/src/util/katex-preprocess.ts +14 -0
  623. package/src/util/math.ts +289 -0
  624. package/src/util/mobile-native-utils.test.ts +22 -0
  625. package/src/util/mobile-native-utils.ts +12 -0
  626. package/src/util/react-render.tsx +27 -0
  627. package/src/util/register-all-widgets-for-testing.ts +11 -0
  628. package/src/util/scroll-utils.ts +155 -0
  629. package/src/util/sizing-utils.ts +46 -0
  630. package/src/util/tex.ts +208 -0
  631. package/src/util/url-utils.ts +34 -0
  632. package/src/util.ts +1003 -0
  633. package/src/version.ts +11 -0
  634. package/src/widget-container.tsx +175 -0
  635. package/src/widgets/__stories__/categorizer.stories.tsx +14 -0
  636. package/src/widgets/__stories__/cs-program.stories.tsx +14 -0
  637. package/src/widgets/__stories__/definition.stories.tsx +111 -0
  638. package/src/widgets/__stories__/dropdown.stories.tsx +14 -0
  639. package/src/widgets/__stories__/explanation.stories.tsx +18 -0
  640. package/src/widgets/__stories__/expression.stories.tsx +29 -0
  641. package/src/widgets/__stories__/graded-group-set.stories.tsx +31 -0
  642. package/src/widgets/__stories__/graded-group.stories.tsx +31 -0
  643. package/src/widgets/__stories__/grapher.stories.tsx +60 -0
  644. package/src/widgets/__stories__/group.stories.tsx +14 -0
  645. package/src/widgets/__stories__/iframe.stories.tsx +14 -0
  646. package/src/widgets/__stories__/image.stories.tsx +61 -0
  647. package/src/widgets/__stories__/input-number.stories.tsx +110 -0
  648. package/src/widgets/__stories__/interaction.stories.tsx +14 -0
  649. package/src/widgets/__stories__/interactive-graph.stories.tsx +60 -0
  650. package/src/widgets/__stories__/matcher.stories.tsx +14 -0
  651. package/src/widgets/__stories__/matrix.stories.tsx +14 -0
  652. package/src/widgets/__stories__/number-line.stories.tsx +14 -0
  653. package/src/widgets/__stories__/numeric-input.stories.tsx +107 -0
  654. package/src/widgets/__stories__/on-screen-keypad.stories.tsx +120 -0
  655. package/src/widgets/__stories__/orderer.stories.tsx +14 -0
  656. package/src/widgets/__stories__/passage-ref.stories.tsx +22 -0
  657. package/src/widgets/__stories__/passage.stories.tsx +32 -0
  658. package/src/widgets/__stories__/radio.stories.tsx +88 -0
  659. package/src/widgets/__stories__/sorter.stories.tsx +14 -0
  660. package/src/widgets/__stories__/transformer.stories.tsx +14 -0
  661. package/src/widgets/__stories__/unit.stories.tsx +30 -0
  662. package/src/widgets/__stories__/video-transcript-link.stories.tsx +27 -0
  663. package/src/widgets/__stories__/video.stories.tsx +14 -0
  664. package/src/widgets/__testdata__/base-radio.testdata.ts +21 -0
  665. package/src/widgets/__testdata__/categorizer.testdata.ts +49 -0
  666. package/src/widgets/__testdata__/cs-program.testdata.ts +27 -0
  667. package/src/widgets/__testdata__/dropdown.testdata.ts +33 -0
  668. package/src/widgets/__testdata__/explanation.testdata.ts +55 -0
  669. package/src/widgets/__testdata__/expression.testdata.ts +94 -0
  670. package/src/widgets/__testdata__/graded-group-set.testdata.ts +356 -0
  671. package/src/widgets/__testdata__/graded-group.testdata.ts +77 -0
  672. package/src/widgets/__testdata__/grapher.testdata.ts +374 -0
  673. package/src/widgets/__testdata__/group.testdata.ts +155 -0
  674. package/src/widgets/__testdata__/iframe.testdata.ts +35 -0
  675. package/src/widgets/__testdata__/image.testdata.ts +36 -0
  676. package/src/widgets/__testdata__/input-number.testdata.ts +72 -0
  677. package/src/widgets/__testdata__/interaction.testdata.ts +262 -0
  678. package/src/widgets/__testdata__/interactive-graph.testdata.ts +644 -0
  679. package/src/widgets/__testdata__/matcher.testdata.ts +33 -0
  680. package/src/widgets/__testdata__/matrix.testdata.ts +28 -0
  681. package/src/widgets/__testdata__/number-line.testdata.ts +30 -0
  682. package/src/widgets/__testdata__/numeric-input.testdata.ts +266 -0
  683. package/src/widgets/__testdata__/orderer.testdata.ts +57 -0
  684. package/src/widgets/__testdata__/passage-ref.testdata.ts +101 -0
  685. package/src/widgets/__testdata__/passage.testdata.ts +95 -0
  686. package/src/widgets/__testdata__/radio.testdata.ts +261 -0
  687. package/src/widgets/__testdata__/sorter.testdata.ts +19 -0
  688. package/src/widgets/__testdata__/transformer.testdata.ts +108 -0
  689. package/src/widgets/__testdata__/video.testdata.ts +21 -0
  690. package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +497 -0
  691. package/src/widgets/__tests__/__snapshots__/unit.test.tsx.snap +20 -0
  692. package/src/widgets/__tests__/categorizer.test.ts +203 -0
  693. package/src/widgets/__tests__/cs-program.test.ts +43 -0
  694. package/src/widgets/__tests__/definition.test.ts +136 -0
  695. package/src/widgets/__tests__/dropdown.test.ts +105 -0
  696. package/src/widgets/__tests__/explanation.test.ts +198 -0
  697. package/src/widgets/__tests__/expression.test.ts +431 -0
  698. package/src/widgets/__tests__/graded-group-set-jipt.test.ts +30 -0
  699. package/src/widgets/__tests__/graded-group-set.test.ts +288 -0
  700. package/src/widgets/__tests__/graded-group.test.ts +232 -0
  701. package/src/widgets/__tests__/grapher.cypress.ts +576 -0
  702. package/src/widgets/__tests__/grapher.test.ts +33 -0
  703. package/src/widgets/__tests__/group.test.tsx +512 -0
  704. package/src/widgets/__tests__/iframe.test.ts +45 -0
  705. package/src/widgets/__tests__/image.test.ts +62 -0
  706. package/src/widgets/__tests__/input-number.test.ts +354 -0
  707. package/src/widgets/__tests__/interaction.test.ts +31 -0
  708. package/src/widgets/__tests__/interactive-graph.cypress.ts +815 -0
  709. package/src/widgets/__tests__/interactive-graph.test.ts +106 -0
  710. package/src/widgets/__tests__/matcher.test.tsx +152 -0
  711. package/src/widgets/__tests__/matrix.test.ts +82 -0
  712. package/src/widgets/__tests__/number-line.test.ts +79 -0
  713. package/src/widgets/__tests__/numeric-input.test.ts +502 -0
  714. package/src/widgets/__tests__/orderer.test.ts +73 -0
  715. package/src/widgets/__tests__/passage-ref.test.ts +168 -0
  716. package/src/widgets/__tests__/passage.test.tsx +224 -0
  717. package/src/widgets/__tests__/radio/base-radio.test.tsx +470 -0
  718. package/src/widgets/__tests__/radio/choice-icon.test.tsx +90 -0
  719. package/src/widgets/__tests__/radio/choice.test.tsx +310 -0
  720. package/src/widgets/__tests__/radio/focus-ring.test.tsx +23 -0
  721. package/src/widgets/__tests__/radio/option-status.test.tsx +77 -0
  722. package/src/widgets/__tests__/radio.test.ts +807 -0
  723. package/src/widgets/__tests__/renderQuestion.tsx +77 -0
  724. package/src/widgets/__tests__/unit.test.tsx +168 -0
  725. package/src/widgets/__tests__/video.test.ts +53 -0
  726. package/src/widgets/categorizer.tsx +343 -0
  727. package/src/widgets/cs-program.tsx +227 -0
  728. package/src/widgets/definition.tsx +121 -0
  729. package/src/widgets/dropdown.tsx +142 -0
  730. package/src/widgets/explanation.tsx +317 -0
  731. package/src/widgets/expression.tsx +647 -0
  732. package/src/widgets/graded-group-answer-bar.tsx +142 -0
  733. package/src/widgets/graded-group-set.tsx +296 -0
  734. package/src/widgets/graded-group.tsx +466 -0
  735. package/src/widgets/grapher/util.tsx +803 -0
  736. package/src/widgets/grapher.tsx +674 -0
  737. package/src/widgets/group.tsx +196 -0
  738. package/src/widgets/iframe.tsx +195 -0
  739. package/src/widgets/image.tsx +309 -0
  740. package/src/widgets/input-number.tsx +413 -0
  741. package/src/widgets/interaction/arrow-picker.tsx +38 -0
  742. package/src/widgets/interaction/color-picker.tsx +69 -0
  743. package/src/widgets/interaction/dash-picker.tsx +45 -0
  744. package/src/widgets/interaction/element-container.tsx +101 -0
  745. package/src/widgets/interaction.tsx +826 -0
  746. package/src/widgets/interactive-graph.tsx +2921 -0
  747. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +98 -0
  748. package/src/widgets/label-image/__stories__/marker.stories.tsx +181 -0
  749. package/src/widgets/label-image/answer-choices.tsx +300 -0
  750. package/src/widgets/label-image/marker.tsx +364 -0
  751. package/src/widgets/label-image/types.ts +26 -0
  752. package/src/widgets/label-image.test.ts +840 -0
  753. package/src/widgets/label-image.tsx +849 -0
  754. package/src/widgets/lights-puzzle.tsx +359 -0
  755. package/src/widgets/matcher.tsx +278 -0
  756. package/src/widgets/matrix.tsx +637 -0
  757. package/src/widgets/measurer.tsx +217 -0
  758. package/src/widgets/molecule/__tests__/layout.test.ts +162 -0
  759. package/src/widgets/molecule/__tests__/parser.test.ts +155 -0
  760. package/src/widgets/molecule/molecule-drawing.ts +173 -0
  761. package/src/widgets/molecule/molecule-layout.ts +362 -0
  762. package/src/widgets/molecule/smiles-parser.ts +296 -0
  763. package/src/widgets/molecule.tsx +172 -0
  764. package/src/widgets/number-line.tsx +864 -0
  765. package/src/widgets/numeric-input.tsx +563 -0
  766. package/src/widgets/orderer.tsx +788 -0
  767. package/src/widgets/passage/__tests__/passage-markdown.test.ts +376 -0
  768. package/src/widgets/passage/passage-markdown.tsx +475 -0
  769. package/src/widgets/passage-ref-target.tsx +73 -0
  770. package/src/widgets/passage-ref.tsx +215 -0
  771. package/src/widgets/passage.tsx +584 -0
  772. package/src/widgets/plotter.tsx +1204 -0
  773. package/src/widgets/radio/__stories__/base-radio.stories.tsx +204 -0
  774. package/src/widgets/radio/__stories__/choice-icon.stories.tsx +168 -0
  775. package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +40 -0
  776. package/src/widgets/radio/__stories__/choice.stories.tsx +137 -0
  777. package/src/widgets/radio/__stories__/focus-ring.stories.tsx +43 -0
  778. package/src/widgets/radio/__stories__/option-status.stories.tsx +105 -0
  779. package/src/widgets/radio/base-radio.tsx +509 -0
  780. package/src/widgets/radio/choice-a11y-text.ts +61 -0
  781. package/src/widgets/radio/choice-icon/choice-icon.tsx +217 -0
  782. package/src/widgets/radio/choice-icon/cross-out-line.tsx +53 -0
  783. package/src/widgets/radio/choice-icon/shared-styles.ts +15 -0
  784. package/src/widgets/radio/choice-none-above.tsx +56 -0
  785. package/src/widgets/radio/choice.jsx.fixture.ts +45 -0
  786. package/src/widgets/radio/choice.tsx +358 -0
  787. package/src/widgets/radio/focus-ring.tsx +57 -0
  788. package/src/widgets/radio/option-status.tsx +100 -0
  789. package/src/widgets/radio/util.test.ts +18 -0
  790. package/src/widgets/radio/util.ts +31 -0
  791. package/src/widgets/radio/widget.tsx +521 -0
  792. package/src/widgets/radio.ts +157 -0
  793. package/src/widgets/reaction-diagram.tsx +144 -0
  794. package/src/widgets/sequence.tsx +137 -0
  795. package/src/widgets/simulator.tsx +831 -0
  796. package/src/widgets/sorter.tsx +154 -0
  797. package/src/widgets/table.tsx +393 -0
  798. package/src/widgets/transformer.tsx +2951 -0
  799. package/src/widgets/unit.tsx +374 -0
  800. package/src/widgets/video-transcript-link.test.tsx +213 -0
  801. package/src/widgets/video-transcript-link.tsx +84 -0
  802. package/src/widgets/video.tsx +124 -0
  803. package/src/widgets.ts +444 -0
  804. package/src/zoom.ts +558 -0
  805. package/tsconfig.json +25 -0
  806. package/tsconfig.tsbuildinfo +1 -0
  807. package/src/__stories__/hints-renderer.stories.jsx +0 -60
  808. package/src/__stories__/item-renderer.stories.jsx +0 -27
  809. package/src/__stories__/server-item-renderer.stories.jsx +0 -27
  810. package/src/__testdata__/graphie_testdata.js +0 -53
  811. package/src/__testdata__/item-renderer_testdata.js +0 -161
  812. package/src/__testdata__/renderer_testdata.js +0 -123
  813. package/src/__tests__/a11y_test.jsx +0 -304
  814. package/src/__tests__/item-renderer_test.jsx +0 -892
  815. package/src/__tests__/jipt-paragraphs_test.js +0 -34
  816. package/src/__tests__/mock-asset-loading-widget.jsx +0 -57
  817. package/src/__tests__/mock-widget.jsx +0 -35
  818. package/src/__tests__/perseus-markdown_test.jsx +0 -747
  819. package/src/__tests__/renderability_test.jsx +0 -481
  820. package/src/__tests__/renderer-api_test.jsx +0 -309
  821. package/src/__tests__/renderer_test.jsx +0 -1792
  822. package/src/__tests__/server-item-renderer_test.jsx +0 -516
  823. package/src/__tests__/test-items/image-item.js +0 -25
  824. package/src/__tests__/test-items/input-number-1-item.js +0 -27
  825. package/src/__tests__/test-items/input-number-2-item.js +0 -39
  826. package/src/__tests__/test-items/table-item.js +0 -30
  827. package/src/__tests__/tex-wrangler_test.js +0 -83
  828. package/src/__tests__/util_test.js +0 -41
  829. package/src/a11y.js +0 -46
  830. package/src/all-widgets.js +0 -9
  831. package/src/article-renderer.jsx +0 -214
  832. package/src/asset-context.js +0 -30
  833. package/src/basic-widgets.js +0 -13
  834. package/src/components/__stories__/button-group.stories.jsx +0 -61
  835. package/src/components/__stories__/fixed-to-responsive.stories.jsx +0 -132
  836. package/src/components/__stories__/graph.stories.jsx +0 -27
  837. package/src/components/__stories__/graphie.stories.jsx +0 -32
  838. package/src/components/__stories__/hud.stories.jsx +0 -36
  839. package/src/components/__stories__/icon.stories.jsx +0 -56
  840. package/src/components/__stories__/image-loader.stories.jsx +0 -60
  841. package/src/components/__stories__/info-tip.stories.jsx +0 -33
  842. package/src/components/__stories__/inline-icon.stories.jsx +0 -39
  843. package/src/components/__stories__/input-with-examples.stories.jsx +0 -52
  844. package/src/components/__stories__/lint.stories.jsx +0 -40
  845. package/src/components/__stories__/math-input.stories.jsx +0 -29
  846. package/src/components/__stories__/math-output.stories.jsx +0 -24
  847. package/src/components/__stories__/multi-button-group.stories.jsx +0 -69
  848. package/src/components/__stories__/number-input.stories.jsx +0 -42
  849. package/src/components/__stories__/prop-check-box.stories.jsx +0 -62
  850. package/src/components/__stories__/range-input.stories.jsx +0 -28
  851. package/src/components/__stories__/simple-keypad-input.stories.jsx +0 -28
  852. package/src/components/__stories__/sortable.stories.jsx +0 -73
  853. package/src/components/__stories__/stub-tag-editor.stories.jsx +0 -44
  854. package/src/components/__stories__/svg-image.stories.jsx +0 -71
  855. package/src/components/__stories__/tex.stories.jsx +0 -24
  856. package/src/components/__stories__/text-buttons.stories.jsx +0 -51
  857. package/src/components/__stories__/text-input.stories.jsx +0 -34
  858. package/src/components/__stories__/text-list-editor.stories.jsx +0 -33
  859. package/src/components/__stories__/zoomable-tex.stories.jsx +0 -39
  860. package/src/components/__stories__/zoomable.stories.jsx +0 -40
  861. package/src/components/__testdata__/sorter_testdata.js +0 -20
  862. package/src/components/__tests__/number-input_test.jsx +0 -112
  863. package/src/components/__tests__/sortable_test.jsx +0 -234
  864. package/src/components/__tests__/sorter_test.jsx +0 -111
  865. package/src/components/__tests__/zoomable_test.jsx +0 -388
  866. package/src/components/button-group.jsx +0 -131
  867. package/src/components/constants.js +0 -15
  868. package/src/components/fixed-to-responsive.jsx +0 -165
  869. package/src/components/graph.jsx +0 -413
  870. package/src/components/graphie-classes.jsx +0 -148
  871. package/src/components/graphie-movables.jsx +0 -342
  872. package/src/components/graphie.jsx +0 -353
  873. package/src/components/highlighting/highlightable-content.jsx +0 -245
  874. package/src/components/highlighting/highlights.js +0 -208
  875. package/src/components/highlighting/ranges.js +0 -299
  876. package/src/components/highlighting/types.js +0 -73
  877. package/src/components/highlighting/ui/highlight-renderer.jsx +0 -179
  878. package/src/components/highlighting/ui/highlight-set-renderer.jsx +0 -190
  879. package/src/components/highlighting/ui/highlight-tooltip.jsx +0 -143
  880. package/src/components/highlighting/ui/highlighting-ui.jsx +0 -163
  881. package/src/components/highlighting/ui/selection-tracker.jsx +0 -184
  882. package/src/components/highlighting/ui/types.js +0 -21
  883. package/src/components/highlighting/ui/util.js +0 -166
  884. package/src/components/highlighting/word-indexer.jsx +0 -155
  885. package/src/components/hud.jsx +0 -179
  886. package/src/components/icon.jsx +0 -149
  887. package/src/components/image-loader.jsx +0 -175
  888. package/src/components/info-tip/info-tip.jsx +0 -146
  889. package/src/components/info-tip.jsx +0 -38
  890. package/src/components/inline-icon.jsx +0 -81
  891. package/src/components/input-with-examples.jsx +0 -248
  892. package/src/components/lint.jsx +0 -455
  893. package/src/components/math-input.jsx +0 -293
  894. package/src/components/math-output.jsx +0 -128
  895. package/src/components/multi-button-group.jsx +0 -137
  896. package/src/components/number-input.jsx +0 -253
  897. package/src/components/prop-check-box.jsx +0 -80
  898. package/src/components/range-input.jsx +0 -61
  899. package/src/components/simple-keypad-input.jsx +0 -88
  900. package/src/components/sortable.jsx +0 -872
  901. package/src/components/stub-tag-editor.jsx +0 -54
  902. package/src/components/svg-image.jsx +0 -765
  903. package/src/components/tex-buttons.jsx +0 -320
  904. package/src/components/tex.jsx +0 -70
  905. package/src/components/text-input.jsx +0 -133
  906. package/src/components/text-list-editor.jsx +0 -157
  907. package/src/components/tooltip.jsx +0 -392
  908. package/src/components/visibility-observer/__stories__/visibility-observer.stories.jsx +0 -140
  909. package/src/components/visibility-observer/get-scroll-parent.js +0 -45
  910. package/src/components/visibility-observer/visibility-observer.js +0 -109
  911. package/src/components/visibility-observer/visibility-observer.jsx +0 -123
  912. package/src/components/zoomable-tex.jsx +0 -70
  913. package/src/components/zoomable.jsx +0 -294
  914. package/src/components.js +0 -17
  915. package/src/definition-context.js +0 -59
  916. package/src/dependencies.js +0 -22
  917. package/src/error-boundary.jsx +0 -48
  918. package/src/extra-widgets.js +0 -75
  919. package/src/hint-renderer.jsx +0 -155
  920. package/src/hints-renderer.jsx +0 -367
  921. package/src/icon-paths.js +0 -120
  922. package/src/index.js +0 -159
  923. package/src/init.js +0 -49
  924. package/src/interaction-tracker.js +0 -60
  925. package/src/interactive2/__tests__/movable-mock.js +0 -48
  926. package/src/interactive2/__tests__/movable-point_test.js +0 -146
  927. package/src/interactive2/interactive-util.js +0 -152
  928. package/src/interactive2/movable-helper-methods.js +0 -160
  929. package/src/interactive2/movable-line-options.js +0 -392
  930. package/src/interactive2/movable-line.js +0 -322
  931. package/src/interactive2/movable-point-options.js +0 -190
  932. package/src/interactive2/movable-point.jsx +0 -597
  933. package/src/interactive2/movable-polygon-options.js +0 -351
  934. package/src/interactive2/movable-polygon.js +0 -368
  935. package/src/interactive2/movable.js +0 -273
  936. package/src/interactive2/objective_.js +0 -79
  937. package/src/interactive2/types.js +0 -3
  938. package/src/interactive2/wrapped-defaults.js +0 -86
  939. package/src/interactive2/wrapped-ellipse.js +0 -86
  940. package/src/interactive2/wrapped-line.js +0 -109
  941. package/src/interactive2/wrapped-path.js +0 -47
  942. package/src/interactive2.js +0 -91
  943. package/src/item-renderer.jsx +0 -514
  944. package/src/item-version.js +0 -12
  945. package/src/jipt-paragraphs.js +0 -52
  946. package/src/keypad-context.js +0 -33
  947. package/src/loading-context.js +0 -20
  948. package/src/logging/log.js +0 -107
  949. package/src/logging/log_test.js +0 -41
  950. package/src/mixins/__tests__/widget-prop-denylist_test.js +0 -23
  951. package/src/mixins/changeable.jsx +0 -115
  952. package/src/mixins/editor-jsonify.jsx +0 -13
  953. package/src/mixins/provide-keypad.jsx +0 -131
  954. package/src/mixins/widget-jsonify-deprecated.jsx +0 -23
  955. package/src/mixins/widget-prop-denylist.js +0 -49
  956. package/src/multi-items/__stories__/multi-renderer.stories.js +0 -88
  957. package/src/multi-items/__testdata__/multi-renderer_testdata.js +0 -174
  958. package/src/multi-items/__tests__/items_test.js +0 -245
  959. package/src/multi-items/__tests__/multi-renderer_test.js +0 -903
  960. package/src/multi-items/__tests__/prop-type-builders_test.js +0 -134
  961. package/src/multi-items/__tests__/shapes_test.js +0 -44
  962. package/src/multi-items/__tests__/trees_test.js +0 -316
  963. package/src/multi-items/items.js +0 -176
  964. package/src/multi-items/multi-renderer.jsx +0 -543
  965. package/src/multi-items/prop-type-builders.js +0 -105
  966. package/src/multi-items/shape-types.js +0 -47
  967. package/src/multi-items/shapes.js +0 -53
  968. package/src/multi-items/tree-types.js +0 -42
  969. package/src/multi-items/trees.js +0 -345
  970. package/src/multi-items.js +0 -76
  971. package/src/perseus-api.jsx +0 -221
  972. package/src/perseus-env.js +0 -26
  973. package/src/perseus-error.js +0 -19
  974. package/src/perseus-markdown.jsx +0 -408
  975. package/src/perseus-types.js +0 -1471
  976. package/src/question-paragraph.jsx +0 -30
  977. package/src/renderability.jsx +0 -108
  978. package/src/renderer.jsx +0 -1937
  979. package/src/server-item-renderer.jsx +0 -467
  980. package/src/sigfigs.jsx +0 -492
  981. package/src/styles/constants.js +0 -96
  982. package/src/styles/global-constants.js +0 -344
  983. package/src/styles/global-styles.js +0 -307
  984. package/src/styles/media-queries.js +0 -48
  985. package/src/styles/shared.js +0 -132
  986. package/src/tex-wrangler.js +0 -176
  987. package/src/translation-linter.js +0 -125
  988. package/src/traversal.jsx +0 -141
  989. package/src/types.js +0 -488
  990. package/src/util/a11y.js +0 -24
  991. package/src/util/answer-types.js +0 -861
  992. package/src/util/answer-types_test.js +0 -115
  993. package/src/util/colors.js +0 -94
  994. package/src/util/fix-passage-refs.jsx +0 -122
  995. package/src/util/graph-utils.js +0 -16
  996. package/src/util/graphie.js +0 -1586
  997. package/src/util/interactive.js +0 -4078
  998. package/src/util/katex-preprocess.js +0 -16
  999. package/src/util/math.js +0 -289
  1000. package/src/util/mobile-native-utils.js +0 -14
  1001. package/src/util/mobile-native-utils_test.js +0 -24
  1002. package/src/util/react-render.js +0 -27
  1003. package/src/util/register-all-widgets-for-testing.js +0 -12
  1004. package/src/util/scroll-utils.js +0 -162
  1005. package/src/util/sizing-utils.js +0 -46
  1006. package/src/util/tex.js +0 -203
  1007. package/src/util/url-utils.js +0 -36
  1008. package/src/util.js +0 -984
  1009. package/src/version.js +0 -11
  1010. package/src/widget-container.jsx +0 -178
  1011. package/src/widgets/__stories__/categorizer.stories.jsx +0 -15
  1012. package/src/widgets/__stories__/cs-program.stories.jsx +0 -15
  1013. package/src/widgets/__stories__/definition.stories.jsx +0 -108
  1014. package/src/widgets/__stories__/dropdown.stories.jsx +0 -15
  1015. package/src/widgets/__stories__/explanation.stories.jsx +0 -19
  1016. package/src/widgets/__stories__/expression.stories.jsx +0 -26
  1017. package/src/widgets/__stories__/graded-group-set.stories.jsx +0 -32
  1018. package/src/widgets/__stories__/graded-group.stories.jsx +0 -32
  1019. package/src/widgets/__stories__/grapher.stories.jsx +0 -47
  1020. package/src/widgets/__stories__/group.stories.jsx +0 -15
  1021. package/src/widgets/__stories__/iframe.stories.jsx +0 -15
  1022. package/src/widgets/__stories__/image.stories.jsx +0 -62
  1023. package/src/widgets/__stories__/input-number.stories.jsx +0 -102
  1024. package/src/widgets/__stories__/interaction.stories.jsx +0 -15
  1025. package/src/widgets/__stories__/interactive-graph.stories.jsx +0 -61
  1026. package/src/widgets/__stories__/matcher.stories.jsx +0 -15
  1027. package/src/widgets/__stories__/matrix.stories.jsx +0 -15
  1028. package/src/widgets/__stories__/number-line.stories.jsx +0 -15
  1029. package/src/widgets/__stories__/numeric-input.stories.jsx +0 -106
  1030. package/src/widgets/__stories__/on-screen-keypad.stories.jsx +0 -118
  1031. package/src/widgets/__stories__/orderer.stories.jsx +0 -15
  1032. package/src/widgets/__stories__/passage-ref.stories.jsx +0 -23
  1033. package/src/widgets/__stories__/passage.stories.jsx +0 -27
  1034. package/src/widgets/__stories__/radio.stories.jsx +0 -90
  1035. package/src/widgets/__stories__/sorter.stories.jsx +0 -15
  1036. package/src/widgets/__stories__/transformer.stories.jsx +0 -15
  1037. package/src/widgets/__stories__/unit.stories.jsx +0 -45
  1038. package/src/widgets/__stories__/video-transcript-link.stories.jsx +0 -24
  1039. package/src/widgets/__stories__/video.stories.jsx +0 -15
  1040. package/src/widgets/__testdata__/base-radio_testdata.js +0 -22
  1041. package/src/widgets/__testdata__/categorizer_testdata.js +0 -50
  1042. package/src/widgets/__testdata__/cs-program_testdata.js +0 -28
  1043. package/src/widgets/__testdata__/dropdown_testdata.js +0 -34
  1044. package/src/widgets/__testdata__/explanation_testdata.js +0 -56
  1045. package/src/widgets/__testdata__/expression_testdata.js +0 -95
  1046. package/src/widgets/__testdata__/graded-group-set_testdata.js +0 -358
  1047. package/src/widgets/__testdata__/graded-group_testdata.js +0 -79
  1048. package/src/widgets/__testdata__/grapher_testdata.js +0 -376
  1049. package/src/widgets/__testdata__/group_testdata.js +0 -156
  1050. package/src/widgets/__testdata__/iframe_testdata.js +0 -36
  1051. package/src/widgets/__testdata__/image_testdata.js +0 -38
  1052. package/src/widgets/__testdata__/input-number_testdata.js +0 -73
  1053. package/src/widgets/__testdata__/interaction_testdata.js +0 -264
  1054. package/src/widgets/__testdata__/interactive-graph_testdata.js +0 -646
  1055. package/src/widgets/__testdata__/matcher_testdata.js +0 -34
  1056. package/src/widgets/__testdata__/matrix_testdata.js +0 -29
  1057. package/src/widgets/__testdata__/number-line_testdata.js +0 -31
  1058. package/src/widgets/__testdata__/numeric-input_testdata.js +0 -266
  1059. package/src/widgets/__testdata__/orderer_testdata.js +0 -58
  1060. package/src/widgets/__testdata__/passage-ref_testdata.js +0 -103
  1061. package/src/widgets/__testdata__/passage_testdata.js +0 -96
  1062. package/src/widgets/__testdata__/radio_testdata.js +0 -262
  1063. package/src/widgets/__testdata__/sorter_testdata.js +0 -20
  1064. package/src/widgets/__testdata__/transformer_testdata.js +0 -109
  1065. package/src/widgets/__testdata__/video_testdata.js +0 -22
  1066. package/src/widgets/__tests__/__snapshots__/expression_test.jsx.snap +0 -38
  1067. package/src/widgets/__tests__/__snapshots__/input-number_test.jsx.snap +0 -978
  1068. package/src/widgets/__tests__/categorizer_test.jsx +0 -205
  1069. package/src/widgets/__tests__/cs-program_test.jsx +0 -45
  1070. package/src/widgets/__tests__/definition_test.js +0 -137
  1071. package/src/widgets/__tests__/dropdown_test.jsx +0 -106
  1072. package/src/widgets/__tests__/explanation_test.js +0 -199
  1073. package/src/widgets/__tests__/expression_test.jsx +0 -439
  1074. package/src/widgets/__tests__/graded-group-set-jipt_test.jsx +0 -32
  1075. package/src/widgets/__tests__/graded-group-set_test.jsx +0 -290
  1076. package/src/widgets/__tests__/graded-group_test.jsx +0 -233
  1077. package/src/widgets/__tests__/grapher.cypress.jsx +0 -546
  1078. package/src/widgets/__tests__/grapher_test.jsx +0 -35
  1079. package/src/widgets/__tests__/group_test.jsx +0 -512
  1080. package/src/widgets/__tests__/iframe_test.jsx +0 -47
  1081. package/src/widgets/__tests__/image_test.jsx +0 -65
  1082. package/src/widgets/__tests__/input-number_test.jsx +0 -360
  1083. package/src/widgets/__tests__/interaction_test.jsx +0 -33
  1084. package/src/widgets/__tests__/interactive-graph.cypress.jsx +0 -777
  1085. package/src/widgets/__tests__/interactive-graph_test.jsx +0 -105
  1086. package/src/widgets/__tests__/matcher_test.jsx +0 -157
  1087. package/src/widgets/__tests__/matrix_test.jsx +0 -84
  1088. package/src/widgets/__tests__/number-line_test.jsx +0 -81
  1089. package/src/widgets/__tests__/numeric-input_test.jsx +0 -514
  1090. package/src/widgets/__tests__/orderer_test.jsx +0 -75
  1091. package/src/widgets/__tests__/passage-ref_test.jsx +0 -166
  1092. package/src/widgets/__tests__/passage_test.jsx +0 -212
  1093. package/src/widgets/__tests__/radio/base-radio_test.jsx +0 -443
  1094. package/src/widgets/__tests__/radio/choice-icon_test.jsx +0 -91
  1095. package/src/widgets/__tests__/radio/choice_test.jsx +0 -311
  1096. package/src/widgets/__tests__/radio/focus-ring_test.jsx +0 -23
  1097. package/src/widgets/__tests__/radio/option-status_test.jsx +0 -65
  1098. package/src/widgets/__tests__/radio_test.jsx +0 -810
  1099. package/src/widgets/__tests__/renderQuestion.jsx +0 -66
  1100. package/src/widgets/__tests__/unit_test.jsx +0 -144
  1101. package/src/widgets/__tests__/video_test.jsx +0 -55
  1102. package/src/widgets/categorizer.jsx +0 -343
  1103. package/src/widgets/cs-program.jsx +0 -227
  1104. package/src/widgets/definition.jsx +0 -121
  1105. package/src/widgets/dropdown.jsx +0 -141
  1106. package/src/widgets/explanation.jsx +0 -315
  1107. package/src/widgets/expression.jsx +0 -652
  1108. package/src/widgets/graded-group-answer-bar.jsx +0 -152
  1109. package/src/widgets/graded-group-set.jsx +0 -296
  1110. package/src/widgets/graded-group.jsx +0 -453
  1111. package/src/widgets/grapher/util.jsx +0 -806
  1112. package/src/widgets/grapher.jsx +0 -663
  1113. package/src/widgets/group.jsx +0 -195
  1114. package/src/widgets/iframe.jsx +0 -198
  1115. package/src/widgets/image.jsx +0 -310
  1116. package/src/widgets/input-number.jsx +0 -412
  1117. package/src/widgets/interaction/arrow-picker.jsx +0 -39
  1118. package/src/widgets/interaction/color-picker.jsx +0 -69
  1119. package/src/widgets/interaction/dash-picker.jsx +0 -46
  1120. package/src/widgets/interaction/element-container.jsx +0 -97
  1121. package/src/widgets/interaction.jsx +0 -742
  1122. package/src/widgets/interactive-graph.jsx +0 -2820
  1123. package/src/widgets/label-image/__stories__/answer-choices.stories.jsx +0 -93
  1124. package/src/widgets/label-image/__stories__/marker.stories.jsx +0 -172
  1125. package/src/widgets/label-image/answer-choices.jsx +0 -311
  1126. package/src/widgets/label-image/marker.jsx +0 -365
  1127. package/src/widgets/label-image/types.js +0 -33
  1128. package/src/widgets/label-image.jsx +0 -841
  1129. package/src/widgets/label-image_test.js +0 -840
  1130. package/src/widgets/lights-puzzle.jsx +0 -356
  1131. package/src/widgets/matcher.jsx +0 -274
  1132. package/src/widgets/matrix.jsx +0 -632
  1133. package/src/widgets/measurer.jsx +0 -215
  1134. package/src/widgets/molecule/__tests__/layout_test.jsx +0 -159
  1135. package/src/widgets/molecule/__tests__/parser_test.jsx +0 -142
  1136. package/src/widgets/molecule/molecule-drawing.jsx +0 -175
  1137. package/src/widgets/molecule/molecule-layout.jsx +0 -367
  1138. package/src/widgets/molecule/smiles-parser.jsx +0 -300
  1139. package/src/widgets/molecule.jsx +0 -172
  1140. package/src/widgets/number-line.jsx +0 -858
  1141. package/src/widgets/numeric-input.jsx +0 -553
  1142. package/src/widgets/orderer.jsx +0 -756
  1143. package/src/widgets/passage/__tests__/passage-markdown_test.jsx +0 -373
  1144. package/src/widgets/passage/passage-markdown.jsx +0 -472
  1145. package/src/widgets/passage-ref-target.jsx +0 -73
  1146. package/src/widgets/passage-ref.jsx +0 -214
  1147. package/src/widgets/passage.jsx +0 -576
  1148. package/src/widgets/plotter.jsx +0 -1198
  1149. package/src/widgets/radio/__stories__/base-radio.stories.jsx +0 -189
  1150. package/src/widgets/radio/__stories__/choice-icon.stories.jsx +0 -166
  1151. package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +0 -41
  1152. package/src/widgets/radio/__stories__/choice.stories.jsx +0 -138
  1153. package/src/widgets/radio/__stories__/focus-ring.stories.jsx +0 -44
  1154. package/src/widgets/radio/__stories__/option-status.stories.jsx +0 -104
  1155. package/src/widgets/radio/base-radio.jsx +0 -494
  1156. package/src/widgets/radio/choice-a11y-text.js +0 -62
  1157. package/src/widgets/radio/choice-icon/choice-icon.jsx +0 -214
  1158. package/src/widgets/radio/choice-icon/cross-out-line.jsx +0 -52
  1159. package/src/widgets/radio/choice-icon/shared-styles.js +0 -16
  1160. package/src/widgets/radio/choice-none-above.jsx +0 -63
  1161. package/src/widgets/radio/choice.jsx +0 -382
  1162. package/src/widgets/radio/choice.jsx.fixture.js +0 -46
  1163. package/src/widgets/radio/focus-ring.jsx +0 -58
  1164. package/src/widgets/radio/option-status.jsx +0 -98
  1165. package/src/widgets/radio/util.js +0 -32
  1166. package/src/widgets/radio/util_test.js +0 -19
  1167. package/src/widgets/radio/widget.jsx +0 -515
  1168. package/src/widgets/radio.jsx +0 -155
  1169. package/src/widgets/reaction-diagram.jsx +0 -137
  1170. package/src/widgets/sequence.jsx +0 -143
  1171. package/src/widgets/simulator.jsx +0 -806
  1172. package/src/widgets/sorter.jsx +0 -149
  1173. package/src/widgets/table.jsx +0 -397
  1174. package/src/widgets/transformer.jsx +0 -2876
  1175. package/src/widgets/unit.jsx +0 -372
  1176. package/src/widgets/video-transcript-link.jsx +0 -84
  1177. package/src/widgets/video-transcript-link_test.js +0 -211
  1178. package/src/widgets/video.jsx +0 -126
  1179. package/src/widgets.js +0 -431
  1180. package/src/zoom.js +0 -539
  1181. /package/{src/multi-items/item-types.js → dist/multi-items/item-types.js.flow} +0 -0
  1182. /package/dist/{strings.js → strings} +0 -0
  1183. /package/src/__tests__/__snapshots__/{item-renderer_test.jsx.snap → item-renderer.test.tsx.snap} +0 -0
  1184. /package/src/__tests__/__snapshots__/{perseus-markdown_test.jsx.snap → perseus-markdown.test.ts.snap} +0 -0
  1185. /package/src/__tests__/__snapshots__/{renderer_test.jsx.snap → renderer.test.tsx.snap} +0 -0
  1186. /package/src/__tests__/__snapshots__/{server-item-renderer_test.jsx.snap → server-item-renderer.test.tsx.snap} +0 -0
  1187. /package/src/components/__tests__/__snapshots__/{sortable_test.jsx.snap → sortable.test.tsx.snap} +0 -0
  1188. /package/src/components/__tests__/__snapshots__/{sorter_test.jsx.snap → sorter.test.tsx.snap} +0 -0
  1189. /package/src/multi-items/__tests__/__snapshots__/{multi-renderer_test.js.snap → multi-renderer.test.tsx.snap} +0 -0
  1190. /package/src/widgets/__tests__/__snapshots__/{categorizer_test.jsx.snap → categorizer.test.ts.snap} +0 -0
  1191. /package/src/widgets/__tests__/__snapshots__/{cs-program_test.jsx.snap → cs-program.test.ts.snap} +0 -0
  1192. /package/src/widgets/__tests__/__snapshots__/{definition_test.js.snap → definition.test.ts.snap} +0 -0
  1193. /package/src/widgets/__tests__/__snapshots__/{dropdown_test.jsx.snap → dropdown.test.ts.snap} +0 -0
  1194. /package/src/widgets/__tests__/__snapshots__/{explanation_test.js.snap → explanation.test.ts.snap} +0 -0
  1195. /package/src/widgets/__tests__/__snapshots__/{graded-group-set-jipt_test.jsx.snap → graded-group-set-jipt.test.ts.snap} +0 -0
  1196. /package/src/widgets/__tests__/__snapshots__/{graded-group-set_test.jsx.snap → graded-group-set.test.ts.snap} +0 -0
  1197. /package/src/widgets/__tests__/__snapshots__/{graded-group_test.jsx.snap → graded-group.test.ts.snap} +0 -0
  1198. /package/src/widgets/__tests__/__snapshots__/{grapher_test.jsx.snap → grapher.test.ts.snap} +0 -0
  1199. /package/src/widgets/__tests__/__snapshots__/{group_test.jsx.snap → group.test.tsx.snap} +0 -0
  1200. /package/src/widgets/__tests__/__snapshots__/{iframe_test.jsx.snap → iframe.test.ts.snap} +0 -0
  1201. /package/src/widgets/__tests__/__snapshots__/{image_test.jsx.snap → image.test.ts.snap} +0 -0
  1202. /package/src/widgets/__tests__/__snapshots__/{interaction_test.jsx.snap → interaction.test.ts.snap} +0 -0
  1203. /package/src/widgets/__tests__/__snapshots__/{interactive-graph_test.jsx.snap → interactive-graph.test.ts.snap} +0 -0
  1204. /package/src/widgets/__tests__/__snapshots__/{matcher_test.jsx.snap → matcher.test.tsx.snap} +0 -0
  1205. /package/src/widgets/__tests__/__snapshots__/{matrix_test.jsx.snap → matrix.test.ts.snap} +0 -0
  1206. /package/src/widgets/__tests__/__snapshots__/{number-line_test.jsx.snap → number-line.test.ts.snap} +0 -0
  1207. /package/src/widgets/__tests__/__snapshots__/{numeric-input_test.jsx.snap → numeric-input.test.ts.snap} +0 -0
  1208. /package/src/widgets/__tests__/__snapshots__/{orderer_test.jsx.snap → orderer.test.ts.snap} +0 -0
  1209. /package/src/widgets/__tests__/__snapshots__/{passage-ref_test.jsx.snap → passage-ref.test.ts.snap} +0 -0
  1210. /package/src/widgets/__tests__/__snapshots__/{passage_test.jsx.snap → passage.test.tsx.snap} +0 -0
  1211. /package/src/widgets/__tests__/__snapshots__/{radio_test.jsx.snap → radio.test.ts.snap} +0 -0
  1212. /package/src/widgets/__tests__/__snapshots__/{video_test.jsx.snap → video.test.ts.snap} +0 -0
@@ -1,1792 +0,0 @@
1
- // @flow
2
-
3
- import {screen, waitFor, within} from "@testing-library/react";
4
- import userEvent from "@testing-library/user-event";
5
- import * as React from "react";
6
-
7
- import "@testing-library/jest-dom"; // Imports custom matchers
8
-
9
- import {clone} from "../../../../testing/object-utils.js";
10
- import {testDependencies} from "../../../../testing/test-dependencies.js";
11
- import {
12
- dropdownWidget,
13
- imageWidget,
14
- inputNumberWidget,
15
- question1,
16
- question2,
17
- mockedItem,
18
- } from "../__testdata__/renderer_testdata.js";
19
- import * as Dependencies from "../dependencies.js";
20
- import {Errors} from "../logging/log.js";
21
- import {registerWidget} from "../widgets.js";
22
- import {renderQuestion} from "../widgets/__tests__/renderQuestion.jsx";
23
- import InputNumberExport from "../widgets/input-number.jsx";
24
- import RadioWidgetExport from "../widgets/radio.jsx";
25
-
26
- import MockWidgetExport from "./mock-widget.jsx";
27
-
28
- import type {
29
- DropdownWidget,
30
- PerseusImageWidgetOptions,
31
- PerseusInputNumberWidgetOptions,
32
- } from "../perseus-types.js";
33
-
34
- // NOTE(jeremy): We can't use an automatic mock for the translation linter,
35
- // because one of it's "instance" methods is created using `debounce` and Jest
36
- // doesn't provide a mocked instance method for it (I suspect that Jest doesn't
37
- // see that symbol as an instance method).
38
- const mockRunLinter = jest.fn();
39
- const mockApplyLintErrors = jest.fn();
40
- jest.mock("../translation-linter.js", () => {
41
- // We mock the TranslationLinter constructor here setting things up so we
42
- // can spy/verify calls to instances of TranslationLinter
43
- return function () {
44
- return {
45
- runLinter: mockRunLinter,
46
- applyLintErrors: mockApplyLintErrors,
47
- };
48
- };
49
- });
50
-
51
- describe("renderer", () => {
52
- beforeAll(() => {
53
- registerWidget("input-number", InputNumberExport);
54
- registerWidget("radio", RadioWidgetExport);
55
- registerWidget("mock-widget", MockWidgetExport);
56
- });
57
-
58
- beforeEach(() => {
59
- jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
60
- testDependencies,
61
- );
62
- });
63
-
64
- afterEach(() => {
65
- // The Renderer uses a timer to wait for widgets to complete rendering.
66
- // If we don't spin the timers here, then the timer fires in the test
67
- // _after_ and breaks it because we do setState() in the callback,
68
- // and by that point the component has been unmounted.
69
- jest.runOnlyPendingTimers();
70
- jest.clearAllMocks();
71
- });
72
-
73
- describe("snapshots", () => {
74
- it("initial render", () => {
75
- // Arrange and Act
76
- const {container} = renderQuestion(question1);
77
-
78
- // Assert
79
- expect(container).toMatchSnapshot("initial render");
80
- });
81
-
82
- it("correct answer", () => {
83
- // Arrange
84
- const {container} = renderQuestion(question1);
85
-
86
- // Act
87
- userEvent.click(screen.getByRole("button"));
88
- userEvent.click(screen.getAllByRole("option")[2]);
89
- jest.runOnlyPendingTimers();
90
-
91
- // Assert
92
- expect(container).toMatchSnapshot("correct answer");
93
- });
94
-
95
- it("incorrect answer", () => {
96
- // Arrange
97
- const {container} = renderQuestion(question1);
98
-
99
- // Act
100
- userEvent.click(screen.getByRole("button"));
101
- userEvent.click(screen.getAllByRole("option")[1]);
102
- jest.runOnlyPendingTimers();
103
-
104
- // Assert
105
- expect(container).toMatchSnapshot("incorrect answer");
106
- });
107
- });
108
-
109
- describe("linting (TranslationLinter)", () => {
110
- const extraProps = {
111
- linterContext: {
112
- contentType: "exercise",
113
- highlightLint: true,
114
- // TODO(CP-4838): is it okay to use [] as a default?
115
- paths: [],
116
- stack: [],
117
- },
118
- };
119
-
120
- it("should run the linter on mount", () => {
121
- // Arrange and Act
122
- renderQuestion(question1, {}, extraProps);
123
-
124
- // Assert
125
- expect(mockRunLinter).toHaveBeenCalledWith(
126
- "The total number of boxes the forklift can carry is [[☃ dropdown 1]] $60$.",
127
- expect.any(Function),
128
- );
129
- });
130
-
131
- it("should do nothing in linter callback if component is already unmounted", () => {
132
- // Arrange
133
- const {unmount} = renderQuestion(question1, {}, extraProps);
134
- unmount();
135
- mockApplyLintErrors.mockClear();
136
-
137
- // Act - Call the linter callback
138
- // `.calls` is an array of calls to this mock.
139
- // Each call is an array of the parameters passed to that call.
140
- // So `[0][1]` is the first call's second parameter.
141
- mockRunLinter.mock.calls[0][1]([]);
142
-
143
- // Assert
144
- expect(mockApplyLintErrors).not.toHaveBeenCalled();
145
- });
146
-
147
- it("should run linter on update", () => {
148
- // Arrange
149
- const {rerender} = renderQuestion(question1, {}, extraProps);
150
-
151
- mockRunLinter.mockClear();
152
-
153
- // Act
154
- rerender(question1, {...extraProps, problemNum: 1});
155
-
156
- // Assert
157
- expect(mockRunLinter).toHaveBeenCalled();
158
- });
159
- });
160
-
161
- describe("initial render", () => {
162
- it("should build initial state from props passed in", () => {
163
- // Arrange and Act
164
- const {renderer} = renderQuestion(question1);
165
-
166
- // Assert
167
- expect(renderer.state.jiptContent).toBeNull();
168
- expect(renderer.state.translationLintErrors).toHaveLength(0);
169
- expect(renderer.state.lastUsedWidgetId).toBeNull();
170
-
171
- expect(renderer.state.widgetInfo).toStrictEqual(question1.widgets);
172
- expect(renderer.state.widgetProps).toMatchInlineSnapshot(`
173
- {
174
- "dropdown 1": {
175
- "choices": [
176
- "greater than or equal to",
177
- "less than or equal to",
178
- ],
179
- "placeholder": "greater/less than or equal to",
180
- },
181
- }
182
- `);
183
- });
184
-
185
- it("should derive type widget ID if type missing", () => {
186
- // Arrange
187
- // Note that the Flow types disallow this, but our Renderer handles the
188
- // case so for now, I'm adding this test. We can remove the test
189
- // if/when we clean up the code for it in _getAllWidgetsInfo().
190
- const question = {
191
- ...question1,
192
- widgets: {
193
- ...question1.widgets,
194
- // $FlowIgnore[prop-missing]
195
- // $FlowIgnore[incompatible-cast]
196
- "dropdown 1": ({
197
- ...question1.widgets["dropdown 1"],
198
- // $FlowIgnore[incompatible-cast]
199
- type: undefined,
200
- }: DropdownWidget),
201
- },
202
- };
203
-
204
- // Act
205
- const {renderer} = renderQuestion(question);
206
-
207
- // Assert
208
- expect(renderer.state.widgetInfo["dropdown 1"]?.type).toBe(
209
- "dropdown",
210
- );
211
- });
212
-
213
- it("should default alignment if missing", () => {
214
- // Arrange/Act
215
- const {renderer} = renderQuestion({
216
- ...question1,
217
- widgets: {
218
- ...question1.widgets,
219
- "dropdown 1": {
220
- ...question1.widgets["dropdown 1"],
221
- alignment: undefined,
222
- },
223
- },
224
- });
225
-
226
- // Assert
227
- expect(renderer.state.widgetInfo["dropdown 1"]?.alignment).toBe(
228
- "default",
229
- );
230
- });
231
-
232
- it("should build default widget info if widget ID missing from widget props", () => {
233
- // Arrange
234
- const {renderer} = renderQuestion({
235
- ...question1,
236
- content:
237
- "[[☃ dropdown 1]] exists.\n\n" +
238
- "[[☃ dropdown 2]] does not!",
239
- });
240
- expect(question1.widgets["dropdown 2"]).toBeUndefined();
241
- let sawDropdown2 = false;
242
-
243
- // Act
244
- const widgets = renderer.findInternalWidgets((id, info, widget) => {
245
- // We should see the Renderer dealing with `dropdown 2` even if
246
- // no widget options/props were provided in the Perseus item.
247
- if (id === "dropdown 2") {
248
- // Dropdown 2's info is the default value (ie. it's got a
249
- // type and empty options object).
250
- expect(info.type).toBe("dropdown");
251
- expect(info.options).toStrictEqual({});
252
- expect(info.graded).toBeTrue();
253
-
254
- sawDropdown2 = true;
255
- return true;
256
- }
257
- return false;
258
- });
259
-
260
- // Assert
261
- expect(sawDropdown2).toBeTrue();
262
- // `dropdown 2` not found, however, because the Renderer doesn't
263
- // render widget's that don't have options defined.
264
- expect(widgets).toStrictEqual([null]);
265
- });
266
-
267
- it("should restore serialized state on mount if provided in prop", () => {
268
- // Arrange
269
- renderQuestion(
270
- question1,
271
- {},
272
- {
273
- serializedState: {
274
- "dropdown 1": {
275
- placeholder: "greater/less than or equal to",
276
- choices: [
277
- "greater than or equal to",
278
- "less than or equal to",
279
- ],
280
- selected: 2,
281
- },
282
- },
283
- },
284
- );
285
-
286
- // Assert
287
- expect(screen.getByRole("button")).toHaveTextContent(
288
- /^less than or equal to$/,
289
- );
290
- });
291
- });
292
-
293
- describe("rendering", () => {
294
- const images = [];
295
- let originalImage;
296
-
297
- beforeEach(() => {
298
- originalImage = window.Image;
299
- // Mock HTML Image so we can trigger onLoad callbacks and see full
300
- // image rendering.
301
- window.Image = jest.fn(() => {
302
- const img = {};
303
- images.push(img);
304
- return img;
305
- });
306
- });
307
-
308
- afterEach(() => {
309
- window.Image = originalImage;
310
- });
311
-
312
- // Tells the image loader 1, or all, of our images loaded
313
- const markImagesAsLoaded = (imageIndex?: number) => {
314
- if (imageIndex != null) {
315
- const img = images[imageIndex];
316
- if (img?.onload) {
317
- img.onload();
318
- }
319
- } else {
320
- images.forEach((i) => {
321
- if (i?.onload) {
322
- i.onload();
323
- }
324
- });
325
- }
326
- };
327
-
328
- it.each([true, false])(
329
- "should render a table when isMobile: %s",
330
- (isMobile: boolean) => {
331
- // Arrange
332
- const question = {
333
- content:
334
- "| Heading 1 | Heading 2 | Heading 3 |\n" +
335
- "| --------- | --------- | --------- |\n" +
336
- "| r1c1 | r1c2 | r1c3 |\n" +
337
- "| r2c1 | r2c2 | r2c3 |\n" +
338
- "| r3c1 | r3c2 | r3c3 |",
339
- images: {},
340
- widgets: {},
341
- };
342
-
343
- // Act
344
- const {container} = renderQuestion(question, {
345
- isMobile,
346
- });
347
-
348
- // Assert
349
- expect(container).toMatchSnapshot();
350
- },
351
- );
352
-
353
- it("should wrap image to be responsive if not in table and dimensions provided", () => {
354
- // Arrange
355
- const question = {
356
- content:
357
- "One image with dimensions that isn't in a table.\n\n" +
358
- "![This image has dimensions](https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg)",
359
- images: {
360
- "https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg":
361
- {height: 410, width: 420},
362
- },
363
- widgets: {},
364
- };
365
- renderQuestion(question);
366
-
367
- // Act
368
- markImagesAsLoaded();
369
-
370
- // Assert
371
- const imageNodes = screen.queryAllByRole("img");
372
- expect(imageNodes).toHaveLength(1);
373
-
374
- // eslint-disable-next-line testing-library/no-node-access
375
- expect(imageNodes[0].parentElement).toHaveClass(
376
- "fixed-to-responsive",
377
- );
378
- });
379
-
380
- it("should not wrap image to be responsive if not in table and no dimensions provided", () => {
381
- // Arrange
382
- const question = {
383
- content:
384
- "One image without dimensions.\n\n" +
385
- "![This image doesn't have dimensions](https://ka-perseus-images.s3.amazonaws.com/41dbe22e2d8aa0eb4356195d634c3219dc7142c9.svg)",
386
- images: {},
387
- widgets: {},
388
- };
389
- renderQuestion(question);
390
-
391
- // Act
392
- markImagesAsLoaded();
393
-
394
- // Assert
395
- const imageNodes = screen.queryAllByRole("img");
396
- expect(imageNodes).toHaveLength(1);
397
-
398
- // image didn't have dimensions provided so it is not rendered as
399
- // responsive.
400
- // eslint-disable-next-line testing-library/no-node-access
401
- expect(imageNodes[0].parentElement).not.toHaveClass(
402
- "fixed-to-responsive",
403
- );
404
- });
405
-
406
- it("should add dimensions to wrapper, if provided", () => {
407
- // Arrange
408
- const question = {
409
- content:
410
- "One image with dimensions.\n\n" +
411
- "![This image has dimensions](https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg)",
412
- images: {
413
- "https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg":
414
- {height: 410, width: 420},
415
- },
416
- widgets: {},
417
- };
418
- renderQuestion(question);
419
-
420
- // Act
421
- markImagesAsLoaded();
422
-
423
- // Assert
424
- expect(screen.queryAllByRole("img")).toHaveLength(1);
425
-
426
- const wrapperStyle = getComputedStyle(
427
- // $FlowIgnore[incompatible-call]
428
- screen.getByAltText("This image has dimensions").parentElement, // eslint-disable-line testing-library/no-node-access
429
- );
430
- expect(wrapperStyle.maxWidth).toBe("420px");
431
- expect(wrapperStyle.maxHeight).toBe("410px");
432
- });
433
-
434
- it("should not add dimensions to wrapper, if not provided", () => {
435
- // Arrange
436
- const question = {
437
- content:
438
- "One image without dimensions.\n\n" +
439
- "![This image doesn't](https://ka-perseus-images.s3.amazonaws.com/41dbe22e2d8aa0eb4356195d634c3219dc7142c9.svg)",
440
- images: {},
441
- widgets: {},
442
- };
443
- renderQuestion(question);
444
-
445
- // Act
446
- markImagesAsLoaded();
447
-
448
- // Assert
449
- expect(screen.queryAllByRole("img")).toHaveLength(1);
450
-
451
- const wrapperStyle = getComputedStyle(
452
- // $FlowIgnore[incompatible-call]
453
- screen.getByAltText("This image doesn't").parentElement, // eslint-disable-line testing-library/no-node-access
454
- );
455
- expect(wrapperStyle.maxWidth).toBe("");
456
- expect(wrapperStyle.maxHeight).toBe("");
457
- });
458
-
459
- it("should never render image in responsive mode if inside table", () => {
460
- // Arrange
461
- const question = {
462
- content:
463
- "A table with images:\n\n" +
464
- "\n\n" +
465
- "| Title | Image |\n" +
466
- "| ----- |------ |\n" +
467
- "| Are you hungry for pizza? |\n" +
468
- "| ![This image has dimensions](https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg) ",
469
- images: {
470
- "https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg":
471
- {height: 410, width: 420},
472
- },
473
- widgets: {},
474
- };
475
- renderQuestion(question);
476
-
477
- // Act
478
- markImagesAsLoaded();
479
-
480
- // Assert
481
- const imageNodes = screen.queryAllByRole("img");
482
- expect(imageNodes).toHaveLength(1);
483
- expect(getComputedStyle(imageNodes[0]).width).toBe("420px");
484
- expect(getComputedStyle(imageNodes[0]).height).toBe("410px");
485
-
486
- // And the parent shouldn't be a wrapper element
487
- // eslint-disable-next-line testing-library/no-node-access
488
- expect(imageNodes[0].parentElement).not.toHaveClass(
489
- "fixed-to-responsive",
490
- );
491
- });
492
-
493
- it("should render widgetPlaceholder if provided", () => {
494
- // Arrange
495
- const widgetPlaceholder = <div key="1">This is a placeholder</div>;
496
-
497
- // Act
498
- renderQuestion(question1, {
499
- widgetPlaceholder,
500
- });
501
-
502
- // Assert
503
- expect(
504
- screen.getByText("This is a placeholder"),
505
- ).toBeInTheDocument();
506
- // Make sure the 'dropdown' widget wasn't rendered!
507
- expect(screen.queryAllByRole("button")).toHaveLength(0);
508
- });
509
-
510
- it("should render columns", () => {
511
- // Arrange
512
- const question = {
513
- content:
514
- "Stuff in column 1\n\n" +
515
- "=====\n\n" +
516
- "Stuff in column 2\n\n",
517
- images: {},
518
- widgets: {},
519
- };
520
-
521
- // Act
522
- const {container} = renderQuestion(question);
523
-
524
- // Assert
525
- expect(container).toMatchSnapshot();
526
- });
527
-
528
- it("should render image placeholder for links found in content that are images (for translation support)", () => {
529
- // Arrange
530
- const question = {
531
- content:
532
- "A link to an image: https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg",
533
- images: {},
534
- widgets: {},
535
- };
536
- const imagePlaceholder = (
537
- // Without a `key`, we get React warnings
538
- <div key="placeholder">image placeholder</div>
539
- );
540
-
541
- // Act
542
- renderQuestion(question, {
543
- imagePlaceholder,
544
- });
545
-
546
- // Assert
547
- const renderedPlaceholder = screen.getByText("image placeholder");
548
- expect(renderedPlaceholder).toBeInTheDocument();
549
- // eslint-disable-next-line testing-library/no-node-access
550
- expect(renderedPlaceholder.parentElement).toMatchInlineSnapshot(`
551
- <a
552
- href="https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg"
553
- rel="noopener noreferrer"
554
- target="_blank"
555
- >
556
- <div>
557
- image placeholder
558
- </div>
559
- </a>
560
- `);
561
- });
562
-
563
- it("should render imagePlaceholder for all images", () => {
564
- // Arrange
565
- const imagePlaceholder = (
566
- <div key="1">This is an image placeholder</div>
567
- );
568
-
569
- // Act
570
- renderQuestion(
571
- {
572
- content:
573
- "We need more cat gifs: \n\n" +
574
- "![this isn't a cat gif :(](https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg)\n\n" +
575
- "![this isn't a cat gif :(](https://ka-perseus-images.s3.amazonaws.com/41dbe22e2d8aa0eb4356195d634c3219dc7142c9.svg)",
576
- images: {
577
- "https://ka-perseus-images.s3.amazonaws.com/29e9aa32de3731b09e245e416cbf4e3fb2e89b58.svg":
578
- {height: 420, width: 420},
579
- "https://ka-perseus-images.s3.amazonaws.com/41dbe22e2d8aa0eb4356195d634c3219dc7142c9.svg":
580
- {height: 216, width: 216},
581
- },
582
- widgets: {},
583
- },
584
- {
585
- imagePlaceholder,
586
- },
587
- );
588
-
589
- // Assert
590
- expect(
591
- screen.getAllByText("This is an image placeholder"),
592
- ).toHaveLength(2);
593
- });
594
-
595
- it("should render warning if same widget included multiple times in content", () => {
596
- // Arrange
597
- const question = {
598
- ...question1,
599
- content: question1.content + "\n\n[[☃ dropdown 1]]",
600
- };
601
-
602
- // Act
603
- renderQuestion(question);
604
-
605
- // Assert
606
- expect(
607
- screen.getByText("Widget [[☃ dropdown 1]] already exists."),
608
- ).toBeInTheDocument();
609
- });
610
-
611
- it("should render block math", async () => {
612
- // Arrange
613
- const question = {
614
- content:
615
- "This is some block math\n\n" +
616
- "$1 + 2$\n\n" +
617
- "And a footer.",
618
- images: {},
619
- widgets: {},
620
- };
621
- const apiOptions = {};
622
-
623
- // Act
624
- const {container} = renderQuestion(question, apiOptions);
625
- // KaTeX renders async, so we have to wait until it's done.
626
- await waitFor(() => {
627
- screen.getByText("1 + 2");
628
- });
629
-
630
- // Assert
631
- expect(container).toMatchSnapshot();
632
- });
633
-
634
- it("should render block math on mobile", async () => {
635
- // Arrange
636
- const question = {
637
- content:
638
- "This is some block math\n\n" +
639
- "$1 + 2$\n\n" +
640
- "And a footer.",
641
- images: {},
642
- widgets: {},
643
- };
644
- const apiOptions = {isMobile: true};
645
-
646
- // Act
647
- const {container} = renderQuestion(question, apiOptions);
648
- // KaTeX renders async, so we have to wait until it's done.
649
- await waitFor(() => {
650
- screen.getByText("1 + 2");
651
- });
652
-
653
- // Assert
654
- expect(container).toMatchSnapshot();
655
- });
656
-
657
- it("should render block math in a Zoomable when on mobile", async () => {
658
- // Arrange
659
- const question = {
660
- content:
661
- "This is some block math\n\n" +
662
- "$1 + 2$\n\n" +
663
- "And a footer.",
664
- images: {},
665
- widgets: {},
666
- };
667
- const apiOptions = {isMobile: true};
668
-
669
- // Act
670
- const {container} = renderQuestion(question, apiOptions);
671
- // KaTeX renders async, so we have to wait until it's done.
672
- await waitFor(() => {
673
- screen.getByText("1 + 2");
674
- });
675
-
676
- // Assert
677
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
678
- const [zoomable] = container.querySelectorAll(
679
- ".perseus-block-math-inner span",
680
- );
681
- expect(zoomable).not.toBeUndefined();
682
- expect(zoomable).not.toBeNull();
683
- expect(zoomable.style.transform).not.toBe("");
684
-
685
- /* eslint-disable testing-library/no-node-access */
686
- // $FlowIgnore[prop-missing]
687
- // $FlowIgnore[incompatible-use]
688
- expect(zoomable.parentElement.style.transform).not.toBe("");
689
- /* eslint-enable testing-library/no-node-access */
690
- });
691
-
692
- it("should render the math", async () => {
693
- // Arrange
694
- const question = {
695
- content: "This is some inline math: $1 + 2$",
696
- images: {},
697
- widgets: {},
698
- };
699
-
700
- // Act
701
- const {container} = renderQuestion(question);
702
-
703
- // Assert
704
- await waitFor(() => {
705
- screen.getByText("1 + 2");
706
- });
707
- expect(container).toMatchSnapshot();
708
- });
709
-
710
- it("should replace deprecated alignment tags in inline math", async () => {
711
- // Arrange
712
- const question = {
713
- content:
714
- "$\\begin{align}\n2\\text{HCl}(\\text{aq})+\\text{Ca}(\\text{OH})_2(\\text{aq})\\rightarrow\\text{Ca}(\\text{s})+2\\text H_2\\text O(\\text l)+\\text{Cl}_2(\\text g)\n\\end{align}$",
715
- images: {},
716
- widgets: {},
717
- };
718
-
719
- // Act
720
- renderQuestion(question);
721
-
722
- // Assert
723
- // KaTeX renders async, so we use waitFor() have to wait until it's done.
724
- await waitFor(() => {
725
- screen.getByText(/\\begin\{aligned\}.*\\end\{aligned\}/);
726
- });
727
- });
728
- });
729
-
730
- // Note that we can't use `.each` here because the three props require
731
- // slightly different methods to change them for our rerender() function
732
- describe("resets widgetInfo and widgetProps when a prop in SHOULD_CLEAR_WIDGETS_PROP_LIST changes", () => {
733
- let originalWidgetInfo;
734
- let originalWidgetProps;
735
- let rerender;
736
- let renderer;
737
-
738
- beforeEach(() => {
739
- // Arrange
740
- // eslint-disable-next-line testing-library/no-render-in-setup
741
- const result = renderQuestion(question1);
742
- rerender = result.rerender;
743
- renderer = result.renderer;
744
-
745
- originalWidgetInfo = clone(renderer.state.widgetInfo);
746
- originalWidgetProps = clone(renderer.state.widgetProps);
747
-
748
- // Poke the renderer so it's not in it's initial-render state
749
- userEvent.click(screen.getByRole("button"));
750
- jest.runOnlyPendingTimers(); // There's a setTimeout to open the dropdown
751
- userEvent.click(screen.getAllByRole("option")[1]);
752
- });
753
-
754
- it("'content' prop'", () => {
755
- // Act
756
- rerender({
757
- ...question1,
758
- content:
759
- "this is a content change but still retains the widget it had: [[☃ dropdown 1]]",
760
- });
761
-
762
- // Assert
763
- expect(renderer.state.widgetInfo).toStrictEqual(originalWidgetInfo);
764
- expect(renderer.state.widgetProps).toStrictEqual(
765
- originalWidgetProps,
766
- );
767
- });
768
-
769
- it("'problemNum' prop", () => {
770
- // Act
771
- rerender(question1, {problemNum: 1});
772
-
773
- // Assert
774
- expect(renderer.state.widgetInfo).toStrictEqual(originalWidgetInfo);
775
- expect(renderer.state.widgetProps).toStrictEqual(
776
- originalWidgetProps,
777
- );
778
- });
779
-
780
- it("'widgets' prop", () => {
781
- // Act
782
- rerender({
783
- ...question1,
784
- widgets: {
785
- ...question1.widgets,
786
- // This is just a copy of the original widget, but it
787
- // causes a 'widgets' prop change
788
- "another-widget 1": question1.widgets["dropdown 1"],
789
- },
790
- });
791
-
792
- // Assert
793
- const allWidgetIds = Object.getOwnPropertyNames(originalWidgetInfo);
794
-
795
- // Note that we are only caring about equality of keys that existed
796
- // in the original state. Of course, since we made changes to the
797
- // `widgets` prop, the two widget-dependant state fields will be
798
- // changed!
799
- for (const widgetId of allWidgetIds) {
800
- expect(renderer.state.widgetInfo[widgetId]).toStrictEqual(
801
- originalWidgetInfo[widgetId],
802
- );
803
- }
804
-
805
- for (const widgetId of allWidgetIds) {
806
- expect(renderer.state.widgetProps[widgetId]).toStrictEqual(
807
- originalWidgetProps[widgetId],
808
- );
809
- }
810
- });
811
- });
812
-
813
- describe("focus management", () => {
814
- it("should focus the first focusable widget", () => {
815
- // Arrange
816
- const question = {
817
- content:
818
- "A dropdown [[☃ dropdown 1]]\nAn input [[☃ input-number 1]]\n\nAnd an image [[☃ image 1]].",
819
- images: {},
820
- widgets: {
821
- "dropdown 1": dropdownWidget,
822
- "input-number 1": inputNumberWidget,
823
- "image 1": imageWidget,
824
- },
825
- };
826
- const onFocusChange = jest.fn();
827
- const {renderer} = renderQuestion(question, {
828
- onFocusChange,
829
- });
830
-
831
- // Act
832
- const focusResult = renderer.focus();
833
-
834
- // Assert
835
- expect(focusResult).toBeTrue();
836
- expect(onFocusChange).toHaveBeenCalledWith(["dropdown 1"], null);
837
- });
838
-
839
- it("should return false if no widgets are focusable", () => {
840
- // Arrange
841
- const onFocusChange = jest.fn();
842
- const {renderer} = renderQuestion(
843
- {
844
- content: "[[☃ image 1]]",
845
- images: {},
846
- widgets: {
847
- "image 1": {
848
- alignment: "block",
849
- graded: true,
850
- options: ({
851
- alt: "A number line labeled 200 to 300 with tick marks at every 5 units. The tick marks at 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, and 300 are labeled. A red circle labeled A is between 220 tick mark and 230 tick mark.",
852
- backgroundImage: {
853
- height: 80,
854
- url: "web+graphie://ka-perseus-graphie.s3.amazonaws.com/3351ccf19e60c28a1d08664f5c16defa76ed0348",
855
- width: 380,
856
- },
857
- }: PerseusImageWidgetOptions),
858
- static: false,
859
- type: "image",
860
- version: {major: 0, minor: 0},
861
- },
862
- },
863
- },
864
- {
865
- onFocusChange,
866
- },
867
- );
868
-
869
- // Act
870
- const focusResult = renderer.focus();
871
-
872
- // Assert
873
- expect(focusResult).toBeFalsy();
874
- expect(onFocusChange).not.toHaveBeenCalled();
875
- });
876
-
877
- it("should call onFocusChange callback when new widget receives focus", () => {
878
- // Arrange
879
- const onFocusChange = jest.fn();
880
- renderQuestion(
881
- {
882
- ...question2,
883
- content:
884
- "Enter 1 in this field: [[☃ input-number 1]].\n\n" +
885
- "Enter 2 in this field: [[☃ input-number 2]] $60$.",
886
- widgets: {
887
- "input-number 1": question2.widgets["input-number 1"],
888
- "input-number 2": question2.widgets["input-number 1"],
889
- },
890
- },
891
- {onFocusChange},
892
- );
893
-
894
- // Act
895
- userEvent.click(screen.getAllByRole("textbox")[1]);
896
-
897
- // Assert
898
- expect(onFocusChange).toHaveBeenCalledWith(
899
- /* new focus path */ ["input-number 2"],
900
- /* old focus path */ null,
901
- );
902
- });
903
-
904
- it("should call onFocusChange callback when a widget loses focus", () => {
905
- // Arrange
906
- const onFocusChange = jest.fn();
907
- renderQuestion(
908
- {
909
- ...question2,
910
- content:
911
- "Enter 1 in this field: [[☃ input-number 1]].\n\n" +
912
- "Enter 2 in this field: [[☃ input-number 2]] $60$.",
913
- widgets: {
914
- "input-number 1": question2.widgets["input-number 1"],
915
- "input-number 2": question2.widgets["input-number 1"],
916
- },
917
- },
918
- {onFocusChange},
919
- );
920
- userEvent.click(screen.getAllByRole("textbox")[1]);
921
- onFocusChange.mockClear();
922
-
923
- // Act
924
- userEvent.tab();
925
- // There's a _.defer() in the blur handling
926
- jest.runOnlyPendingTimers();
927
-
928
- // Assert
929
- expect(onFocusChange).toHaveBeenCalledWith(
930
- /* new focus path */ null,
931
- /* old focus path */ ["input-number 2"],
932
- );
933
- });
934
-
935
- it("should throw if widget provides invalid focus path", () => {
936
- // Arrange
937
- const {renderer} = renderQuestion(mockedItem);
938
- const [widget2] = renderer.findWidgets("mock-widget 2");
939
-
940
- // Act and Assert
941
- expect(() => {
942
- // TODO: Right now KAError is mocked because we're
943
- // jest.mock()ing the logging module. Figure out how to
944
- // unmock.
945
- widget2.props.onFocus("this is not an array");
946
- }).toThrow("widget props.onFocus focusPath must be an Array");
947
- });
948
-
949
- it("should focus the input at the requested FocusPath", () => {
950
- // Arrange
951
- const {renderer} = renderQuestion(question2);
952
-
953
- // Act
954
- renderer.focusPath(["input-number 1"]);
955
-
956
- // Assert
957
- expect(screen.getByRole("textbox")).toHaveFocus();
958
- });
959
-
960
- it("should do nothing if requested FocusPath is already focused", () => {
961
- // Arrange
962
- const onFocusChange = jest.fn();
963
- const {renderer} = renderQuestion(question2, {
964
- onFocusChange,
965
- });
966
- renderer.focusPath(["input-number 1"]);
967
- onFocusChange.mockClear();
968
-
969
- // Act
970
- renderer.focusPath(["input-number 1"]);
971
-
972
- // Assert
973
- expect(onFocusChange).not.toHaveBeenCalled();
974
- });
975
-
976
- it("should blur current widget when focus changes", () => {
977
- // Arrange
978
- const onFocusChange = jest.fn();
979
- const {renderer} = renderQuestion(
980
- {
981
- ...question2,
982
- content:
983
- "Input 1: [[☃ input-number 1]]\n\n" +
984
- "Input 2: [[☃ input-number 2]]",
985
- widgets: {
986
- ...question2.widgets,
987
- "input-number 2": question2.widgets["input-number 1"],
988
- },
989
- },
990
- {onFocusChange},
991
- );
992
- renderer.focusPath(["input-number 1"]);
993
- onFocusChange.mockClear();
994
-
995
- // Act
996
- renderer.focusPath(["input-number 2"]);
997
-
998
- // Assert
999
- expect(onFocusChange).toHaveBeenCalledWith(
1000
- ["input-number 2"], // New focus
1001
- ["input-number 1"], // Old focus
1002
- );
1003
- });
1004
-
1005
- it("should do nothing if blurred widget is not focused", () => {
1006
- // Arrange
1007
- const onFocusChange = jest.fn();
1008
- const {renderer} = renderQuestion(
1009
- {
1010
- ...question2,
1011
- content:
1012
- "Input 1: [[☃ input-number 1]]\n\n" +
1013
- "Input 2: [[☃ input-number 2]]",
1014
- widgets: {
1015
- ...question2.widgets,
1016
- "input-number 2": question2.widgets["input-number 1"],
1017
- },
1018
- },
1019
- {onFocusChange},
1020
- );
1021
- // Focus _second_ input number widget
1022
- screen.getAllByRole("textbox")[1].focus();
1023
- onFocusChange.mockClear();
1024
-
1025
- // Act
1026
- renderer.blurPath(["input-number 1"]);
1027
-
1028
- // Assert
1029
- expect(onFocusChange).not.toHaveBeenCalled();
1030
- });
1031
-
1032
- it("should blur current widget", () => {
1033
- // Arrange
1034
- const onFocusChange = jest.fn();
1035
- const {renderer} = renderQuestion(
1036
- {
1037
- ...question2,
1038
- content:
1039
- "Input 1: [[☃ input-number 1]]\n\n" +
1040
- "Input 2: [[☃ input-number 2]]",
1041
- widgets: {
1042
- ...question2.widgets,
1043
- "input-number 2": question2.widgets["input-number 1"],
1044
- },
1045
- },
1046
- {onFocusChange},
1047
- );
1048
- // Focus _second_ input number widget
1049
- screen.getAllByRole("textbox")[1].focus();
1050
- onFocusChange.mockClear();
1051
-
1052
- // Act
1053
- renderer.blur();
1054
- jest.runOnlyPendingTimers(); // There's a _.defer() in this code path
1055
-
1056
- // Assert
1057
- expect(onFocusChange).toHaveBeenCalledWith(
1058
- null, // New focus
1059
- ["input-number 2"], // Old focus
1060
- );
1061
- });
1062
-
1063
- it("should do nothing when blur() called but no widget focused", () => {
1064
- // Arrange
1065
- const onFocusChange = jest.fn();
1066
- const {renderer} = renderQuestion(
1067
- {
1068
- ...question2,
1069
- content:
1070
- "Input 1: [[☃ input-number 1]]\n\n" +
1071
- "Input 2: [[☃ input-number 2]]",
1072
- widgets: {
1073
- ...question2.widgets,
1074
- "input-number 2": question2.widgets["input-number 1"],
1075
- },
1076
- },
1077
- {onFocusChange},
1078
- );
1079
-
1080
- // Act
1081
- renderer.blur();
1082
- jest.runOnlyPendingTimers(); // There's a _.defer() in this code path
1083
-
1084
- // Assert
1085
- expect(onFocusChange).not.toHaveBeenCalled();
1086
- });
1087
- });
1088
-
1089
- describe("state serialization", () => {
1090
- it("should request widget's serialized state if implemented", () => {
1091
- // Arrange
1092
- const {renderer} = renderQuestion(mockedItem);
1093
-
1094
- const [widget2] = renderer.findWidgets("mock-widget 2");
1095
- expect(widget2).not.toBeUndefined();
1096
- widget2.getSerializedState = jest.fn();
1097
-
1098
- // Act
1099
- renderer.getSerializedState();
1100
-
1101
- // Act
1102
- expect(widget2.getSerializedState).toHaveBeenCalled();
1103
- });
1104
-
1105
- it("should skip restoration if state's widget ID list doesn't match renderer widgets", () => {
1106
- // Arrange
1107
- const errorSpy = jest.spyOn(testDependencies.Log, "error");
1108
-
1109
- const {renderer} = renderQuestion(question1);
1110
-
1111
- // Act
1112
- renderer.restoreSerializedState({
1113
- "group 1": {},
1114
- "interactive-chart 1": {},
1115
- });
1116
-
1117
- // Assert
1118
- expect(errorSpy).toHaveBeenCalledWith(
1119
- "Refusing to restore bad serialized state:",
1120
- Errors.Internal,
1121
- {
1122
- loggedMetadata: {
1123
- currentProps: expect.anything(),
1124
- serializedState:
1125
- '{"group 1":{},"interactive-chart 1":{}}',
1126
- },
1127
- },
1128
- );
1129
- });
1130
-
1131
- it("should fire restoration callback when all widgets have restored", () => {
1132
- // Arrange
1133
- const makeRestoreSerializedStateMock = jest
1134
- .fn()
1135
- .mockImplementation((props, callback) => callback());
1136
-
1137
- const {renderer} = renderQuestion(mockedItem);
1138
- const [widget1, widget2, widget3] = renderer.findWidgets(
1139
- (_, info) => info.type === "mock-widget",
1140
- );
1141
- widget1.restoreSerializedState = makeRestoreSerializedStateMock;
1142
- widget2.restoreSerializedState = makeRestoreSerializedStateMock;
1143
- widget3.restoreSerializedState = makeRestoreSerializedStateMock;
1144
-
1145
- const restorationCallback = jest.fn();
1146
-
1147
- // Act
1148
- renderer.restoreSerializedState(
1149
- {"mock-widget 1": {}, "mock-widget 2": {}, "mock-widget 3": {}},
1150
- restorationCallback,
1151
- );
1152
- jest.runOnlyPendingTimers();
1153
-
1154
- // Assert
1155
- expect(restorationCallback).toHaveBeenCalledTimes(1);
1156
- });
1157
-
1158
- it("should return each widget's state from serialize()", () => {
1159
- // Arrange
1160
- const {renderer} = renderQuestion(mockedItem);
1161
- const widgets = renderer.findWidgets((id) =>
1162
- ["mock-widget 1", "mock-widget 2", "mock-widget 3"].includes(
1163
- id,
1164
- ),
1165
- );
1166
- widgets.forEach((w) => {
1167
- w.serialize = jest.fn(() => `State: ${w.props.widgetId}`);
1168
- });
1169
- // It takes a clock tick after rendering for widgetInfo to be
1170
- // populated (which renderer uses during serialize()).
1171
- jest.runOnlyPendingTimers();
1172
-
1173
- // Act
1174
- const state = renderer.serialize();
1175
-
1176
- // Assert
1177
- expect(state).toStrictEqual({
1178
- "mock-widget 1": "State: mock-widget 1",
1179
- "mock-widget 2": "State: mock-widget 2",
1180
- "mock-widget 3": "State: mock-widget 3",
1181
- });
1182
- });
1183
- });
1184
-
1185
- describe("finding widgets", () => {
1186
- it("should be able to find widgets by widget ID string", () => {
1187
- // Arrange
1188
- const {renderer} = renderQuestion(question1);
1189
-
1190
- // Act
1191
- const [dropdown1] = renderer.findWidgets("dropdown 1");
1192
-
1193
- // Assert
1194
- expect(dropdown1).not.toBeNull();
1195
- expect(dropdown1).not.toBeUndefined();
1196
- });
1197
-
1198
- it("should be able to find widgets by widget type string", () => {
1199
- // Arrange
1200
- const {renderer} = renderQuestion(question1);
1201
-
1202
- // Act
1203
- const [dropdown1] = renderer.findWidgets("dropdown");
1204
-
1205
- // Assert
1206
- expect(dropdown1).not.toBeNull();
1207
- expect(dropdown1).not.toBeUndefined();
1208
- });
1209
-
1210
- it("should be able to find widgets by filter function", () => {
1211
- // Arrange
1212
- const {renderer} = renderQuestion(question1);
1213
- let filterCalled = false;
1214
-
1215
- // Act and Arrange
1216
- renderer.findWidgets((id, info, widget) => {
1217
- filterCalled = true;
1218
- expect(id).toBe("dropdown 1");
1219
- expect(info.type).toBe("dropdown");
1220
- expect(widget).not.toBeNull();
1221
- expect(widget).not.toBeUndefined();
1222
- return false;
1223
- });
1224
-
1225
- expect(filterCalled).toBeTrue();
1226
- });
1227
- });
1228
-
1229
- describe("misc behaviors", () => {
1230
- it("should be able to force re-render", () => {
1231
- // Arrange
1232
- const onRender = jest.fn();
1233
- const apiOptions = {};
1234
- const extraProps = {
1235
- alwaysUpdate: true, // Switching to `false` to fails test
1236
- onRender,
1237
- };
1238
- const {rerender} = renderQuestion(
1239
- question1,
1240
- apiOptions,
1241
- extraProps,
1242
- );
1243
-
1244
- // Act
1245
- rerender(question1, extraProps);
1246
-
1247
- // How do I tell it rerendered?
1248
- expect(onRender).toHaveBeenCalledTimes(2);
1249
- });
1250
-
1251
- it("should use new serializedState if getSerializedState is different", () => {
1252
- // Act
1253
- // Render with serialized state
1254
- const {rerender} = renderQuestion(
1255
- question1,
1256
- {},
1257
- {
1258
- serializedState: {
1259
- "dropdown 1": {
1260
- placeholder: "greater/less than or equal to",
1261
- choices: [
1262
- "greater than or equal to",
1263
- "less than or equal to",
1264
- ],
1265
- selected: 2, // <-- Important
1266
- },
1267
- },
1268
- },
1269
- );
1270
-
1271
- // Act
1272
- rerender(question1, {
1273
- serializedState: {
1274
- "dropdown 1": {
1275
- placeholder: "greater/less than or equal to",
1276
- choices: [
1277
- "greater than or equal to",
1278
- "less than or equal to",
1279
- ],
1280
- selected: 1, // <-- Important
1281
- },
1282
- },
1283
- });
1284
-
1285
- expect(screen.getByRole("button")).toHaveTextContent(
1286
- /greater than or equal to/,
1287
- );
1288
- });
1289
-
1290
- it("should render the widget in full width if alignment == 'fullWidth'", () => {
1291
- // Arrange/Act
1292
- renderQuestion({
1293
- ...question1,
1294
- widgets: {
1295
- ...question1.widgets,
1296
- "dropdown 1": {
1297
- ...question1.widgets["dropdown 1"],
1298
- alignment: "full-width",
1299
- },
1300
- },
1301
- });
1302
-
1303
- // Assert
1304
- let el = screen.getByRole("button");
1305
- while (el != null) {
1306
- if (el.classList.contains("widget-full-width")) {
1307
- break;
1308
- }
1309
- // eslint-disable-next-line testing-library/no-node-access
1310
- el = el.parentElement;
1311
- }
1312
-
1313
- // Didn't find parent element that's set to full-widget
1314
- expect(el).not.toBeNull();
1315
- });
1316
-
1317
- it("should force the widget to be non-static if it has a problem number", () => {
1318
- // Arrange/Act
1319
- const {renderer} = renderQuestion(
1320
- {
1321
- ...question1,
1322
- widgets: {
1323
- ...question1.widgets,
1324
- "dropdown 1": {
1325
- ...question1.widgets["dropdown 1"],
1326
- static: true,
1327
- },
1328
- },
1329
- },
1330
- {},
1331
- {problemNum: 1},
1332
- );
1333
-
1334
- // Assert
1335
- const [dropdownWidget] = renderer.findWidgets("dropdown 1");
1336
-
1337
- // Act
1338
- expect(dropdownWidget.props.static).toBeFalse();
1339
- });
1340
-
1341
- it("should ask each widget to show rationales", () => {
1342
- // Arrange
1343
- const {renderer} = renderQuestion(mockedItem);
1344
- const widgets = renderer.findWidgets(
1345
- (_, info) => info.type === "mock-widget",
1346
- );
1347
- widgets.forEach(
1348
- (w) =>
1349
- (w.showRationalesForCurrentlySelectedChoices = jest.fn()),
1350
- );
1351
-
1352
- // Guard: If our test data were to cause this to return an empty
1353
- // array, the rest of the assertions in this test would pass.
1354
- expect(widgets.length).toBeGreaterThan(0);
1355
-
1356
- // Act
1357
- renderer.showRationalesForCurrentlySelectedChoices();
1358
-
1359
- // Assert
1360
- widgets.forEach((w) =>
1361
- expect(
1362
- w.showRationalesForCurrentlySelectedChoices,
1363
- ).toHaveBeenCalled(),
1364
- );
1365
- });
1366
-
1367
- it("should ask each widget to deselect incorrect choices", () => {
1368
- // Arrange
1369
- const {renderer} = renderQuestion(mockedItem);
1370
- const widgets = renderer.findWidgets(
1371
- (_, info) => info.type === "mock-widget",
1372
- );
1373
- widgets.forEach(
1374
- (w) => (w.deselectIncorrectSelectedChoices = jest.fn()),
1375
- );
1376
-
1377
- // Guard: If our test data were to cause this to return an empty
1378
- // array, the rest of the assertions in this test would pass.
1379
- expect(widgets.length).toBeGreaterThan(0);
1380
-
1381
- // Act
1382
- renderer.deselectIncorrectSelectedChoices();
1383
-
1384
- // Assert
1385
- widgets.forEach((w) =>
1386
- expect(w.deselectIncorrectSelectedChoices).toHaveBeenCalled(),
1387
- );
1388
- });
1389
-
1390
- it("should return user input", () => {
1391
- // Arrange
1392
- const {renderer} = renderQuestion({
1393
- ...question2,
1394
- content:
1395
- "Input 1: [[☃ input-number 1]]\n\n" +
1396
- "Input 2: [[☃ input-number 2]]\n\n" +
1397
- "A widget that doesn't implement getUserInput: [[☃ image 1]]",
1398
- widgets: {
1399
- ...question2.widgets,
1400
- "input-number 2": {
1401
- ...question2.widgets["input-number 1"],
1402
- static: true,
1403
- },
1404
- "image 1": {
1405
- type: "image",
1406
- graded: false,
1407
- options: {
1408
- backgroundImage: {
1409
- url: "https://example.com/cat.png",
1410
- width: 100,
1411
- height: 100,
1412
- },
1413
- },
1414
- },
1415
- },
1416
- });
1417
-
1418
- screen
1419
- .getAllByRole("textbox")
1420
- .forEach((el, i) => userEvent.type(el, i.toString()));
1421
-
1422
- // Act
1423
- const input = renderer.getUserInput();
1424
-
1425
- // Assert
1426
- expect(input).toStrictEqual([
1427
- {currentValue: "0"},
1428
- {currentValue: "1"},
1429
- null, // image widget doesn't implement getUserinput
1430
- ]);
1431
- });
1432
-
1433
- it("should return all widget IDs that were rendererd", () => {
1434
- // Arrange
1435
- const {renderer} = renderQuestion({
1436
- ...question2,
1437
- content:
1438
- "Input 1: [[☃ input-number 1]]\n\n" +
1439
- "Input 2: [[☃ input-number 2]]\n\n" +
1440
- "A widget that doesn't implement getUserInput: [[☃ image 1]]",
1441
- widgets: {
1442
- ...question2.widgets,
1443
- "input-number 2": {
1444
- ...question2.widgets["input-number 1"],
1445
- static: true,
1446
- },
1447
- "image 1": {
1448
- type: "image",
1449
- graded: false,
1450
- options: {
1451
- backgroundImage: {
1452
- url: "https://example.com/cat.png",
1453
- width: 100,
1454
- height: 100,
1455
- },
1456
- },
1457
- },
1458
- },
1459
- });
1460
-
1461
- // Act
1462
- const widgetIds = renderer.getWidgetIds();
1463
-
1464
- // Assert
1465
- expect(widgetIds).toStrictEqual([
1466
- "input-number 1",
1467
- "input-number 2",
1468
- "image 1",
1469
- ]);
1470
- });
1471
- });
1472
-
1473
- describe("getDOMNodeForPath", () => {
1474
- it("should return the DOM node for the widget at requested FocusPath", () => {
1475
- // Arrange
1476
- const {renderer} = renderQuestion(question1);
1477
-
1478
- // Act
1479
- const node = renderer.getDOMNodeForPath(["dropdown 1"]);
1480
-
1481
- // Assert
1482
- // "button" role is the WB dropdown's "opener" element
1483
- // $FlowIgnore[incompatible-call]
1484
- expect(within(node).queryAllByRole("button")).toHaveLength(1);
1485
- });
1486
-
1487
- it("should return the widget's getDOMNodeForPath() result for the widget at requested FocusPath", () => {
1488
- // Arrange
1489
- const {renderer} = renderQuestion(mockedItem);
1490
- const widget2DOMNode = <span />;
1491
- const [widget2] = renderer.findWidgets("mock-widget 2");
1492
- widget2.getDOMNodeForPath = jest.fn(() => widget2DOMNode);
1493
-
1494
- // Act
1495
- const node = renderer.getDOMNodeForPath(["mock-widget 2"]);
1496
-
1497
- // Assert
1498
- expect(node).toBe(widget2DOMNode);
1499
- });
1500
- });
1501
-
1502
- describe("getGrammarTypeForPath", () => {
1503
- it("should return undefined if matching widget doesn't implement getGrammarTypeForPath", () => {
1504
- // Arrange
1505
- const {renderer} = renderQuestion(question1);
1506
-
1507
- // Act
1508
- const grammarType = renderer.getGrammarTypeForPath(["dropdown 1"]);
1509
-
1510
- // Assert
1511
- expect(grammarType).toBeUndefined();
1512
- });
1513
-
1514
- it("should return widget result if matching widget implements getGrammarTypeForPath", () => {
1515
- // Arrange
1516
- const {renderer} = renderQuestion(question2);
1517
-
1518
- // Act
1519
- const grammarType = renderer.getGrammarTypeForPath([
1520
- "input-number 1",
1521
- ]);
1522
-
1523
- // Assert
1524
- expect(grammarType).toBe("number");
1525
- });
1526
- });
1527
-
1528
- describe("getInputPaths", () => {
1529
- it("should return all input paths for all rendererd widgets", () => {
1530
- // Arrange
1531
- const {renderer} = renderQuestion(mockedItem);
1532
- const [mockWidget1, mockWidget2, mockWidget3] =
1533
- renderer.findWidgets((id) =>
1534
- [
1535
- "mock-widget 1",
1536
- "mock-widget 2",
1537
- "mock-widget 3",
1538
- ].includes(id),
1539
- );
1540
- mockWidget1.getInputPaths = jest.fn(() => ["input 1"]);
1541
- mockWidget2.getInputPaths = jest.fn(() => ["input 2", "input 3"]);
1542
- mockWidget3.getInputPaths = jest.fn(() => [
1543
- ["input 4", "sub-input 4.1"],
1544
- "input 5",
1545
- ]);
1546
-
1547
- // Act
1548
- const inputPaths = renderer.getInputPaths();
1549
-
1550
- // Assert
1551
- expect(inputPaths).toMatchInlineSnapshot(`
1552
- [
1553
- [
1554
- "mock-widget 1",
1555
- "input 1",
1556
- ],
1557
- [
1558
- "mock-widget 2",
1559
- "input 2",
1560
- ],
1561
- [
1562
- "mock-widget 2",
1563
- "input 3",
1564
- ],
1565
- [
1566
- "mock-widget 3",
1567
- "input 4",
1568
- "sub-input 4.1",
1569
- ],
1570
- [
1571
- "mock-widget 3",
1572
- "input 5",
1573
- ],
1574
- ]
1575
- `);
1576
- });
1577
- });
1578
-
1579
- describe("emptyWidgets", () => {
1580
- it("should return all empty widgets", () => {
1581
- // Arrange
1582
- const {renderer} = renderQuestion({
1583
- ...question2,
1584
- content:
1585
- "Input 1: [[☃ input-number 1]]\n\n" +
1586
- "Input 2: [[☃ input-number 2]]",
1587
- widgets: {
1588
- ...question2.widgets,
1589
- "input-number 2": question2.widgets["input-number 1"],
1590
- },
1591
- });
1592
- userEvent.type(screen.getAllByRole("textbox")[0], "150");
1593
-
1594
- // Act
1595
- const emptyWidgets = renderer.emptyWidgets();
1596
-
1597
- // Assert
1598
- expect(emptyWidgets).toStrictEqual(["input-number 2"]);
1599
- });
1600
-
1601
- it("should not return static widgets even if empty", () => {
1602
- // Arrange
1603
- const {renderer} = renderQuestion({
1604
- ...question2,
1605
- content:
1606
- "Input 1: [[☃ input-number 1]]\n\n" +
1607
- "Input 2: [[☃ input-number 2]]",
1608
- widgets: {
1609
- ...question2.widgets,
1610
- "input-number 2": {
1611
- ...question2.widgets["input-number 1"],
1612
- static: true,
1613
- },
1614
- },
1615
- });
1616
-
1617
- // Act
1618
- const emptyWidgets = renderer.emptyWidgets();
1619
-
1620
- // Assert
1621
- expect(emptyWidgets).toStrictEqual(["input-number 1"]);
1622
- });
1623
- });
1624
-
1625
- describe("setInputValue", () => {
1626
- it("should set the value on the requested FocusPath", () => {
1627
- // Arrange
1628
- const {renderer} = renderQuestion({
1629
- ...question2,
1630
- content:
1631
- "Input 1: [[☃ input-number 1]]\n\n" +
1632
- "Input 2: [[☃ input-number 2]]",
1633
- widgets: {
1634
- ...question2.widgets,
1635
- "input-number 2": {
1636
- ...question2.widgets["input-number 1"],
1637
- static: true,
1638
- },
1639
- },
1640
- });
1641
- const cb = jest.fn();
1642
-
1643
- // Act
1644
- renderer.setInputValue(["input-number 2"], "1000", cb);
1645
-
1646
- // Assert
1647
- expect(screen.getAllByRole("textbox")[0]).toHaveValue("");
1648
- expect(screen.getAllByRole("textbox")[1]).toHaveValue("1000");
1649
- });
1650
-
1651
- it("should call the focus callback when value is complete", () => {
1652
- // Arrange
1653
- const {renderer} = renderQuestion({
1654
- ...question2,
1655
- content:
1656
- "Input 1: [[☃ input-number 1]]\n\n" +
1657
- "Input 2: [[☃ input-number 2]]",
1658
- widgets: {
1659
- ...question2.widgets,
1660
- "input-number 2": {
1661
- ...question2.widgets["input-number 1"],
1662
- static: true,
1663
- },
1664
- },
1665
- });
1666
- const cb = jest.fn();
1667
-
1668
- // Act
1669
- renderer.setInputValue(["input-number 2"], "1000", cb);
1670
- jest.runOnlyPendingTimers();
1671
-
1672
- // Assert
1673
- expect(cb).toHaveBeenCalled();
1674
- });
1675
- });
1676
-
1677
- describe("getUserInputForWidgets", () => {
1678
- it("should return user input for all rendered widgets", () => {
1679
- // Arrange
1680
- const {renderer} = renderQuestion({
1681
- content:
1682
- "Input widget: [[\u2603 input-number 1]]\n\n" +
1683
- "Dropdown widget: [[\u2603 dropdown 1]]\n\n" +
1684
- "Image widget (won't have user input): [[\u2603 image 1]]\n\n" +
1685
- "Another input widget: [[\u2603 input-number 2]]",
1686
- widgets: {
1687
- "image 1": imageWidget,
1688
- "input-number 1": inputNumberWidget,
1689
- "input-number 2": inputNumberWidget,
1690
- "dropdown 1": dropdownWidget,
1691
- },
1692
- images: {},
1693
- });
1694
-
1695
- userEvent.type(screen.getAllByRole("textbox")[0], "100");
1696
- userEvent.type(screen.getAllByRole("textbox")[1], "200");
1697
-
1698
- // Open the dropdown and select the second (idx: 1) item
1699
- userEvent.click(screen.getByRole("button"));
1700
- jest.runOnlyPendingTimers();
1701
- userEvent.click(screen.getAllByRole("option")[1]);
1702
- jest.runOnlyPendingTimers();
1703
-
1704
- // Act
1705
- const userInput = renderer.getUserInputForWidgets();
1706
-
1707
- // Assert
1708
- expect(userInput).toMatchInlineSnapshot(`
1709
- {
1710
- "dropdown 1": {
1711
- "value": 1,
1712
- },
1713
- "image 1": null,
1714
- "input-number 1": {
1715
- "currentValue": "100",
1716
- },
1717
- "input-number 2": {
1718
- "currentValue": "200",
1719
- },
1720
- }
1721
- `);
1722
- });
1723
- });
1724
-
1725
- describe("examples", () => {
1726
- it("should return examples if all widgets return the same examples (or null)", () => {
1727
- // Arrange
1728
- const {renderer} = renderQuestion({
1729
- content:
1730
- "Input widget: [[\u2603 input-number 1]]\n\n" +
1731
- "Dropdown widget: [[\u2603 dropdown 1]]\n\n" +
1732
- "Image widget (won't have user input): [[\u2603 image 1]]\n\n" +
1733
- "Another input widget: [[\u2603 input-number 2]]",
1734
- widgets: {
1735
- "image 1": imageWidget,
1736
- "input-number 1": inputNumberWidget,
1737
- "input-number 2": inputNumberWidget,
1738
- "dropdown 1": dropdownWidget,
1739
- },
1740
- images: {},
1741
- });
1742
-
1743
- // Act
1744
- const examples = renderer.examples();
1745
-
1746
- // Assert
1747
- expect(examples).toMatchInlineSnapshot(`
1748
- [
1749
- "**Your answer should be** ",
1750
- "an integer, like $6$",
1751
- "a *proper* fraction, like $1/2$ or $6/10$",
1752
- "an *improper* fraction, like $10/7$ or $14/8$",
1753
- "a mixed number, like $1\\ 3/4$",
1754
- ]
1755
- `);
1756
- });
1757
-
1758
- it("should return nothing if widgets return the different examples", () => {
1759
- // NOTE(jeremy): I'm unsure why we don't return examples if the
1760
- // examples aren't the same, but this is current functionality so
1761
- // I'm adding this test to verify the current behaviour.
1762
-
1763
- // Arrange
1764
- const {renderer} = renderQuestion({
1765
- content:
1766
- "Input widget: [[\u2603 input-number 1]]\n\n" +
1767
- "Dropdown widget: [[\u2603 dropdown 1]]\n\n" +
1768
- "Image widget (won't have user input): [[\u2603 image 1]]\n\n" +
1769
- "Another input widget: [[\u2603 input-number 2]]",
1770
- widgets: {
1771
- "image 1": imageWidget,
1772
- "input-number 1": inputNumberWidget,
1773
- "input-number 2": {
1774
- ...inputNumberWidget,
1775
- options: (({
1776
- ...inputNumberWidget.options,
1777
- answerType: "percent",
1778
- }: any): PerseusInputNumberWidgetOptions),
1779
- },
1780
- "dropdown 1": dropdownWidget,
1781
- },
1782
- images: {},
1783
- });
1784
-
1785
- // Act
1786
- const examples = renderer.examples();
1787
-
1788
- // Assert
1789
- expect(examples).toBeNull();
1790
- });
1791
- });
1792
- });