@khanacademy/perseus 3.0.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 (1210) hide show
  1. package/.babelrc.js +1 -1
  2. package/.eslintrc.js +1 -0
  3. package/CHANGELOG.md +16 -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 +10880 -14498
  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 +12443 -15871
  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__/categorizer.test.ts +203 -0
  691. package/src/widgets/__tests__/cs-program.test.ts +43 -0
  692. package/src/widgets/__tests__/definition.test.ts +136 -0
  693. package/src/widgets/__tests__/dropdown.test.ts +105 -0
  694. package/src/widgets/__tests__/explanation.test.ts +198 -0
  695. package/src/widgets/__tests__/expression.test.ts +431 -0
  696. package/src/widgets/__tests__/graded-group-set-jipt.test.ts +30 -0
  697. package/src/widgets/__tests__/graded-group-set.test.ts +288 -0
  698. package/src/widgets/__tests__/graded-group.test.ts +232 -0
  699. package/src/widgets/__tests__/grapher.cypress.ts +576 -0
  700. package/src/widgets/__tests__/grapher.test.ts +33 -0
  701. package/src/widgets/__tests__/group.test.tsx +512 -0
  702. package/src/widgets/__tests__/iframe.test.ts +45 -0
  703. package/src/widgets/__tests__/image.test.ts +62 -0
  704. package/src/widgets/__tests__/input-number.test.ts +354 -0
  705. package/src/widgets/__tests__/interaction.test.ts +31 -0
  706. package/src/widgets/__tests__/interactive-graph.cypress.ts +815 -0
  707. package/src/widgets/__tests__/interactive-graph.test.ts +106 -0
  708. package/src/widgets/__tests__/matcher.test.tsx +152 -0
  709. package/src/widgets/__tests__/matrix.test.ts +82 -0
  710. package/src/widgets/__tests__/number-line.test.ts +79 -0
  711. package/src/widgets/__tests__/numeric-input.test.ts +502 -0
  712. package/src/widgets/__tests__/orderer.test.ts +73 -0
  713. package/src/widgets/__tests__/passage-ref.test.ts +168 -0
  714. package/src/widgets/__tests__/passage.test.tsx +224 -0
  715. package/src/widgets/__tests__/radio/base-radio.test.tsx +470 -0
  716. package/src/widgets/__tests__/radio/choice-icon.test.tsx +90 -0
  717. package/src/widgets/__tests__/radio/choice.test.tsx +310 -0
  718. package/src/widgets/__tests__/radio/focus-ring.test.tsx +23 -0
  719. package/src/widgets/__tests__/radio/option-status.test.tsx +77 -0
  720. package/src/widgets/__tests__/radio.test.ts +807 -0
  721. package/src/widgets/__tests__/renderQuestion.tsx +77 -0
  722. package/src/widgets/__tests__/unit.test.tsx +168 -0
  723. package/src/widgets/__tests__/video.test.ts +53 -0
  724. package/src/widgets/categorizer.tsx +343 -0
  725. package/src/widgets/cs-program.tsx +227 -0
  726. package/src/widgets/definition.tsx +121 -0
  727. package/src/widgets/dropdown.tsx +142 -0
  728. package/src/widgets/explanation.tsx +317 -0
  729. package/src/widgets/expression.tsx +647 -0
  730. package/src/widgets/graded-group-answer-bar.tsx +142 -0
  731. package/src/widgets/graded-group-set.tsx +296 -0
  732. package/src/widgets/graded-group.tsx +466 -0
  733. package/src/widgets/grapher/util.tsx +803 -0
  734. package/src/widgets/grapher.tsx +674 -0
  735. package/src/widgets/group.tsx +196 -0
  736. package/src/widgets/iframe.tsx +195 -0
  737. package/src/widgets/image.tsx +309 -0
  738. package/src/widgets/input-number.tsx +413 -0
  739. package/src/widgets/interaction/arrow-picker.tsx +38 -0
  740. package/src/widgets/interaction/color-picker.tsx +69 -0
  741. package/src/widgets/interaction/dash-picker.tsx +45 -0
  742. package/src/widgets/interaction/element-container.tsx +101 -0
  743. package/src/widgets/interaction.tsx +826 -0
  744. package/src/widgets/interactive-graph.tsx +2921 -0
  745. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +98 -0
  746. package/src/widgets/label-image/__stories__/marker.stories.tsx +181 -0
  747. package/src/widgets/label-image/answer-choices.tsx +300 -0
  748. package/src/widgets/label-image/marker.tsx +364 -0
  749. package/src/widgets/label-image/types.ts +26 -0
  750. package/src/widgets/label-image.test.ts +840 -0
  751. package/src/widgets/label-image.tsx +849 -0
  752. package/src/widgets/lights-puzzle.tsx +359 -0
  753. package/src/widgets/matcher.tsx +278 -0
  754. package/src/widgets/matrix.tsx +637 -0
  755. package/src/widgets/measurer.tsx +217 -0
  756. package/src/widgets/molecule/__tests__/layout.test.ts +162 -0
  757. package/src/widgets/molecule/__tests__/parser.test.ts +155 -0
  758. package/src/widgets/molecule/molecule-drawing.ts +173 -0
  759. package/src/widgets/molecule/molecule-layout.ts +362 -0
  760. package/src/widgets/molecule/smiles-parser.ts +296 -0
  761. package/src/widgets/molecule.tsx +172 -0
  762. package/src/widgets/number-line.tsx +864 -0
  763. package/src/widgets/numeric-input.tsx +563 -0
  764. package/src/widgets/orderer.tsx +788 -0
  765. package/src/widgets/passage/__tests__/passage-markdown.test.ts +376 -0
  766. package/src/widgets/passage/passage-markdown.tsx +475 -0
  767. package/src/widgets/passage-ref-target.tsx +73 -0
  768. package/src/widgets/passage-ref.tsx +215 -0
  769. package/src/widgets/passage.tsx +584 -0
  770. package/src/widgets/plotter.tsx +1204 -0
  771. package/src/widgets/radio/__stories__/base-radio.stories.tsx +204 -0
  772. package/src/widgets/radio/__stories__/choice-icon.stories.tsx +168 -0
  773. package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +40 -0
  774. package/src/widgets/radio/__stories__/choice.stories.tsx +137 -0
  775. package/src/widgets/radio/__stories__/focus-ring.stories.tsx +43 -0
  776. package/src/widgets/radio/__stories__/option-status.stories.tsx +105 -0
  777. package/src/widgets/radio/base-radio.tsx +509 -0
  778. package/src/widgets/radio/choice-a11y-text.ts +61 -0
  779. package/src/widgets/radio/choice-icon/choice-icon.tsx +217 -0
  780. package/src/widgets/radio/choice-icon/cross-out-line.tsx +53 -0
  781. package/src/widgets/radio/choice-icon/shared-styles.ts +15 -0
  782. package/src/widgets/radio/choice-none-above.tsx +56 -0
  783. package/src/widgets/radio/choice.jsx.fixture.ts +45 -0
  784. package/src/widgets/radio/choice.tsx +358 -0
  785. package/src/widgets/radio/focus-ring.tsx +57 -0
  786. package/src/widgets/radio/option-status.tsx +100 -0
  787. package/src/widgets/radio/util.test.ts +18 -0
  788. package/src/widgets/radio/util.ts +31 -0
  789. package/src/widgets/radio/widget.tsx +521 -0
  790. package/src/widgets/radio.ts +157 -0
  791. package/src/widgets/reaction-diagram.tsx +144 -0
  792. package/src/widgets/sequence.tsx +137 -0
  793. package/src/widgets/simulator.tsx +831 -0
  794. package/src/widgets/sorter.tsx +154 -0
  795. package/src/widgets/table.tsx +393 -0
  796. package/src/widgets/transformer.tsx +2951 -0
  797. package/src/widgets/unit.tsx +374 -0
  798. package/src/widgets/video-transcript-link.test.tsx +213 -0
  799. package/src/widgets/video-transcript-link.tsx +84 -0
  800. package/src/widgets/video.tsx +124 -0
  801. package/src/widgets.ts +444 -0
  802. package/src/zoom.ts +558 -0
  803. package/tsconfig.json +25 -0
  804. package/tsconfig.tsbuildinfo +1 -0
  805. package/src/__stories__/hints-renderer.stories.jsx +0 -60
  806. package/src/__stories__/item-renderer.stories.jsx +0 -27
  807. package/src/__stories__/server-item-renderer.stories.jsx +0 -27
  808. package/src/__testdata__/graphie_testdata.js +0 -53
  809. package/src/__testdata__/item-renderer_testdata.js +0 -161
  810. package/src/__testdata__/renderer_testdata.js +0 -123
  811. package/src/__tests__/a11y_test.jsx +0 -304
  812. package/src/__tests__/item-renderer_test.jsx +0 -892
  813. package/src/__tests__/jipt-paragraphs_test.js +0 -34
  814. package/src/__tests__/mock-asset-loading-widget.jsx +0 -57
  815. package/src/__tests__/mock-widget.jsx +0 -35
  816. package/src/__tests__/perseus-markdown_test.jsx +0 -747
  817. package/src/__tests__/renderability_test.jsx +0 -481
  818. package/src/__tests__/renderer-api_test.jsx +0 -309
  819. package/src/__tests__/renderer_test.jsx +0 -1792
  820. package/src/__tests__/server-item-renderer_test.jsx +0 -516
  821. package/src/__tests__/test-items/image-item.js +0 -25
  822. package/src/__tests__/test-items/input-number-1-item.js +0 -27
  823. package/src/__tests__/test-items/input-number-2-item.js +0 -39
  824. package/src/__tests__/test-items/table-item.js +0 -30
  825. package/src/__tests__/tex-wrangler_test.js +0 -83
  826. package/src/__tests__/util_test.js +0 -41
  827. package/src/a11y.js +0 -46
  828. package/src/all-widgets.js +0 -9
  829. package/src/article-renderer.jsx +0 -214
  830. package/src/asset-context.js +0 -30
  831. package/src/basic-widgets.js +0 -13
  832. package/src/components/__stories__/button-group.stories.jsx +0 -61
  833. package/src/components/__stories__/fixed-to-responsive.stories.jsx +0 -132
  834. package/src/components/__stories__/graph.stories.jsx +0 -27
  835. package/src/components/__stories__/graphie.stories.jsx +0 -32
  836. package/src/components/__stories__/hud.stories.jsx +0 -36
  837. package/src/components/__stories__/icon.stories.jsx +0 -56
  838. package/src/components/__stories__/image-loader.stories.jsx +0 -60
  839. package/src/components/__stories__/info-tip.stories.jsx +0 -33
  840. package/src/components/__stories__/inline-icon.stories.jsx +0 -39
  841. package/src/components/__stories__/input-with-examples.stories.jsx +0 -52
  842. package/src/components/__stories__/lint.stories.jsx +0 -40
  843. package/src/components/__stories__/math-input.stories.jsx +0 -29
  844. package/src/components/__stories__/math-output.stories.jsx +0 -24
  845. package/src/components/__stories__/multi-button-group.stories.jsx +0 -69
  846. package/src/components/__stories__/number-input.stories.jsx +0 -42
  847. package/src/components/__stories__/prop-check-box.stories.jsx +0 -62
  848. package/src/components/__stories__/range-input.stories.jsx +0 -28
  849. package/src/components/__stories__/simple-keypad-input.stories.jsx +0 -28
  850. package/src/components/__stories__/sortable.stories.jsx +0 -73
  851. package/src/components/__stories__/stub-tag-editor.stories.jsx +0 -44
  852. package/src/components/__stories__/svg-image.stories.jsx +0 -71
  853. package/src/components/__stories__/tex.stories.jsx +0 -24
  854. package/src/components/__stories__/text-buttons.stories.jsx +0 -51
  855. package/src/components/__stories__/text-input.stories.jsx +0 -34
  856. package/src/components/__stories__/text-list-editor.stories.jsx +0 -33
  857. package/src/components/__stories__/zoomable-tex.stories.jsx +0 -39
  858. package/src/components/__stories__/zoomable.stories.jsx +0 -40
  859. package/src/components/__testdata__/sorter_testdata.js +0 -20
  860. package/src/components/__tests__/number-input_test.jsx +0 -112
  861. package/src/components/__tests__/sortable_test.jsx +0 -234
  862. package/src/components/__tests__/sorter_test.jsx +0 -111
  863. package/src/components/__tests__/zoomable_test.jsx +0 -388
  864. package/src/components/button-group.jsx +0 -131
  865. package/src/components/constants.js +0 -15
  866. package/src/components/fixed-to-responsive.jsx +0 -165
  867. package/src/components/graph.jsx +0 -413
  868. package/src/components/graphie-classes.jsx +0 -148
  869. package/src/components/graphie-movables.jsx +0 -342
  870. package/src/components/graphie.jsx +0 -353
  871. package/src/components/highlighting/highlightable-content.jsx +0 -245
  872. package/src/components/highlighting/highlights.js +0 -208
  873. package/src/components/highlighting/ranges.js +0 -299
  874. package/src/components/highlighting/types.js +0 -73
  875. package/src/components/highlighting/ui/highlight-renderer.jsx +0 -179
  876. package/src/components/highlighting/ui/highlight-set-renderer.jsx +0 -190
  877. package/src/components/highlighting/ui/highlight-tooltip.jsx +0 -143
  878. package/src/components/highlighting/ui/highlighting-ui.jsx +0 -163
  879. package/src/components/highlighting/ui/selection-tracker.jsx +0 -184
  880. package/src/components/highlighting/ui/types.js +0 -21
  881. package/src/components/highlighting/ui/util.js +0 -166
  882. package/src/components/highlighting/word-indexer.jsx +0 -155
  883. package/src/components/hud.jsx +0 -179
  884. package/src/components/icon.jsx +0 -149
  885. package/src/components/image-loader.jsx +0 -175
  886. package/src/components/info-tip/info-tip.jsx +0 -146
  887. package/src/components/info-tip.jsx +0 -38
  888. package/src/components/inline-icon.jsx +0 -81
  889. package/src/components/input-with-examples.jsx +0 -248
  890. package/src/components/lint.jsx +0 -455
  891. package/src/components/math-input.jsx +0 -293
  892. package/src/components/math-output.jsx +0 -128
  893. package/src/components/multi-button-group.jsx +0 -137
  894. package/src/components/number-input.jsx +0 -253
  895. package/src/components/prop-check-box.jsx +0 -80
  896. package/src/components/range-input.jsx +0 -61
  897. package/src/components/simple-keypad-input.jsx +0 -88
  898. package/src/components/sortable.jsx +0 -872
  899. package/src/components/stub-tag-editor.jsx +0 -54
  900. package/src/components/svg-image.jsx +0 -765
  901. package/src/components/tex-buttons.jsx +0 -320
  902. package/src/components/tex.jsx +0 -70
  903. package/src/components/text-input.jsx +0 -133
  904. package/src/components/text-list-editor.jsx +0 -157
  905. package/src/components/tooltip.jsx +0 -392
  906. package/src/components/visibility-observer/__stories__/visibility-observer.stories.jsx +0 -140
  907. package/src/components/visibility-observer/get-scroll-parent.js +0 -45
  908. package/src/components/visibility-observer/visibility-observer.js +0 -109
  909. package/src/components/visibility-observer/visibility-observer.jsx +0 -123
  910. package/src/components/zoomable-tex.jsx +0 -70
  911. package/src/components/zoomable.jsx +0 -294
  912. package/src/components.js +0 -17
  913. package/src/definition-context.js +0 -59
  914. package/src/dependencies.js +0 -22
  915. package/src/error-boundary.jsx +0 -48
  916. package/src/extra-widgets.js +0 -75
  917. package/src/hint-renderer.jsx +0 -152
  918. package/src/hints-renderer.jsx +0 -367
  919. package/src/icon-paths.js +0 -120
  920. package/src/index.js +0 -159
  921. package/src/init.js +0 -49
  922. package/src/interaction-tracker.js +0 -60
  923. package/src/interactive2/__tests__/movable-mock.js +0 -48
  924. package/src/interactive2/__tests__/movable-point_test.js +0 -146
  925. package/src/interactive2/interactive-util.js +0 -152
  926. package/src/interactive2/movable-helper-methods.js +0 -160
  927. package/src/interactive2/movable-line-options.js +0 -392
  928. package/src/interactive2/movable-line.js +0 -322
  929. package/src/interactive2/movable-point-options.js +0 -190
  930. package/src/interactive2/movable-point.jsx +0 -597
  931. package/src/interactive2/movable-polygon-options.js +0 -351
  932. package/src/interactive2/movable-polygon.js +0 -368
  933. package/src/interactive2/movable.js +0 -273
  934. package/src/interactive2/objective_.js +0 -79
  935. package/src/interactive2/types.js +0 -3
  936. package/src/interactive2/wrapped-defaults.js +0 -86
  937. package/src/interactive2/wrapped-ellipse.js +0 -86
  938. package/src/interactive2/wrapped-line.js +0 -109
  939. package/src/interactive2/wrapped-path.js +0 -47
  940. package/src/interactive2.js +0 -91
  941. package/src/item-renderer.jsx +0 -514
  942. package/src/item-version.js +0 -12
  943. package/src/jipt-paragraphs.js +0 -52
  944. package/src/keypad-context.js +0 -33
  945. package/src/loading-context.js +0 -20
  946. package/src/logging/log.js +0 -107
  947. package/src/logging/log_test.js +0 -41
  948. package/src/mixins/__tests__/widget-prop-denylist_test.js +0 -23
  949. package/src/mixins/changeable.jsx +0 -115
  950. package/src/mixins/editor-jsonify.jsx +0 -13
  951. package/src/mixins/provide-keypad.jsx +0 -131
  952. package/src/mixins/widget-jsonify-deprecated.jsx +0 -23
  953. package/src/mixins/widget-prop-denylist.js +0 -49
  954. package/src/multi-items/__stories__/multi-renderer.stories.js +0 -88
  955. package/src/multi-items/__testdata__/multi-renderer_testdata.js +0 -174
  956. package/src/multi-items/__tests__/items_test.js +0 -245
  957. package/src/multi-items/__tests__/multi-renderer_test.js +0 -903
  958. package/src/multi-items/__tests__/prop-type-builders_test.js +0 -134
  959. package/src/multi-items/__tests__/shapes_test.js +0 -44
  960. package/src/multi-items/__tests__/trees_test.js +0 -316
  961. package/src/multi-items/items.js +0 -176
  962. package/src/multi-items/multi-renderer.jsx +0 -543
  963. package/src/multi-items/prop-type-builders.js +0 -105
  964. package/src/multi-items/shape-types.js +0 -47
  965. package/src/multi-items/shapes.js +0 -53
  966. package/src/multi-items/tree-types.js +0 -42
  967. package/src/multi-items/trees.js +0 -345
  968. package/src/multi-items.js +0 -76
  969. package/src/perseus-api.jsx +0 -214
  970. package/src/perseus-env.js +0 -26
  971. package/src/perseus-error.js +0 -19
  972. package/src/perseus-markdown.jsx +0 -408
  973. package/src/perseus-types.js +0 -1471
  974. package/src/question-paragraph.jsx +0 -30
  975. package/src/renderability.jsx +0 -108
  976. package/src/renderer.jsx +0 -1937
  977. package/src/server-item-renderer.jsx +0 -467
  978. package/src/sigfigs.jsx +0 -492
  979. package/src/styles/constants.js +0 -96
  980. package/src/styles/global-constants.js +0 -344
  981. package/src/styles/global-styles.js +0 -307
  982. package/src/styles/media-queries.js +0 -48
  983. package/src/styles/shared.js +0 -132
  984. package/src/tex-wrangler.js +0 -176
  985. package/src/translation-linter.js +0 -125
  986. package/src/traversal.jsx +0 -141
  987. package/src/types.js +0 -482
  988. package/src/util/a11y.js +0 -24
  989. package/src/util/answer-types.js +0 -861
  990. package/src/util/answer-types_test.js +0 -115
  991. package/src/util/colors.js +0 -94
  992. package/src/util/fix-passage-refs.jsx +0 -122
  993. package/src/util/graph-utils.js +0 -16
  994. package/src/util/graphie.js +0 -1586
  995. package/src/util/interactive.js +0 -4078
  996. package/src/util/katex-preprocess.js +0 -16
  997. package/src/util/math.js +0 -289
  998. package/src/util/mobile-native-utils.js +0 -14
  999. package/src/util/mobile-native-utils_test.js +0 -24
  1000. package/src/util/react-render.js +0 -27
  1001. package/src/util/register-all-widgets-for-testing.js +0 -12
  1002. package/src/util/scroll-utils.js +0 -162
  1003. package/src/util/sizing-utils.js +0 -46
  1004. package/src/util/tex.js +0 -203
  1005. package/src/util/url-utils.js +0 -36
  1006. package/src/util.js +0 -984
  1007. package/src/version.js +0 -11
  1008. package/src/widget-container.jsx +0 -178
  1009. package/src/widgets/__stories__/categorizer.stories.jsx +0 -15
  1010. package/src/widgets/__stories__/cs-program.stories.jsx +0 -15
  1011. package/src/widgets/__stories__/definition.stories.jsx +0 -108
  1012. package/src/widgets/__stories__/dropdown.stories.jsx +0 -15
  1013. package/src/widgets/__stories__/explanation.stories.jsx +0 -19
  1014. package/src/widgets/__stories__/expression.stories.jsx +0 -26
  1015. package/src/widgets/__stories__/graded-group-set.stories.jsx +0 -32
  1016. package/src/widgets/__stories__/graded-group.stories.jsx +0 -32
  1017. package/src/widgets/__stories__/grapher.stories.jsx +0 -47
  1018. package/src/widgets/__stories__/group.stories.jsx +0 -15
  1019. package/src/widgets/__stories__/iframe.stories.jsx +0 -15
  1020. package/src/widgets/__stories__/image.stories.jsx +0 -62
  1021. package/src/widgets/__stories__/input-number.stories.jsx +0 -102
  1022. package/src/widgets/__stories__/interaction.stories.jsx +0 -15
  1023. package/src/widgets/__stories__/interactive-graph.stories.jsx +0 -61
  1024. package/src/widgets/__stories__/matcher.stories.jsx +0 -15
  1025. package/src/widgets/__stories__/matrix.stories.jsx +0 -15
  1026. package/src/widgets/__stories__/number-line.stories.jsx +0 -15
  1027. package/src/widgets/__stories__/numeric-input.stories.jsx +0 -106
  1028. package/src/widgets/__stories__/on-screen-keypad.stories.jsx +0 -118
  1029. package/src/widgets/__stories__/orderer.stories.jsx +0 -15
  1030. package/src/widgets/__stories__/passage-ref.stories.jsx +0 -23
  1031. package/src/widgets/__stories__/passage.stories.jsx +0 -27
  1032. package/src/widgets/__stories__/radio.stories.jsx +0 -90
  1033. package/src/widgets/__stories__/sorter.stories.jsx +0 -15
  1034. package/src/widgets/__stories__/transformer.stories.jsx +0 -15
  1035. package/src/widgets/__stories__/unit.stories.jsx +0 -29
  1036. package/src/widgets/__stories__/video-transcript-link.stories.jsx +0 -24
  1037. package/src/widgets/__stories__/video.stories.jsx +0 -15
  1038. package/src/widgets/__testdata__/base-radio_testdata.js +0 -22
  1039. package/src/widgets/__testdata__/categorizer_testdata.js +0 -50
  1040. package/src/widgets/__testdata__/cs-program_testdata.js +0 -28
  1041. package/src/widgets/__testdata__/dropdown_testdata.js +0 -34
  1042. package/src/widgets/__testdata__/explanation_testdata.js +0 -56
  1043. package/src/widgets/__testdata__/expression_testdata.js +0 -95
  1044. package/src/widgets/__testdata__/graded-group-set_testdata.js +0 -358
  1045. package/src/widgets/__testdata__/graded-group_testdata.js +0 -79
  1046. package/src/widgets/__testdata__/grapher_testdata.js +0 -376
  1047. package/src/widgets/__testdata__/group_testdata.js +0 -156
  1048. package/src/widgets/__testdata__/iframe_testdata.js +0 -36
  1049. package/src/widgets/__testdata__/image_testdata.js +0 -38
  1050. package/src/widgets/__testdata__/input-number_testdata.js +0 -73
  1051. package/src/widgets/__testdata__/interaction_testdata.js +0 -264
  1052. package/src/widgets/__testdata__/interactive-graph_testdata.js +0 -646
  1053. package/src/widgets/__testdata__/matcher_testdata.js +0 -34
  1054. package/src/widgets/__testdata__/matrix_testdata.js +0 -29
  1055. package/src/widgets/__testdata__/number-line_testdata.js +0 -31
  1056. package/src/widgets/__testdata__/numeric-input_testdata.js +0 -266
  1057. package/src/widgets/__testdata__/orderer_testdata.js +0 -58
  1058. package/src/widgets/__testdata__/passage-ref_testdata.js +0 -103
  1059. package/src/widgets/__testdata__/passage_testdata.js +0 -96
  1060. package/src/widgets/__testdata__/radio_testdata.js +0 -262
  1061. package/src/widgets/__testdata__/sorter_testdata.js +0 -20
  1062. package/src/widgets/__testdata__/transformer_testdata.js +0 -109
  1063. package/src/widgets/__testdata__/video_testdata.js +0 -22
  1064. package/src/widgets/__tests__/categorizer_test.jsx +0 -205
  1065. package/src/widgets/__tests__/cs-program_test.jsx +0 -45
  1066. package/src/widgets/__tests__/definition_test.js +0 -137
  1067. package/src/widgets/__tests__/dropdown_test.jsx +0 -106
  1068. package/src/widgets/__tests__/explanation_test.js +0 -199
  1069. package/src/widgets/__tests__/expression_test.jsx +0 -429
  1070. package/src/widgets/__tests__/graded-group-set-jipt_test.jsx +0 -32
  1071. package/src/widgets/__tests__/graded-group-set_test.jsx +0 -290
  1072. package/src/widgets/__tests__/graded-group_test.jsx +0 -233
  1073. package/src/widgets/__tests__/grapher.cypress.jsx +0 -546
  1074. package/src/widgets/__tests__/grapher_test.jsx +0 -35
  1075. package/src/widgets/__tests__/group_test.jsx +0 -512
  1076. package/src/widgets/__tests__/iframe_test.jsx +0 -47
  1077. package/src/widgets/__tests__/image_test.jsx +0 -65
  1078. package/src/widgets/__tests__/input-number_test.jsx +0 -352
  1079. package/src/widgets/__tests__/interaction_test.jsx +0 -33
  1080. package/src/widgets/__tests__/interactive-graph.cypress.jsx +0 -777
  1081. package/src/widgets/__tests__/interactive-graph_test.jsx +0 -105
  1082. package/src/widgets/__tests__/matcher_test.jsx +0 -157
  1083. package/src/widgets/__tests__/matrix_test.jsx +0 -84
  1084. package/src/widgets/__tests__/number-line_test.jsx +0 -81
  1085. package/src/widgets/__tests__/numeric-input_test.jsx +0 -503
  1086. package/src/widgets/__tests__/orderer_test.jsx +0 -75
  1087. package/src/widgets/__tests__/passage-ref_test.jsx +0 -166
  1088. package/src/widgets/__tests__/passage_test.jsx +0 -212
  1089. package/src/widgets/__tests__/radio/base-radio_test.jsx +0 -443
  1090. package/src/widgets/__tests__/radio/choice-icon_test.jsx +0 -91
  1091. package/src/widgets/__tests__/radio/choice_test.jsx +0 -311
  1092. package/src/widgets/__tests__/radio/focus-ring_test.jsx +0 -23
  1093. package/src/widgets/__tests__/radio/option-status_test.jsx +0 -65
  1094. package/src/widgets/__tests__/radio_test.jsx +0 -810
  1095. package/src/widgets/__tests__/renderQuestion.jsx +0 -66
  1096. package/src/widgets/__tests__/unit_test.jsx +0 -169
  1097. package/src/widgets/__tests__/video_test.jsx +0 -55
  1098. package/src/widgets/categorizer.jsx +0 -343
  1099. package/src/widgets/cs-program.jsx +0 -227
  1100. package/src/widgets/definition.jsx +0 -121
  1101. package/src/widgets/dropdown.jsx +0 -141
  1102. package/src/widgets/explanation.jsx +0 -315
  1103. package/src/widgets/expression.jsx +0 -629
  1104. package/src/widgets/graded-group-answer-bar.jsx +0 -152
  1105. package/src/widgets/graded-group-set.jsx +0 -296
  1106. package/src/widgets/graded-group.jsx +0 -453
  1107. package/src/widgets/grapher/util.jsx +0 -806
  1108. package/src/widgets/grapher.jsx +0 -663
  1109. package/src/widgets/group.jsx +0 -195
  1110. package/src/widgets/iframe.jsx +0 -198
  1111. package/src/widgets/image.jsx +0 -310
  1112. package/src/widgets/input-number.jsx +0 -402
  1113. package/src/widgets/interaction/arrow-picker.jsx +0 -39
  1114. package/src/widgets/interaction/color-picker.jsx +0 -69
  1115. package/src/widgets/interaction/dash-picker.jsx +0 -46
  1116. package/src/widgets/interaction/element-container.jsx +0 -97
  1117. package/src/widgets/interaction.jsx +0 -742
  1118. package/src/widgets/interactive-graph.jsx +0 -2820
  1119. package/src/widgets/label-image/__stories__/answer-choices.stories.jsx +0 -93
  1120. package/src/widgets/label-image/__stories__/marker.stories.jsx +0 -172
  1121. package/src/widgets/label-image/answer-choices.jsx +0 -311
  1122. package/src/widgets/label-image/marker.jsx +0 -365
  1123. package/src/widgets/label-image/types.js +0 -33
  1124. package/src/widgets/label-image.jsx +0 -841
  1125. package/src/widgets/label-image_test.js +0 -840
  1126. package/src/widgets/lights-puzzle.jsx +0 -356
  1127. package/src/widgets/matcher.jsx +0 -274
  1128. package/src/widgets/matrix.jsx +0 -616
  1129. package/src/widgets/measurer.jsx +0 -215
  1130. package/src/widgets/molecule/__tests__/layout_test.jsx +0 -159
  1131. package/src/widgets/molecule/__tests__/parser_test.jsx +0 -142
  1132. package/src/widgets/molecule/molecule-drawing.jsx +0 -175
  1133. package/src/widgets/molecule/molecule-layout.jsx +0 -367
  1134. package/src/widgets/molecule/smiles-parser.jsx +0 -300
  1135. package/src/widgets/molecule.jsx +0 -172
  1136. package/src/widgets/number-line.jsx +0 -855
  1137. package/src/widgets/numeric-input.jsx +0 -546
  1138. package/src/widgets/orderer.jsx +0 -756
  1139. package/src/widgets/passage/__tests__/passage-markdown_test.jsx +0 -373
  1140. package/src/widgets/passage/passage-markdown.jsx +0 -472
  1141. package/src/widgets/passage-ref-target.jsx +0 -73
  1142. package/src/widgets/passage-ref.jsx +0 -214
  1143. package/src/widgets/passage.jsx +0 -576
  1144. package/src/widgets/plotter.jsx +0 -1198
  1145. package/src/widgets/radio/__stories__/base-radio.stories.jsx +0 -189
  1146. package/src/widgets/radio/__stories__/choice-icon.stories.jsx +0 -166
  1147. package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +0 -41
  1148. package/src/widgets/radio/__stories__/choice.stories.jsx +0 -138
  1149. package/src/widgets/radio/__stories__/focus-ring.stories.jsx +0 -44
  1150. package/src/widgets/radio/__stories__/option-status.stories.jsx +0 -104
  1151. package/src/widgets/radio/base-radio.jsx +0 -494
  1152. package/src/widgets/radio/choice-a11y-text.js +0 -62
  1153. package/src/widgets/radio/choice-icon/choice-icon.jsx +0 -214
  1154. package/src/widgets/radio/choice-icon/cross-out-line.jsx +0 -52
  1155. package/src/widgets/radio/choice-icon/shared-styles.js +0 -16
  1156. package/src/widgets/radio/choice-none-above.jsx +0 -63
  1157. package/src/widgets/radio/choice.jsx +0 -373
  1158. package/src/widgets/radio/choice.jsx.fixture.js +0 -46
  1159. package/src/widgets/radio/focus-ring.jsx +0 -58
  1160. package/src/widgets/radio/option-status.jsx +0 -98
  1161. package/src/widgets/radio/util.js +0 -32
  1162. package/src/widgets/radio/util_test.js +0 -19
  1163. package/src/widgets/radio/widget.jsx +0 -515
  1164. package/src/widgets/radio.jsx +0 -155
  1165. package/src/widgets/reaction-diagram.jsx +0 -137
  1166. package/src/widgets/sequence.jsx +0 -143
  1167. package/src/widgets/simulator.jsx +0 -802
  1168. package/src/widgets/sorter.jsx +0 -149
  1169. package/src/widgets/table.jsx +0 -389
  1170. package/src/widgets/transformer.jsx +0 -2872
  1171. package/src/widgets/unit.jsx +0 -357
  1172. package/src/widgets/video-transcript-link.jsx +0 -84
  1173. package/src/widgets/video-transcript-link_test.js +0 -211
  1174. package/src/widgets/video.jsx +0 -126
  1175. package/src/widgets.js +0 -431
  1176. package/src/zoom.js +0 -539
  1177. /package/{src/multi-items/item-types.js → dist/multi-items/item-types.js.flow} +0 -0
  1178. /package/dist/{strings.js → strings} +0 -0
  1179. /package/src/__tests__/__snapshots__/{item-renderer_test.jsx.snap → item-renderer.test.tsx.snap} +0 -0
  1180. /package/src/__tests__/__snapshots__/{perseus-markdown_test.jsx.snap → perseus-markdown.test.ts.snap} +0 -0
  1181. /package/src/__tests__/__snapshots__/{renderer_test.jsx.snap → renderer.test.tsx.snap} +0 -0
  1182. /package/src/__tests__/__snapshots__/{server-item-renderer_test.jsx.snap → server-item-renderer.test.tsx.snap} +0 -0
  1183. /package/src/components/__tests__/__snapshots__/{sortable_test.jsx.snap → sortable.test.tsx.snap} +0 -0
  1184. /package/src/components/__tests__/__snapshots__/{sorter_test.jsx.snap → sorter.test.tsx.snap} +0 -0
  1185. /package/src/multi-items/__tests__/__snapshots__/{multi-renderer_test.js.snap → multi-renderer.test.tsx.snap} +0 -0
  1186. /package/src/widgets/__tests__/__snapshots__/{categorizer_test.jsx.snap → categorizer.test.ts.snap} +0 -0
  1187. /package/src/widgets/__tests__/__snapshots__/{cs-program_test.jsx.snap → cs-program.test.ts.snap} +0 -0
  1188. /package/src/widgets/__tests__/__snapshots__/{definition_test.js.snap → definition.test.ts.snap} +0 -0
  1189. /package/src/widgets/__tests__/__snapshots__/{dropdown_test.jsx.snap → dropdown.test.ts.snap} +0 -0
  1190. /package/src/widgets/__tests__/__snapshots__/{explanation_test.js.snap → explanation.test.ts.snap} +0 -0
  1191. /package/src/widgets/__tests__/__snapshots__/{graded-group-set-jipt_test.jsx.snap → graded-group-set-jipt.test.ts.snap} +0 -0
  1192. /package/src/widgets/__tests__/__snapshots__/{graded-group-set_test.jsx.snap → graded-group-set.test.ts.snap} +0 -0
  1193. /package/src/widgets/__tests__/__snapshots__/{graded-group_test.jsx.snap → graded-group.test.ts.snap} +0 -0
  1194. /package/src/widgets/__tests__/__snapshots__/{grapher_test.jsx.snap → grapher.test.ts.snap} +0 -0
  1195. /package/src/widgets/__tests__/__snapshots__/{group_test.jsx.snap → group.test.tsx.snap} +0 -0
  1196. /package/src/widgets/__tests__/__snapshots__/{iframe_test.jsx.snap → iframe.test.ts.snap} +0 -0
  1197. /package/src/widgets/__tests__/__snapshots__/{image_test.jsx.snap → image.test.ts.snap} +0 -0
  1198. /package/src/widgets/__tests__/__snapshots__/{input-number_test.jsx.snap → input-number.test.ts.snap} +0 -0
  1199. /package/src/widgets/__tests__/__snapshots__/{interaction_test.jsx.snap → interaction.test.ts.snap} +0 -0
  1200. /package/src/widgets/__tests__/__snapshots__/{interactive-graph_test.jsx.snap → interactive-graph.test.ts.snap} +0 -0
  1201. /package/src/widgets/__tests__/__snapshots__/{matcher_test.jsx.snap → matcher.test.tsx.snap} +0 -0
  1202. /package/src/widgets/__tests__/__snapshots__/{matrix_test.jsx.snap → matrix.test.ts.snap} +0 -0
  1203. /package/src/widgets/__tests__/__snapshots__/{number-line_test.jsx.snap → number-line.test.ts.snap} +0 -0
  1204. /package/src/widgets/__tests__/__snapshots__/{numeric-input_test.jsx.snap → numeric-input.test.ts.snap} +0 -0
  1205. /package/src/widgets/__tests__/__snapshots__/{orderer_test.jsx.snap → orderer.test.ts.snap} +0 -0
  1206. /package/src/widgets/__tests__/__snapshots__/{passage-ref_test.jsx.snap → passage-ref.test.ts.snap} +0 -0
  1207. /package/src/widgets/__tests__/__snapshots__/{passage_test.jsx.snap → passage.test.tsx.snap} +0 -0
  1208. /package/src/widgets/__tests__/__snapshots__/{radio_test.jsx.snap → radio.test.ts.snap} +0 -0
  1209. /package/src/widgets/__tests__/__snapshots__/{unit_test.jsx.snap → unit.test.tsx.snap} +0 -0
  1210. /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
- });