@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
@@ -0,0 +1,2951 @@
1
+ /* eslint-disable react/prop-types */
2
+ /* eslint-disable @babel/no-invalid-this */
3
+ /* eslint-disable camelcase */
4
+ /* eslint-disable react/no-did-update-set-state */
5
+ /* eslint-disable react/sort-comp */
6
+ /*
7
+ NOTE(Pereus stabilize project): This widget is no-longer-used as of January
8
+ 2022. It's not present in US content but is still present in some
9
+ international content so it can't be removed quite yet. As soon as it's
10
+ verified to have been removed from international content this all needs
11
+ to get deleted. In the meantime- do not maintain this code.
12
+
13
+ ref: https://khanacademy.slack.com/archives/CJDRXTGQ7/p1641857400011600
14
+ ref: https://khanacademy.slack.com/archives/C2RFQGYKU/p1596160975061500?thread_ts=1596129758.040000&cid=C2RFQGYKU
15
+ */
16
+ import {
17
+ number as knumber,
18
+ vector as kvector,
19
+ point as kpoint,
20
+ ray as kray,
21
+ line as kline,
22
+ } from "@khanacademy/kmath";
23
+ import * as i18n from "@khanacademy/wonder-blocks-i18n";
24
+ import createReactClass from "create-react-class";
25
+ import $ from "jquery";
26
+ import * as React from "react";
27
+ import ReactDOM from "react-dom";
28
+ import _ from "underscore";
29
+
30
+ import Graph from "../components/graph";
31
+ import InlineIcon from "../components/inline-icon";
32
+ import NumberInput from "../components/number-input";
33
+ import SimpleKeypadInput from "../components/simple-keypad-input";
34
+ import {getDependencies} from "../dependencies";
35
+ import {iconPlus, iconUndo} from "../icon-paths";
36
+ import InteractiveUtil from "../interactive2/interactive-util";
37
+ import {Errors} from "../logging/log";
38
+ import {ApiOptions} from "../perseus-api";
39
+ import {PerseusError} from "../perseus-error";
40
+ import Util from "../util";
41
+ import KhanColors from "../util/colors";
42
+ import KhanMath from "../util/math";
43
+
44
+ import type {Coord} from "../interactive2/types";
45
+ import type {
46
+ PerseusTransformerWidgetOptions,
47
+ PerseusTransformerTransformation as TransformerTransformation,
48
+ DilationTransformation,
49
+ ReflectionTransformation,
50
+ RotationTransformation,
51
+ TranslationTransformation,
52
+ } from "../perseus-types";
53
+ import type {Path, PerseusScore, WidgetExports, WidgetProps} from "../types";
54
+
55
+ const {deepEq, getGridStep, captureScratchpadTouchStart} = Util;
56
+ const {assert} = InteractiveUtil;
57
+
58
+ const ROTATE_SNAP_DEGREES = 15;
59
+
60
+ const DEGREE_SIGN = "\u00B0";
61
+ const RENDER_TRANSFORM_DELAY_IN_MS = 300;
62
+ const ROTATE_HANDLE_DIST = 1.5;
63
+ const REFLECT_ROTATE_HANDLE_DIST = 2;
64
+ const REFLECT_BUTTON_SIZE = 1;
65
+ const defaultBoxSize = 400;
66
+ const defaultBackgroundImage = {
67
+ url: null,
68
+ } as const;
69
+
70
+ /* Does a pluck on keys inside objects in an object
71
+ *
72
+ * Ex:
73
+ * tools = {
74
+ * translation: {
75
+ * enabled: true
76
+ * },
77
+ * rotation: {
78
+ * enabled: false
79
+ * }
80
+ * };
81
+ * pluckObject(tools, "enabled") returns {
82
+ * translation: true
83
+ * rotation: false
84
+ * }
85
+ */
86
+ function pluckObject(object, subKey: string) {
87
+ return _.object(
88
+ _.map(object, function (value, key) {
89
+ return [key, value[subKey]];
90
+ }),
91
+ );
92
+ }
93
+
94
+ const defaultGraphProps = function (setProps, boxSize) {
95
+ setProps = setProps || {};
96
+ const labels = setProps.labels || ["x", "y"];
97
+ const range = setProps.range || [
98
+ [-10, 10],
99
+ [-10, 10],
100
+ ];
101
+ const step = setProps.step || [1, 1];
102
+ const gridStep = setProps.gridStep || getGridStep(range, step, boxSize);
103
+ return {
104
+ box: [boxSize, boxSize],
105
+ labels: labels,
106
+ range: range,
107
+ step: step,
108
+ gridStep: gridStep,
109
+ valid: true,
110
+ backgroundImage: defaultBackgroundImage,
111
+ markings: "grid",
112
+ showProtractor: false,
113
+ };
114
+ };
115
+
116
+ const defaultTransformerProps = {
117
+ apiOptions: ApiOptions.defaults,
118
+ gradeEmpty: false,
119
+ graphMode: "interactive",
120
+ listMode: "dynamic",
121
+ graph: {},
122
+ tools: {
123
+ translation: {
124
+ enabled: true,
125
+ required: false,
126
+ constraints: {},
127
+ },
128
+ rotation: {
129
+ enabled: true,
130
+ required: false,
131
+ constraints: {
132
+ fixed: false,
133
+ },
134
+ coord: [1, 6],
135
+ },
136
+ reflection: {
137
+ enabled: true,
138
+ required: false,
139
+ constraints: {
140
+ fixed: false,
141
+ },
142
+ coords: [
143
+ [2, -4],
144
+ [2, 2],
145
+ ],
146
+ },
147
+ dilation: {
148
+ enabled: true,
149
+ required: false,
150
+ constraints: {
151
+ fixed: false,
152
+ },
153
+ coord: [6, 6],
154
+ },
155
+ },
156
+ drawSolutionShape: true,
157
+ starting: {
158
+ shape: {
159
+ type: "polygon-3",
160
+ coords: [
161
+ [2, 2],
162
+ [2, 6],
163
+ [7, 2],
164
+ ],
165
+ },
166
+ transformations: [],
167
+ },
168
+ correct: {
169
+ shape: {
170
+ type: "polygon-3",
171
+ coords: [
172
+ [2, 2],
173
+ [2, 6],
174
+ [7, 2],
175
+ ],
176
+ },
177
+ transformations: [],
178
+ },
179
+ } as const;
180
+
181
+ function colorForTool(tool) {
182
+ return tool.constraints.fixed ? KhanColors.DYNAMIC : KhanColors.INTERACTIVE;
183
+ }
184
+
185
+ /* Scales a distance from the default range of
186
+ * [-10, 10] to a given props.range pair
187
+ *
188
+ * Used for sizing various transformation tools
189
+ * (rotation handle, dilation circle)
190
+ */
191
+ function scaleToRange(dist: number, range) {
192
+ const spreadX = range[0][1] - range[0][0];
193
+ const spreadY = range[1][1] - range[1][0];
194
+
195
+ return (dist * Math.max(spreadX, spreadY)) / 20;
196
+ }
197
+
198
+ function dilatePointFromCenter(
199
+ point: any,
200
+ dilationCenter: Coord,
201
+ scale: number,
202
+ ) {
203
+ const pv = kvector.subtract(point, dilationCenter);
204
+ const pvScaled = kvector.scale(pv, scale);
205
+ const transformedPoint = kvector.add(dilationCenter, pvScaled);
206
+ return transformedPoint;
207
+ }
208
+
209
+ // TODO(jack): i18nize this
210
+ function stringFromDecimal(number) {
211
+ return String(KhanMath.roundTo(9, number));
212
+ }
213
+
214
+ function stringFromFraction(number) {
215
+ const frac = KhanMath.toFraction(number, knumber.DEFAULT_TOLERANCE);
216
+ if (frac[1] === 1) {
217
+ return stringFromDecimal(number);
218
+ }
219
+ return stringFromDecimal(frac[0]) + "/" + stringFromDecimal(frac[1]);
220
+ }
221
+
222
+ function texFromPoint(point: Coord) {
223
+ const {TeX} = getDependencies();
224
+
225
+ return [
226
+ <TeX key="(">(</TeX>,
227
+ stringFromDecimal(point[0]),
228
+ <TeX key=",">{", {}"}</TeX>,
229
+ stringFromDecimal(point[1]),
230
+ <TeX key=")">)</TeX>,
231
+ ];
232
+ }
233
+
234
+ function texFromVector(vector) {
235
+ const {TeX} = getDependencies();
236
+
237
+ return [
238
+ <TeX key="<">{i18n.doNotTranslate("\\langle")}</TeX>,
239
+ stringFromDecimal(vector[0]),
240
+ <TeX key=",">{", {}"}</TeX>,
241
+ stringFromDecimal(vector[1]),
242
+ <TeX key=">">{i18n.doNotTranslate("\\rangle")}</TeX>,
243
+ ];
244
+ }
245
+
246
+ function texFromAngleDeg(angleDeg: number) {
247
+ return stringFromDecimal(angleDeg) + DEGREE_SIGN;
248
+ }
249
+
250
+ function orderInsensitiveCoordsEqual(coords1, coords2: any) {
251
+ coords1 = _.clone(coords1).sort(kpoint.compare);
252
+ coords2 = _.clone(coords2).sort(kpoint.compare);
253
+ return _.all(
254
+ _.map(coords1, function (coord1, i) {
255
+ const coord2 = coords2[i];
256
+ return kpoint.equal(coord1, coord2);
257
+ }),
258
+ );
259
+ }
260
+
261
+ const inputComponentForApiOptions = (apiOptions) => {
262
+ if (apiOptions.customKeypad) {
263
+ return SimpleKeypadInput;
264
+ }
265
+ return NumberInput;
266
+ };
267
+
268
+ /* Perform operations on raw transform objects */
269
+ const TransformOps = {
270
+ apply: function (transform: TransformerTransformation) {
271
+ // Any transformation with empty text boxes is a no-op until
272
+ // filled out (these show up as nulls in transform.vector/line/etc).
273
+ // TODO (jack): Merge this just into reflections now that other
274
+ // transforms are always valid (after merging transformation
275
+ // collapsing, which may use isValid)
276
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
277
+ if (!Transformations[transform.type].isValid(transform)) {
278
+ return _.identity; // do not transform the coord
279
+ }
280
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
281
+ return Transformations[transform.type].apply(transform);
282
+ },
283
+
284
+ append: function (transformList, newTransform) {
285
+ // Append newTransform to transformList, and collapse the last
286
+ // two transforms if they are collapsable
287
+ const results = TransformOps._appendAndCollapseLastTwo(
288
+ transformList,
289
+ newTransform,
290
+ );
291
+ // Collapse any no-ops at the end of the transformation list
292
+ return TransformOps._collapseFinalNoOps(results);
293
+ },
294
+
295
+ _collapseFinalNoOps: function (transforms) {
296
+ // Collapse no-op transformations at the end of the list
297
+ if (transforms.length && TransformOps.isNoOp(_.last(transforms))) {
298
+ return _.initial(transforms);
299
+ }
300
+ return transforms;
301
+ },
302
+
303
+ _appendAndCollapseLastTwo: function (transformList, newTransform) {
304
+ if (!transformList.length) {
305
+ return [newTransform];
306
+ }
307
+ const collapsed = TransformOps.collapse(
308
+ _.last(transformList),
309
+ newTransform,
310
+ );
311
+ return _.initial(transformList).concat(collapsed);
312
+ },
313
+
314
+ isNoOp: function (transform) {
315
+ return Transformations[transform.type].isNoOp(transform);
316
+ },
317
+
318
+ collapse: function (transform1, transform2) {
319
+ // We can only collapse transforms that have the same type
320
+ if (transform1.type !== transform2.type) {
321
+ return [transform1, transform2];
322
+ }
323
+
324
+ // Clicking the button again removes empty transformations
325
+ if (
326
+ TransformOps.isEmpty(transform1) &&
327
+ TransformOps.isEmpty(transform2)
328
+ ) {
329
+ return [];
330
+ }
331
+
332
+ // Don't collapse invalid transformations otherwise
333
+ if (
334
+ !TransformOps.isValid(transform1) ||
335
+ !TransformOps.isValid(transform2)
336
+ ) {
337
+ return [transform1, transform2];
338
+ }
339
+
340
+ return TransformOps._collapseValidMonotypedTransforms(
341
+ transform1,
342
+ transform2,
343
+ );
344
+ },
345
+
346
+ isValid: function (transform: TransformerTransformation): boolean {
347
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
348
+ return Transformations[transform.type].isValid(transform);
349
+ },
350
+
351
+ isEmpty: function (transform: TransformerTransformation): boolean {
352
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
353
+ return Transformations[transform.type].isEmpty(transform);
354
+ },
355
+
356
+ _collapseValidMonotypedTransforms: function (transform1, transform2) {
357
+ let collapsed = Transformations[transform1.type].collapse(
358
+ transform1,
359
+ transform2,
360
+ );
361
+ if (collapsed) {
362
+ // Force all answers into an array
363
+ if (!_.isArray(collapsed)) {
364
+ collapsed = [collapsed];
365
+ }
366
+ // Add types to all transforms in the answer
367
+ _.each(collapsed, function (transform) {
368
+ transform.type = transform1.type;
369
+ });
370
+ return collapsed;
371
+ }
372
+ // These transforms can't be collapsed together
373
+ return [transform1, transform2];
374
+ },
375
+
376
+ toTeX: function (transform) {
377
+ return Transformations[transform.type].toTeX(transform);
378
+ },
379
+
380
+ /* A react representation of this transform object */
381
+ ListItem: createReactClass({
382
+ displayName: "ListItem",
383
+
384
+ render: function () {
385
+ if (this.props.mode === "dynamic") {
386
+ return <div>{TransformOps.toTeX(this.props.transform)}</div>;
387
+ }
388
+ if (this.props.mode === "interactive") {
389
+ const TransformClass =
390
+ Transformations[this.props.transform.type].Input;
391
+ return (
392
+ <TransformClass
393
+ // eslint-disable-next-line react/no-string-refs
394
+ ref="transform"
395
+ onChange={this.handleChange}
396
+ onFocus={this.props.onFocus}
397
+ onBlur={this.props.onBlur}
398
+ keypadElement={this.props.keypadElement}
399
+ apiOptions={this.props.apiOptions}
400
+ {...this.props.transform}
401
+ />
402
+ );
403
+ }
404
+ throw new PerseusError(
405
+ "Invalid mode: " + this.props.mode,
406
+ Errors.InvalidInput,
407
+ );
408
+ },
409
+
410
+ value: function () {
411
+ if (this.props.mode === "interactive") {
412
+ return _.extend(
413
+ {
414
+ type: this.props.transform.type,
415
+ },
416
+ // eslint-disable-next-line react/no-string-refs
417
+ this.refs.transform.value(),
418
+ );
419
+ }
420
+ return this.props.transform;
421
+ },
422
+
423
+ handleChange: _.debounce(function (callback) {
424
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
425
+ this.props.onChange(this.value(), callback);
426
+ }, RENDER_TRANSFORM_DELAY_IN_MS),
427
+
428
+ /* InputPath API: depending on the API call, this could involve simply
429
+ * navigating to the right ref and calling the function on that
430
+ * component, or threading the call down and returning the result. */
431
+ _getComponentAtPath: function (path) {
432
+ // eslint-disable-next-line react/no-string-refs
433
+ const transform = this.refs.transform;
434
+ const ref = _.head(path);
435
+ return transform.refs[ref];
436
+ },
437
+
438
+ focus: function () {
439
+ // eslint-disable-next-line react/no-string-refs
440
+ const transform = this.refs.transform;
441
+ const path = _.head(transform.getInputPaths());
442
+ if (path) {
443
+ this.focusInputPath(path);
444
+ }
445
+ },
446
+
447
+ focusInputPath: function (path) {
448
+ this._getComponentAtPath(path).focus();
449
+ },
450
+
451
+ blurInputPath: function (path) {
452
+ this._getComponentAtPath(path).blur();
453
+ },
454
+
455
+ getDOMNodeForPath: function (path) {
456
+ return ReactDOM.findDOMNode(this._getComponentAtPath(path));
457
+ },
458
+
459
+ getGrammarTypeForPath: function (path) {
460
+ return "number";
461
+ },
462
+
463
+ setInputValue: function (path, value: string | number, cb) {
464
+ // `value` comes in as a string on mobile, but we need a number
465
+ // We let through the empty string so that "Clear" works -- in
466
+ // that case, the transformer widget will just act as if there is
467
+ // no input, which is what we want.
468
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'length' does not exist on type 'string | number'.
469
+ if (value.length) {
470
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'string | number' is not assignable to parameter of type 'string'.
471
+ value = parseFloat(value);
472
+ if (isNaN(value)) {
473
+ return;
474
+ }
475
+ }
476
+ // eslint-disable-next-line react/no-string-refs
477
+ this.refs.transform.setInputValue(path, value, cb);
478
+ },
479
+
480
+ getInputPaths: function () {
481
+ // If we're in dynamic mode, then the list items are made up of
482
+ // static text.
483
+ if (this.props.mode === "dynamic") {
484
+ return [];
485
+ }
486
+ // eslint-disable-next-line react/no-string-refs
487
+ return this.refs.transform.getInputPaths();
488
+ },
489
+ }),
490
+ } as const;
491
+
492
+ const Transformations = {
493
+ translation: {
494
+ // I18N: As in the command, "Translate the polygon"
495
+ verbName: i18n._("Translate"),
496
+ nounName: i18n._("Translation"),
497
+ lowerNounName: i18n._("translation"),
498
+ apply: function (transform: TranslationTransformation) {
499
+ return function (coord) {
500
+ return kvector.add(coord, transform.vector);
501
+ };
502
+ },
503
+ isValid: function (transform: TranslationTransformation) {
504
+ return (
505
+ _.isFinite(transform.vector[0]) &&
506
+ _.isFinite(transform.vector[1])
507
+ );
508
+ },
509
+ isEmpty: function (transform: TranslationTransformation) {
510
+ return transform.vector[0] === null && transform.vector[1] === null;
511
+ },
512
+ isNoOp: function (transform) {
513
+ return kvector.equal(transform.vector, [0, 0]);
514
+ },
515
+ collapse: function (
516
+ transform1: TranslationTransformation,
517
+ transform2: TranslationTransformation,
518
+ ) {
519
+ return {
520
+ vector: kvector.add(transform1.vector, transform2.vector),
521
+ };
522
+ },
523
+ toTeX: function (transform: TranslationTransformation) {
524
+ // I18N: As in the command, "Translation by <3, 1>"
525
+ return i18n.$_("Translation by %(vector)s", {
526
+ vector: texFromVector(transform.vector),
527
+ });
528
+ },
529
+ Input: class extends React.Component<any, any> {
530
+ state = {
531
+ vector: this.props.vector || [null, null],
532
+ };
533
+
534
+ componentDidUpdate(prevProps: any) {
535
+ if (!deepEq(this.props, prevProps)) {
536
+ this.setState({vector: this.props.vector});
537
+ }
538
+ }
539
+
540
+ render(): React.ReactNode {
541
+ const InputComponent = inputComponentForApiOptions(
542
+ this.props.apiOptions,
543
+ );
544
+ const {TeX} = getDependencies();
545
+
546
+ const vector = [
547
+ <TeX key="<">{i18n.doNotTranslate("\\langle")}</TeX>,
548
+ <InputComponent
549
+ key="vec_x"
550
+ // eslint-disable-next-line react/no-string-refs
551
+ ref="x"
552
+ placeholder={0}
553
+ value={this.state.vector[0]}
554
+ useArrowKeys={true}
555
+ onChange={(val0) => {
556
+ const val1 = this.state.vector[1];
557
+ this.setState({vector: [val0, val1]}, () => {
558
+ this.props.onChange();
559
+ });
560
+ }}
561
+ onFocus={_.partial(this.props.onFocus, "x")}
562
+ onBlur={_.partial(this.props.onBlur, "x")}
563
+ keypadElement={this.props.keypadElement}
564
+ />,
565
+ <TeX key=",">{", {}"}</TeX>,
566
+ <InputComponent
567
+ key="vec_y"
568
+ // eslint-disable-next-line react/no-string-refs
569
+ ref="y"
570
+ placeholder={0}
571
+ value={this.state.vector[1]}
572
+ useArrowKeys={true}
573
+ onChange={(val1) => {
574
+ const val0 = this.state.vector[0];
575
+ this.setState({vector: [val0, val1]}, () => {
576
+ this.props.onChange();
577
+ });
578
+ }}
579
+ onFocus={_.partial(this.props.onFocus, "y")}
580
+ onBlur={_.partial(this.props.onBlur, "y")}
581
+ keypadElement={this.props.keypadElement}
582
+ />,
583
+ <TeX key=">">{i18n.doNotTranslate("\\rangle")}</TeX>,
584
+ ];
585
+ return (
586
+ <div>
587
+ {i18n.$_("Translation by %(vector)s", {vector: vector})}
588
+ </div>
589
+ );
590
+ }
591
+
592
+ value = () => {
593
+ // eslint-disable-next-line react/no-string-refs
594
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
595
+ const x = this.refs.x.getValue();
596
+ // eslint-disable-next-line react/no-string-refs
597
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
598
+ const y = this.refs.y.getValue();
599
+ return {
600
+ vector: [x, y],
601
+ };
602
+ };
603
+
604
+ /* InputPath API */
605
+ setInputValue = (path, value, cb) => {
606
+ const id = _.first(path);
607
+ const vector = _.clone(this.state.vector);
608
+ if (id === "x") {
609
+ vector[0] = value;
610
+ } else if (id === "y") {
611
+ vector[1] = value;
612
+ }
613
+ this.setState({vector: vector}, () => {
614
+ this.props.onChange(cb);
615
+ });
616
+ };
617
+
618
+ getInputPaths = () => {
619
+ return [["x"], ["y"]];
620
+ };
621
+ },
622
+ },
623
+
624
+ rotation: {
625
+ // I18N: As in the command, "Rotate the polygon"
626
+ verbName: i18n._("Rotate"),
627
+ nounName: i18n._("Rotation"),
628
+ lowerNounName: i18n._("rotation"),
629
+ apply: function (transform: RotationTransformation) {
630
+ return function (coord: any) {
631
+ return kpoint.rotateDeg(
632
+ coord,
633
+ transform.angleDeg,
634
+ transform.center,
635
+ );
636
+ };
637
+ },
638
+ isValid: function (transform: RotationTransformation) {
639
+ return (
640
+ _.isFinite(transform.angleDeg) &&
641
+ _.isFinite(transform.center[0]) &&
642
+ _.isFinite(transform.center[1])
643
+ );
644
+ },
645
+ isEmpty: function (transform: RotationTransformation) {
646
+ return (
647
+ transform.angleDeg === null &&
648
+ transform.center[0] === null &&
649
+ transform.center[1] === null
650
+ );
651
+ },
652
+ isNoOp: function (transform: RotationTransformation) {
653
+ return knumber.equal(transform.angleDeg, 0);
654
+ },
655
+ collapse: function (
656
+ transform1: RotationTransformation,
657
+ transform2: RotationTransformation,
658
+ ) {
659
+ if (!kpoint.equal(transform1.center, transform2.center)) {
660
+ return false;
661
+ }
662
+ return {
663
+ center: transform1.center,
664
+ angleDeg: transform1.angleDeg + transform2.angleDeg,
665
+ };
666
+ },
667
+ toTeX: function (transform: RotationTransformation) {
668
+ return i18n.$_("Rotation by %(degrees)s about %(point)s", {
669
+ degrees: texFromAngleDeg(transform.angleDeg),
670
+ point: texFromPoint(transform.center),
671
+ });
672
+ },
673
+ Input: class extends React.Component<any, any> {
674
+ state = {
675
+ center: this.props.center || [null, null],
676
+ angleDeg: this.props.angleDeg || null,
677
+ };
678
+
679
+ componentDidUpdate(prevProps: any) {
680
+ if (!deepEq(this.props, prevProps)) {
681
+ this.setState({
682
+ center: this.props.center,
683
+ angleDeg: this.props.angleDeg,
684
+ });
685
+ }
686
+ }
687
+
688
+ render(): React.ReactNode {
689
+ const InputComponent = inputComponentForApiOptions(
690
+ this.props.apiOptions,
691
+ );
692
+ const {TeX} = getDependencies();
693
+
694
+ const point = [
695
+ <TeX key="(">(</TeX>,
696
+ <InputComponent
697
+ key="X"
698
+ // eslint-disable-next-line react/no-string-refs
699
+ ref="centerX"
700
+ placeholder={0}
701
+ value={this.state.center[0]}
702
+ useArrowKeys={true}
703
+ onChange={(val0) => {
704
+ const val1 = this.state.center[1];
705
+ this.setState({center: [val0, val1]}, () => {
706
+ this.props.onChange();
707
+ });
708
+ }}
709
+ onFocus={_.partial(this.props.onFocus, "centerX")}
710
+ onBlur={_.partial(this.props.onBlur, "centerX")}
711
+ keypadElement={this.props.keypadElement}
712
+ />,
713
+ <TeX key=",">{", {}"}</TeX>,
714
+ <InputComponent
715
+ key="Y"
716
+ // eslint-disable-next-line react/no-string-refs
717
+ ref="centerY"
718
+ placeholder={0}
719
+ value={this.state.center[1]}
720
+ useArrowKeys={true}
721
+ onChange={(val1) => {
722
+ const val0 = this.state.center[0];
723
+ this.setState({center: [val0, val1]}, () => {
724
+ this.props.onChange();
725
+ });
726
+ }}
727
+ onFocus={_.partial(this.props.onFocus, "centerY")}
728
+ onBlur={_.partial(this.props.onBlur, "centerY")}
729
+ keypadElement={this.props.keypadElement}
730
+ />,
731
+ <TeX key=")">)</TeX>,
732
+ ];
733
+ const degrees = [
734
+ <InputComponent
735
+ key="deg"
736
+ // eslint-disable-next-line react/no-string-refs
737
+ ref="angleDeg"
738
+ placeholder={0}
739
+ value={this.state.angleDeg}
740
+ useArrowKeys={true}
741
+ onChange={(val) => {
742
+ this.setState({angleDeg: val}, () => {
743
+ this.props.onChange();
744
+ });
745
+ }}
746
+ onFocus={_.partial(this.props.onFocus, "angleDeg")}
747
+ onBlur={_.partial(this.props.onBlur, "angleDeg")}
748
+ keypadElement={this.props.keypadElement}
749
+ />,
750
+ DEGREE_SIGN,
751
+ ];
752
+ // I18N: %(point)s must come before %(degrees)s in this phrase
753
+ const text = i18n.$_(
754
+ "Rotation about %(point)s by %(degrees)s",
755
+ {
756
+ point,
757
+ degrees,
758
+ },
759
+ );
760
+
761
+ return <div>{text}</div>;
762
+ }
763
+
764
+ value = () => {
765
+ // eslint-disable-next-line react/no-string-refs
766
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
767
+ const angleDeg = this.refs.angleDeg.getValue();
768
+ // eslint-disable-next-line react/no-string-refs
769
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
770
+ const centerX = this.refs.centerX.getValue();
771
+ // eslint-disable-next-line react/no-string-refs
772
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
773
+ const centerY = this.refs.centerY.getValue();
774
+ return {
775
+ angleDeg: angleDeg,
776
+ center: [centerX, centerY],
777
+ };
778
+ };
779
+
780
+ /* InputPath API */
781
+ setInputValue = (path, value, cb) => {
782
+ const id = _.first(path);
783
+ let angleDeg = _.clone(this.state.angleDeg);
784
+ const center = _.clone(this.state.center);
785
+ if (id === "angleDeg") {
786
+ angleDeg = value;
787
+ } else if (id === "centerX") {
788
+ center[0] = value;
789
+ } else if (id === "centerY") {
790
+ center[1] = value;
791
+ }
792
+ this.setState({angleDeg: angleDeg, center: center}, () => {
793
+ this.props.onChange(cb);
794
+ });
795
+ };
796
+
797
+ getInputPaths = () => {
798
+ return [["centerX"], ["centerY"], ["angleDeg"]];
799
+ };
800
+ },
801
+ },
802
+
803
+ reflection: {
804
+ // I18N: As in the command, "Reflect the polygon"
805
+ verbName: i18n._("Reflect"),
806
+ nounName: i18n._("Reflection"),
807
+ lowerNounName: i18n._("reflection"),
808
+ apply: function (transform: ReflectionTransformation) {
809
+ return function (coord: any) {
810
+ return kpoint.reflectOverLine(coord, transform.line);
811
+ };
812
+ },
813
+ isValid: function (transform: ReflectionTransformation) {
814
+ // A bit hacky, but we'll also define reflecting over a
815
+ // single point as a no-op, to avoid NaN fun.
816
+ return (
817
+ _.all(_.flatten(transform.line), _.isFinite) &&
818
+ !kpoint.equal(transform.line[0], transform.line[1])
819
+ );
820
+ },
821
+ isEmpty: function (transform: ReflectionTransformation) {
822
+ return _.all(_.flatten(transform.line), _.isNull);
823
+ },
824
+ isNoOp: function (transform: ReflectionTransformation) {
825
+ // Invalid transforms are implicitly no-ops, so we don't
826
+ // have to catch that case here.
827
+ return false;
828
+ },
829
+ collapse: function (
830
+ transform1: ReflectionTransformation,
831
+ transform2: ReflectionTransformation,
832
+ ) {
833
+ if (!kline.equal(transform1.line, transform2.line)) {
834
+ return false;
835
+ }
836
+ return [];
837
+ },
838
+ toTeX: function (transform) {
839
+ const point1 = transform.line[0];
840
+ const point2 = transform.line[1];
841
+ return i18n.$_(
842
+ "Reflection over the line from %(point1)s to %(point2)s",
843
+ {
844
+ point1: texFromPoint(point1),
845
+ point2: texFromPoint(point2),
846
+ },
847
+ );
848
+ },
849
+ Input: class extends React.Component<any, any> {
850
+ state = {
851
+ line: this.props.line || [
852
+ [null, null],
853
+ [null, null],
854
+ ],
855
+ };
856
+
857
+ componentDidUpdate(prevProps) {
858
+ if (!deepEq(this.props, prevProps)) {
859
+ this.setState({line: this.props.line});
860
+ }
861
+ }
862
+
863
+ render(): React.ReactNode {
864
+ const InputComponent = inputComponentForApiOptions(
865
+ this.props.apiOptions,
866
+ );
867
+ const {TeX} = getDependencies();
868
+
869
+ const point1 = [
870
+ <TeX key="(">(</TeX>,
871
+ <InputComponent
872
+ key="x1"
873
+ // eslint-disable-next-line react/no-string-refs
874
+ ref="x1"
875
+ value={this.state.line[0][0]}
876
+ useArrowKeys={true}
877
+ // eslint-disable-next-line react/jsx-no-bind
878
+ onChange={this.changePoint.bind(this, 0, 0)}
879
+ onFocus={_.partial(this.props.onFocus, "x1")}
880
+ onBlur={_.partial(this.props.onBlur, "x1")}
881
+ keypadElement={this.props.keypadElement}
882
+ />,
883
+ <TeX key=",">{", {}"}</TeX>,
884
+ <InputComponent
885
+ key="y1"
886
+ // eslint-disable-next-line react/no-string-refs
887
+ ref="y1"
888
+ value={this.state.line[0][1]}
889
+ useArrowKeys={true}
890
+ // eslint-disable-next-line react/jsx-no-bind
891
+ onChange={this.changePoint.bind(this, 0, 1)}
892
+ onFocus={_.partial(this.props.onFocus, "y1")}
893
+ onBlur={_.partial(this.props.onBlur, "y1")}
894
+ keypadElement={this.props.keypadElement}
895
+ />,
896
+ <TeX key=")">)</TeX>,
897
+ ];
898
+ const point2 = [
899
+ <TeX key="(">(</TeX>,
900
+ <InputComponent
901
+ key="x2"
902
+ // eslint-disable-next-line react/no-string-refs
903
+ ref="x2"
904
+ value={this.state.line[1][0]}
905
+ useArrowKeys={true}
906
+ // eslint-disable-next-line react/jsx-no-bind
907
+ onChange={this.changePoint.bind(this, 1, 0)}
908
+ onFocus={_.partial(this.props.onFocus, "x2")}
909
+ onBlur={_.partial(this.props.onBlur, "x2")}
910
+ keypadElement={this.props.keypadElement}
911
+ />,
912
+ <TeX key=",">{", {}"}</TeX>,
913
+ <InputComponent
914
+ key="y2"
915
+ // eslint-disable-next-line react/no-string-refs
916
+ ref="y2"
917
+ value={this.state.line[1][1]}
918
+ useArrowKeys={true}
919
+ // eslint-disable-next-line react/jsx-no-bind
920
+ onChange={this.changePoint.bind(this, 1, 1)}
921
+ onFocus={_.partial(this.props.onFocus, "y2")}
922
+ onBlur={_.partial(this.props.onBlur, "y2")}
923
+ keypadElement={this.props.keypadElement}
924
+ />,
925
+ <TeX key=")">)</TeX>,
926
+ ];
927
+ return (
928
+ <div>
929
+ {i18n.$_(
930
+ "Reflection over the line from " +
931
+ "%(point1)s to %(point2)s",
932
+ {point1, point2},
933
+ )}
934
+ </div>
935
+ );
936
+ }
937
+
938
+ changePoint = (
939
+ i: undefined | number,
940
+ j: undefined | number,
941
+ val: any,
942
+ cb,
943
+ ) => {
944
+ const line = _.map(this.state.line, _.clone);
945
+ // @ts-expect-error [FEI-5003] - TS2538 - Type 'undefined' cannot be used as an index type.
946
+ line[i][j] = val;
947
+ this.setState({line: line}, () => {
948
+ this.props.onChange(cb);
949
+ });
950
+ };
951
+
952
+ value = () => {
953
+ // eslint-disable-next-line react/no-string-refs
954
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
955
+ const x1 = this.refs.x1.getValue();
956
+ // eslint-disable-next-line react/no-string-refs
957
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
958
+ const y1 = this.refs.y1.getValue();
959
+ // eslint-disable-next-line react/no-string-refs
960
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
961
+ const x2 = this.refs.x2.getValue();
962
+ // eslint-disable-next-line react/no-string-refs
963
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
964
+ const y2 = this.refs.y2.getValue();
965
+ return {
966
+ line: [
967
+ [x1, y1],
968
+ [x2, y2],
969
+ ],
970
+ };
971
+ };
972
+
973
+ /* InputPath API */
974
+ setInputValue = (path: any, value: any, cb: any) => {
975
+ const id = _.first(path);
976
+ let j;
977
+ if (id[0] === "x") {
978
+ j = 0;
979
+ } else if (id[0] === "y") {
980
+ j = 1;
981
+ }
982
+ let i;
983
+ if (id[1] === "1") {
984
+ i = 0;
985
+ } else if (id[1] === "2") {
986
+ i = 1;
987
+ }
988
+ this.changePoint(i, j, value, cb);
989
+ };
990
+
991
+ getInputPaths = () => {
992
+ return [["x1"], ["y1"], ["x2"], ["y2"]];
993
+ };
994
+ },
995
+ },
996
+
997
+ dilation: {
998
+ // I18N: As in the command, "Dilate the polygon"
999
+ verbName: i18n._("Dilate"),
1000
+ nounName: i18n._("Dilation"),
1001
+ lowerNounName: i18n._("dilation"),
1002
+ apply: function (transform: DilationTransformation) {
1003
+ return function (coord: any) {
1004
+ return dilatePointFromCenter(
1005
+ coord,
1006
+ transform.center,
1007
+ transform.scale,
1008
+ );
1009
+ };
1010
+ },
1011
+ isValid: function (transform: DilationTransformation) {
1012
+ return (
1013
+ _.isFinite(transform.scale) &&
1014
+ _.isFinite(transform.center[0]) &&
1015
+ _.isFinite(transform.center[1])
1016
+ );
1017
+ },
1018
+ isEmpty: function (transform: DilationTransformation) {
1019
+ return (
1020
+ transform.scale === null &&
1021
+ transform.center[0] === null &&
1022
+ transform.center[1] === null
1023
+ );
1024
+ },
1025
+ isNoOp: function (transform: DilationTransformation) {
1026
+ return knumber.equal(transform.scale, 1);
1027
+ },
1028
+ collapse: function (
1029
+ transform1: DilationTransformation,
1030
+ transform2: DilationTransformation,
1031
+ ) {
1032
+ if (!kpoint.equal(transform1.center, transform2.center)) {
1033
+ return false;
1034
+ }
1035
+ return {
1036
+ center: transform1.center,
1037
+ scale: transform1.scale * transform2.scale,
1038
+ };
1039
+ },
1040
+ toTeX: function (transform: DilationTransformation) {
1041
+ const scaleString = stringFromFraction(transform.scale);
1042
+ return i18n.$_("Dilation of scale %(scale)s about %(point)s", {
1043
+ scale: scaleString,
1044
+ point: texFromPoint(transform.center),
1045
+ });
1046
+ },
1047
+ Input: class extends React.Component<any, any> {
1048
+ state = {
1049
+ center: this.props.center || [null, null],
1050
+ scale: this.props.scale || null,
1051
+ };
1052
+
1053
+ componentDidUpdate(prevProps: any) {
1054
+ if (!deepEq(this.props, prevProps)) {
1055
+ this.setState({
1056
+ center: this.props.center,
1057
+ scale: this.props.scale,
1058
+ });
1059
+ }
1060
+ }
1061
+
1062
+ render(): React.ReactNode {
1063
+ const InputComponent = inputComponentForApiOptions(
1064
+ this.props.apiOptions,
1065
+ );
1066
+ const {TeX} = getDependencies();
1067
+
1068
+ const point = [
1069
+ <TeX key="(">(</TeX>,
1070
+ <InputComponent
1071
+ key="point_x"
1072
+ // eslint-disable-next-line react/no-string-refs
1073
+ ref="x"
1074
+ placeholder={0}
1075
+ value={this.state.center[0]}
1076
+ useArrowKeys={true}
1077
+ onChange={(val0) => {
1078
+ const val1 = this.state.center[1];
1079
+ this.setState({center: [val0, val1]}, () => {
1080
+ this.props.onChange();
1081
+ });
1082
+ }}
1083
+ onFocus={_.partial(this.props.onFocus, "x")}
1084
+ onBlur={_.partial(this.props.onBlur, "x")}
1085
+ keypadElement={this.props.keypadElement}
1086
+ />,
1087
+ <TeX key=",">{", {}"}</TeX>,
1088
+ <InputComponent
1089
+ key="point_y"
1090
+ // eslint-disable-next-line react/no-string-refs
1091
+ ref="y"
1092
+ placeholder={0}
1093
+ value={this.state.center[1]}
1094
+ useArrowKeys={true}
1095
+ onChange={(val1) => {
1096
+ const val0 = this.state.center[0];
1097
+ this.setState({center: [val0, val1]}, () => {
1098
+ this.props.onChange();
1099
+ });
1100
+ }}
1101
+ onFocus={_.partial(this.props.onFocus, "y")}
1102
+ onBlur={_.partial(this.props.onBlur, "y")}
1103
+ keypadElement={this.props.keypadElement}
1104
+ />,
1105
+ <TeX key=")">)</TeX>,
1106
+ ];
1107
+ const scale = (
1108
+ <InputComponent
1109
+ // eslint-disable-next-line react/no-string-refs
1110
+ ref="scale"
1111
+ placeholder={1}
1112
+ value={this.state.scale}
1113
+ useArrowKeys={true}
1114
+ onChange={(val) => {
1115
+ this.setState({scale: val}, () => {
1116
+ this.props.onChange();
1117
+ });
1118
+ }}
1119
+ onFocus={_.partial(this.props.onFocus, "scale")}
1120
+ onBlur={_.partial(this.props.onBlur, "scale")}
1121
+ keypadElement={this.props.keypadElement}
1122
+ />
1123
+ );
1124
+ return (
1125
+ <div>
1126
+ {i18n.$_("Dilation about %(point)s by %(scale)s", {
1127
+ point,
1128
+ scale,
1129
+ })}
1130
+ </div>
1131
+ );
1132
+ }
1133
+
1134
+ value = () => {
1135
+ // eslint-disable-next-line react/no-string-refs
1136
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
1137
+ const scale = this.refs.scale.getValue();
1138
+ // eslint-disable-next-line react/no-string-refs
1139
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
1140
+ const x = this.refs.x.getValue();
1141
+ // eslint-disable-next-line react/no-string-refs
1142
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
1143
+ const y = this.refs.y.getValue();
1144
+ return {
1145
+ scale: scale,
1146
+ center: [x, y],
1147
+ };
1148
+ };
1149
+
1150
+ /* InputPath API */
1151
+ setInputValue = (path: any, value, cb: any) => {
1152
+ const id = _.first(path);
1153
+ let scale = this.state.scale;
1154
+ const center = _.clone(this.state.center);
1155
+ if (id === "x") {
1156
+ center[0] = value;
1157
+ } else if (id === "y") {
1158
+ center[1] = value;
1159
+ } else if (id === "scale") {
1160
+ scale = value;
1161
+ }
1162
+ this.setState({scale: scale, center: center}, () => {
1163
+ this.props.onChange(cb);
1164
+ });
1165
+ };
1166
+
1167
+ getInputPaths = () => {
1168
+ return [["x"], ["y"], ["scale"]];
1169
+ };
1170
+ },
1171
+ },
1172
+ } as const;
1173
+
1174
+ /* Various functions to deal with different shape types */
1175
+ const ShapeTypes = {
1176
+ getPointCountForType: function (type) {
1177
+ const splitType = type.split("-");
1178
+ if (splitType[0] === "polygon") {
1179
+ return splitType[1] || 3;
1180
+ }
1181
+ if (splitType[0] === "line" || splitType[0] === "lineSegment") {
1182
+ return 2;
1183
+ }
1184
+ if (splitType[0] === "angle") {
1185
+ return 3;
1186
+ }
1187
+ if (splitType[0] === "circle") {
1188
+ return 2;
1189
+ }
1190
+ if (splitType[0] === "point") {
1191
+ return 1;
1192
+ }
1193
+ },
1194
+
1195
+ addMovableShape: function (graphie, options) {
1196
+ if (options.editable && options.translatable) {
1197
+ throw new PerseusError(
1198
+ "It doesn't make sense to have a movable shape " +
1199
+ "where you can stretch the points and translate them " +
1200
+ "simultaneously. options: " +
1201
+ JSON.stringify(options),
1202
+ Errors.InvalidInput,
1203
+ );
1204
+ }
1205
+
1206
+ const points = _.map(options.shape.coords, function (coord) {
1207
+ let isMoving = false;
1208
+ let previousCoord = coord;
1209
+
1210
+ const onMove = function (x, y: any) {
1211
+ if (!isMoving) {
1212
+ previousCoord = currentPoint.coord;
1213
+ isMoving = true;
1214
+ }
1215
+
1216
+ let moveVector = kvector.subtract([x, y], currentPoint.coord);
1217
+
1218
+ // Translate from (x, y) semantics to (dX, dY) semantics
1219
+ // This is more useful for translations on multiple points,
1220
+ // where we care about how the points moved, not where any
1221
+ // individual point ended up
1222
+ if (options.onMove) {
1223
+ moveVector = options.onMove(moveVector[0], moveVector[1]);
1224
+ }
1225
+
1226
+ // Perform a translation on all points in this shape when
1227
+ // any point moves
1228
+ if (options.translatable) {
1229
+ _.each(points, function (point) {
1230
+ // The point itself will be updated by the
1231
+ // movablePoint class, so only translate the other
1232
+ // points
1233
+ if (point !== currentPoint) {
1234
+ point.setCoord(
1235
+ kvector.add(point.coord, moveVector),
1236
+ );
1237
+ }
1238
+ });
1239
+ }
1240
+
1241
+ // Update our shape and our currentPoint
1242
+ // Without this, some shapes (circles, angles) appear
1243
+ // "bouncy" as they are updated with currentPoint at the
1244
+ // current mouse coordinate (oldCoord), rather than newCoord
1245
+ const oldCoord = currentPoint.coord;
1246
+ const newCoord = kvector.add(currentPoint.coord, moveVector);
1247
+ // Temporarily change our coordinate so that
1248
+ // shape.update() sees the new coordinate
1249
+ currentPoint.coord = newCoord;
1250
+ shape.update();
1251
+ // ...But don't break onMove, which assumes it
1252
+ // is the only thing changing our coord
1253
+ currentPoint.coord = oldCoord;
1254
+ return newCoord;
1255
+ };
1256
+
1257
+ const onMoveEnd = function () {
1258
+ // onMove isn't guaranteed to be called before onMoveEnd, so
1259
+ // we have to take into account that we may not have moved and
1260
+ // set previousCoord.
1261
+ if (options.onMoveEnd && isMoving) {
1262
+ isMoving = false;
1263
+ // We don't use the supplied x and y parameters here
1264
+ // because MovablePoint's onMoveEnd semantics suck.
1265
+ // It returns the mouseX, mouseY without processing them
1266
+ // through onMove, leaving us with weird fractional moves
1267
+ const change = kvector.subtract(
1268
+ currentPoint.coord,
1269
+ previousCoord,
1270
+ );
1271
+ options.onMoveEnd(change[0], change[1]);
1272
+ }
1273
+ shape.update();
1274
+ };
1275
+
1276
+ const currentPoint = graphie.addMovablePoint({
1277
+ coord: coord,
1278
+ normalStyle: options.normalPointStyle,
1279
+ highlightStyle: options.highlightPointStyle,
1280
+ constraints: {
1281
+ fixed: !options.translatable && !options.editable,
1282
+ },
1283
+ visible: options.showPoints,
1284
+ // $FlowFixMe[prop-missing]
1285
+ snapX: (options.snap && options.snap[0]) || 0,
1286
+ // $FlowFixMe[prop-missing]
1287
+ snapY: (options.snap && options.snap[1]) || 0,
1288
+ bounded: false, // Don't bound it when placing it on the graph
1289
+ onMove: onMove,
1290
+ onMoveEnd: onMoveEnd,
1291
+ });
1292
+
1293
+ // Bound it when moving
1294
+ // We can't set this earlier, because doing so would mean any
1295
+ // points outside of the graph would be moved into a moved into
1296
+ // a position that doesn't preserve the shape
1297
+ currentPoint.bounded = true;
1298
+
1299
+ return currentPoint;
1300
+ });
1301
+
1302
+ const shape = ShapeTypes.addShape(graphie, options, points);
1303
+ const removeShapeWithoutPoints = shape.remove;
1304
+ shape.remove = function () {
1305
+ removeShapeWithoutPoints.apply(shape);
1306
+ _.invoke(points, "remove");
1307
+ };
1308
+ return shape;
1309
+ },
1310
+
1311
+ addShape: function (graphie, options, points) {
1312
+ points = points || options.shape.coords;
1313
+
1314
+ const types = ShapeTypes._typesOf(options.shape);
1315
+ const typeOptions =
1316
+ options.shape.options || ShapeTypes.defaultOptions(types);
1317
+
1318
+ // @ts-expect-error [FEI-5003] - TS2554 - Expected 4 arguments, but got 3.
1319
+ const shapes = ShapeTypes._mapTypes(
1320
+ types,
1321
+ points,
1322
+ function (type, points, i) {
1323
+ const shapeOptions = _.extend({}, options, typeOptions[i]);
1324
+ return ShapeTypes._addType(graphie, type, points, shapeOptions);
1325
+ },
1326
+ );
1327
+
1328
+ const updateFuncs = _.filter(_.pluck(shapes, "update"), _.identity);
1329
+ const update = function () {
1330
+ _.invoke(updateFuncs, "call");
1331
+ };
1332
+
1333
+ const removeFuncs = _.filter(_.pluck(shapes, "remove"), _.identity);
1334
+ const remove = function () {
1335
+ _.invoke(removeFuncs, "call");
1336
+ };
1337
+
1338
+ const getOptions = function () {
1339
+ return _.map(shapes, function (shape) {
1340
+ if (shape.getOptions) {
1341
+ return shape.getOptions();
1342
+ }
1343
+ return {};
1344
+ });
1345
+ };
1346
+
1347
+ const toJSON = function () {
1348
+ const coords = _.map(points, function (pt) {
1349
+ if (_.isArray(pt)) {
1350
+ return pt;
1351
+ }
1352
+ return pt.coord;
1353
+ });
1354
+ return {
1355
+ type: types,
1356
+ coords: coords,
1357
+ options: getOptions(),
1358
+ };
1359
+ };
1360
+
1361
+ return {
1362
+ type: types,
1363
+ points: points,
1364
+ update: update,
1365
+ remove: remove,
1366
+ toJSON: toJSON,
1367
+ getOptions: getOptions,
1368
+ };
1369
+ },
1370
+
1371
+ equal: function (shape1, shape2) {
1372
+ const types1 = ShapeTypes._typesOf(shape1);
1373
+ const types2 = ShapeTypes._typesOf(shape2);
1374
+ if (types1.length !== types2.length) {
1375
+ return false;
1376
+ }
1377
+ // @ts-expect-error [FEI-5003] - TS2554 - Expected 4 arguments, but got 3.
1378
+ const shapes1 = ShapeTypes._mapTypes(
1379
+ types1,
1380
+ shape1.coords,
1381
+ ShapeTypes._combine,
1382
+ );
1383
+ // @ts-expect-error [FEI-5003] - TS2554 - Expected 4 arguments, but got 3.
1384
+ const shapes2 = ShapeTypes._mapTypes(
1385
+ types2,
1386
+ shape2.coords,
1387
+ ShapeTypes._combine,
1388
+ );
1389
+ return _.all(
1390
+ _.map(shapes1, function (partialShape1, i) {
1391
+ const partialShape2 = shapes2[i];
1392
+ if (partialShape1.type !== partialShape2.type) {
1393
+ return false;
1394
+ }
1395
+ return ShapeTypes._forType(partialShape1.type).equal(
1396
+ partialShape1.coords,
1397
+ partialShape2.coords,
1398
+ );
1399
+ }),
1400
+ );
1401
+ },
1402
+
1403
+ _typesOf: function (shape) {
1404
+ let types = shape.type;
1405
+ if (!_.isArray(types)) {
1406
+ types = [types];
1407
+ }
1408
+ return _.map(types, function (type) {
1409
+ if (type === "polygon") {
1410
+ return "polygon-3";
1411
+ }
1412
+ return type;
1413
+ });
1414
+ },
1415
+
1416
+ defaultOptions: function (types) {
1417
+ return _.map(types, function (type) {
1418
+ const typeDefaultOptions = ShapeTypes._forType(type).defaultOptions;
1419
+ return _.extend({}, typeDefaultOptions);
1420
+ });
1421
+ },
1422
+
1423
+ _forType: function (type) {
1424
+ const baseType = type.split("-")[0];
1425
+ return ShapeTypes[baseType];
1426
+ },
1427
+
1428
+ _mapTypes: function (types, points, func, context) {
1429
+ return _.map(types, function (type, i) {
1430
+ const pointCount = ShapeTypes.getPointCountForType(type);
1431
+ const currentPoints = _.first(points, pointCount);
1432
+ points = _.rest(points, pointCount);
1433
+ return func.call(context, type, currentPoints, i);
1434
+ });
1435
+ },
1436
+
1437
+ _addType: function (graphie, type, points, options) {
1438
+ const lineCoords = _.isArray(points[0])
1439
+ ? {
1440
+ coordA: points[0],
1441
+ coordZ: points[1],
1442
+ }
1443
+ : {
1444
+ pointA: points[0],
1445
+ pointZ: points[1],
1446
+ };
1447
+
1448
+ type = type.split("-")[0];
1449
+ if (type === "polygon") {
1450
+ const polygon = graphie.addMovablePolygon(
1451
+ _.extend({}, options, {
1452
+ fixed: !options.editable,
1453
+ snapX: (options.snap && options.snap[0]) || 0,
1454
+ snapY: (options.snap && options.snap[1]) || 0,
1455
+ points: points,
1456
+ constrainToGraph: false,
1457
+ }),
1458
+ );
1459
+ return {
1460
+ update: polygon.transform.bind(polygon),
1461
+ remove: polygon.remove.bind(polygon),
1462
+ };
1463
+ }
1464
+ if (type === "line" || type === "lineSegment") {
1465
+ const line = graphie.addMovableLineSegment(
1466
+ _.extend({}, options, lineCoords, {
1467
+ movePointsWithLine: true,
1468
+ fixed: true,
1469
+ constraints: {
1470
+ fixed: true,
1471
+ },
1472
+ extendLine: type === "line",
1473
+ }),
1474
+ );
1475
+
1476
+ // TODO(jack): Hide points on uneditable lines when translation
1477
+ // is a vector.
1478
+ // We can't just remove the points yet, because they are the
1479
+ // translation handle for the line.
1480
+ return {
1481
+ update: line.transform.bind(line, true),
1482
+ remove: line.remove.bind(line),
1483
+ };
1484
+ }
1485
+ if (type === "angle") {
1486
+ // If this angle is editable, we want to be able to make angles
1487
+ // both larger and smaller than 180 degrees.
1488
+ // If this angle is not editable, it should always maintain
1489
+ // it's angle measure, even if it is reflected (causing the
1490
+ // clockwise-ness of the points to change)
1491
+ const shouldChangeReflexivity = options.editable ? null : false;
1492
+
1493
+ const angle = graphie.addMovableAngle({
1494
+ angleLabel: "$deg0",
1495
+ fixed: true,
1496
+ points: points,
1497
+ normalStyle: options.normalStyle,
1498
+ reflex: options.reflex,
1499
+ });
1500
+
1501
+ // Hide non-vertex points on uneditable angles
1502
+ if (!_.isArray(points[0]) && !options.editable) {
1503
+ points[0].remove();
1504
+ points[2].remove();
1505
+ }
1506
+ return {
1507
+ update: angle.update.bind(angle, shouldChangeReflexivity),
1508
+ remove: angle.remove.bind(angle),
1509
+ getOptions: function () {
1510
+ return {
1511
+ reflex: angle.isReflex(),
1512
+ };
1513
+ },
1514
+ };
1515
+ }
1516
+ if (type === "circle") {
1517
+ let perimeter = {
1518
+ // temporary object for the first removal
1519
+ remove: _.identity,
1520
+ };
1521
+ const redrawPerim = function () {
1522
+ const coord0 = points[0].coord || points[0];
1523
+ const coord1 = points[1].coord || points[1];
1524
+ const radius = kpoint.distanceToPoint(coord0, coord1);
1525
+ // @ts-expect-error [FEI-5003] - TS2554 - Expected 1 arguments, but got 0.
1526
+ perimeter.remove();
1527
+ perimeter = graphie.circle(
1528
+ coord0,
1529
+ radius,
1530
+ _.extend(
1531
+ {
1532
+ stroke: KhanColors.DYNAMIC,
1533
+ "stroke-width": 2,
1534
+ },
1535
+ options.normalStyle,
1536
+ ),
1537
+ );
1538
+ };
1539
+
1540
+ redrawPerim();
1541
+ if (points[1].remove && !options.editable) {
1542
+ points[1].remove();
1543
+ }
1544
+
1545
+ return {
1546
+ update: redrawPerim,
1547
+ remove: function () {
1548
+ // Not _.bind because the remove function changes
1549
+ // when the perimeter is redrawn
1550
+ // @ts-expect-error [FEI-5003] - TS2554 - Expected 1 arguments, but got 0.
1551
+ perimeter.remove();
1552
+ },
1553
+ };
1554
+ }
1555
+ if (type === "point") {
1556
+ // do nothing
1557
+ return {
1558
+ update: null,
1559
+ remove: null,
1560
+ };
1561
+ }
1562
+ throw new PerseusError(
1563
+ "Invalid shape type " + type,
1564
+ Errors.InvalidInput,
1565
+ );
1566
+ },
1567
+
1568
+ _combine: function (type, coords) {
1569
+ return {
1570
+ type: type,
1571
+ coords: coords,
1572
+ };
1573
+ },
1574
+
1575
+ polygon: {
1576
+ equal: orderInsensitiveCoordsEqual,
1577
+ },
1578
+
1579
+ line: {
1580
+ equal: kline.equal,
1581
+ },
1582
+
1583
+ lineSegment: {
1584
+ equal: orderInsensitiveCoordsEqual,
1585
+ },
1586
+
1587
+ angle: {
1588
+ equal: function (points1, points2) {
1589
+ if (!kpoint.equal(points1[1], points2[1])) {
1590
+ return false;
1591
+ }
1592
+
1593
+ const line1_0 = [points1[1], points1[0]];
1594
+ const line1_2 = [points1[1], points1[2]];
1595
+ const line2_0 = [points2[1], points2[0]];
1596
+ const line2_2 = [points2[1], points2[2]];
1597
+
1598
+ const equalUnflipped =
1599
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'. | TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'.
1600
+ kray.equal(line1_0, line2_0) && kray.equal(line1_2, line2_2);
1601
+ const equalFlipped =
1602
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'. | TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'.
1603
+ kray.equal(line1_0, line2_2) && kray.equal(line1_2, line2_0);
1604
+
1605
+ return equalUnflipped || equalFlipped;
1606
+ },
1607
+
1608
+ defaultOptions: {
1609
+ reflex: false,
1610
+ },
1611
+ },
1612
+
1613
+ circle: {
1614
+ equal: function (points1, points2) {
1615
+ const radius1 = kpoint.distanceToPoint(points1[0], points1[1]);
1616
+ const radius2 = kpoint.distanceToPoint(points2[0], points2[1]);
1617
+ return (
1618
+ kpoint.equal(points1[0], points2[0]) &&
1619
+ knumber.equal(radius1, radius2)
1620
+ );
1621
+ },
1622
+ },
1623
+
1624
+ point: {
1625
+ equal: kpoint.equal,
1626
+ },
1627
+ } as const;
1628
+
1629
+ const TransformationListItem = TransformOps.ListItem;
1630
+
1631
+ class TransformationList extends React.Component<any, any> {
1632
+ render(): React.ReactNode {
1633
+ if (this.props.mode === "static") {
1634
+ return <span />; // don't render anything
1635
+ }
1636
+
1637
+ const transformationList = _.map(
1638
+ this.props.transformations,
1639
+ function (transform, i) {
1640
+ return (
1641
+ <TransformationListItem
1642
+ ref={"transformation" + i}
1643
+ key={"transformation" + i}
1644
+ transform={transform}
1645
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1646
+ mode={this.props.mode}
1647
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1648
+ onChange={this.handleChange}
1649
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1650
+ onFocus={_.partial(this.props.onFocus, "" + i)}
1651
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1652
+ onBlur={_.partial(this.props.onBlur, "" + i)}
1653
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1654
+ keypadElement={this.props.keypadElement}
1655
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1656
+ apiOptions={this.props.apiOptions}
1657
+ />
1658
+ );
1659
+ },
1660
+ this,
1661
+ );
1662
+
1663
+ return (
1664
+ <div className="perseus-transformation-list">
1665
+ {transformationList}
1666
+ </div>
1667
+ );
1668
+ }
1669
+
1670
+ _transformationRefs = () => {
1671
+ return _.times(this.props.transformations.length, (i) => {
1672
+ // eslint-disable-next-line react/no-string-refs
1673
+ return this.refs["transformation" + i];
1674
+ });
1675
+ };
1676
+
1677
+ value = () => {
1678
+ return _.invoke(this._transformationRefs(), "value");
1679
+ };
1680
+
1681
+ handleChange = (changed: any, callback: any) => {
1682
+ this.props.onChange(this.value(), callback);
1683
+ };
1684
+
1685
+ focusLast = () => {
1686
+ const transformationRefs = this._transformationRefs();
1687
+ if (transformationRefs.length !== 0) {
1688
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'. | TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
1689
+ _.last(transformationRefs).focus();
1690
+ }
1691
+ };
1692
+ }
1693
+
1694
+ class ToolButton extends React.Component<any, any> {
1695
+ render(): React.ReactNode {
1696
+ const classes = this.props.toggled
1697
+ ? "simple-button exercise-orange toggled highlighted-tool-button"
1698
+ : "simple-button";
1699
+
1700
+ return (
1701
+ <button
1702
+ type="button"
1703
+ className={classes}
1704
+ disabled={this.props.disabled}
1705
+ onClick={this.props.onClick}
1706
+ // @ts-expect-error [FEI-5003] - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
1707
+ onTouchStart={captureScratchpadTouchStart}
1708
+ >
1709
+ {this.props.children}
1710
+ </button>
1711
+ );
1712
+ }
1713
+ }
1714
+
1715
+ class ToolsBar extends React.Component<any, any> {
1716
+ state = {
1717
+ selected: null,
1718
+ };
1719
+
1720
+ render(): React.ReactNode {
1721
+ const tools = _.map(
1722
+ Transformations,
1723
+ function (tool, type) {
1724
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1725
+ if (this.props.enabled[type]) {
1726
+ return (
1727
+ <ToolButton
1728
+ key={type}
1729
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1730
+ disabled={this.props.apiOptions.readOnly}
1731
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1732
+ toggled={this.state.selected === type}
1733
+ // eslint-disable-next-line react/jsx-no-bind
1734
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1735
+ onClick={this.changeSelected.bind(this, type)}
1736
+ >
1737
+ {tool.verbName}
1738
+ </ToolButton>
1739
+ );
1740
+ }
1741
+ },
1742
+ this,
1743
+ );
1744
+
1745
+ return (
1746
+ <div className="transformer-tools-bar">
1747
+ <span className="simple-button-group">{tools}</span>
1748
+ <button
1749
+ className="transformer-undo-button simple-button"
1750
+ type="button"
1751
+ disabled={this.props.apiOptions.readOnly}
1752
+ onClick={this.props.onUndoClick}
1753
+ // @ts-expect-error [FEI-5003] - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
1754
+ onTouchStart={captureScratchpadTouchStart}
1755
+ >
1756
+ <InlineIcon {...iconUndo} />
1757
+ {" " + i18n._("Undo")}
1758
+ </button>
1759
+ <div className="clear" />
1760
+ </div>
1761
+ );
1762
+ }
1763
+
1764
+ changeSelected = (tool) => {
1765
+ this.props.removeTool(this.state.selected);
1766
+
1767
+ if (!tool || tool === this.state.selected) {
1768
+ this.setState({
1769
+ selected: null,
1770
+ });
1771
+ } else {
1772
+ this.props.addTool(tool);
1773
+ this.setState({
1774
+ selected: tool,
1775
+ });
1776
+ }
1777
+ };
1778
+ }
1779
+
1780
+ class AddTransformBar extends React.Component<any, any> {
1781
+ render(): React.ReactNode {
1782
+ const tools = _.map(
1783
+ Transformations,
1784
+ function (tool, type) {
1785
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1786
+ if (this.props.enabled[type]) {
1787
+ return (
1788
+ <ToolButton
1789
+ key={type}
1790
+ toggled={false}
1791
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1792
+ disabled={this.props.apiOptions.readOnly}
1793
+ // eslint-disable-next-line react/jsx-no-bind
1794
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
1795
+ onClick={this.changeSelected.bind(this, type)}
1796
+ >
1797
+ <InlineIcon {...iconPlus} /> {tool.nounName}
1798
+ </ToolButton>
1799
+ );
1800
+ }
1801
+ },
1802
+ this,
1803
+ );
1804
+
1805
+ return (
1806
+ <div className="transformer-tools-bar">
1807
+ {tools}
1808
+ <button
1809
+ className="transformer-undo-button simple-button"
1810
+ type="button"
1811
+ onClick={this.props.onUndoClick}
1812
+ disabled={this.props.apiOptions.readOnly}
1813
+ // @ts-expect-error [FEI-5003] - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
1814
+ onTouchStart={captureScratchpadTouchStart}
1815
+ >
1816
+ <InlineIcon {...iconUndo} />
1817
+ {" " + i18n._("Undo")}
1818
+ </button>
1819
+ <div className="clear" />
1820
+ </div>
1821
+ );
1822
+ }
1823
+
1824
+ changeSelected = (tool: any) => {
1825
+ if (tool) {
1826
+ this.props.addTool(tool);
1827
+ }
1828
+ };
1829
+ }
1830
+
1831
+ type Graphie = any;
1832
+ type Tool = any;
1833
+ type ToolCleanup = any;
1834
+
1835
+ type Rubric = PerseusTransformerWidgetOptions;
1836
+ type RenderProps = PerseusTransformerWidgetOptions; // there's no transform in the exports
1837
+ type UserInput = any;
1838
+ type Props = WidgetProps<RenderProps, Rubric> & {
1839
+ transformations: ReadonlyArray<TransformerTransformation>;
1840
+ keypadElement: any;
1841
+ };
1842
+
1843
+ class Transformer extends React.Component<Props> {
1844
+ // @ts-expect-error [FEI-5003] - TS2564 - Property 'tools' has no initializer and is not definitely assigned in the constructor.
1845
+ tools: {
1846
+ [key: string]: Tool;
1847
+ };
1848
+ currentTool: Tool | null | undefined;
1849
+ // @ts-expect-error [FEI-5003] - TS2564 - Property 'transformations' has no initializer and is not definitely assigned in the constructor.
1850
+ transformations: ReadonlyArray<TransformerTransformation>;
1851
+ shape: any | null | undefined; // This is not the same as TransformerShape
1852
+ dilationCircle: any | null | undefined;
1853
+ rotatePoint: any | null | undefined;
1854
+ rotateHandle: any | null | undefined;
1855
+
1856
+ static defaultProps: any = _.defaults(
1857
+ {
1858
+ transformations: [],
1859
+ },
1860
+ defaultTransformerProps,
1861
+ );
1862
+
1863
+ render(): React.ReactNode {
1864
+ // Fill in any missing value in this.props.graph
1865
+ // this can happen because the graph json doesn't include
1866
+ // box, for example
1867
+ const graph = _.extend(
1868
+ defaultGraphProps(this.props.graph, defaultBoxSize),
1869
+ this.props.graph,
1870
+ );
1871
+
1872
+ const interactiveToolsMode = this.props.graphMode === "interactive";
1873
+
1874
+ const ToolsBarClass = interactiveToolsMode ? ToolsBar : AddTransformBar;
1875
+
1876
+ // This style is applied inline because it is dependent on the
1877
+ // size of the graph as set by the graph.box prop, and this also
1878
+ // lets us specify it in the same place the graph's width is
1879
+ // specified.
1880
+ const toolsBar = (
1881
+ <div style={{width: graph.box[0]}}>
1882
+ <ToolsBarClass
1883
+ // eslint-disable-next-line react/no-string-refs
1884
+ ref="toolsBar"
1885
+ enabled={pluckObject(this.props.tools, "enabled")}
1886
+ apiOptions={this.props.apiOptions}
1887
+ addTool={this.addTool}
1888
+ removeTool={this.removeTool}
1889
+ onUndoClick={this.handleUndoClick}
1890
+ />
1891
+ </div>
1892
+ );
1893
+
1894
+ return (
1895
+ <div className={"perseus-widget " + "perseus-widget-transformer"}>
1896
+ <Graph
1897
+ // eslint-disable-next-line react/no-string-refs
1898
+ ref="graph"
1899
+ box={graph.box}
1900
+ range={graph.range}
1901
+ labels={graph.labels}
1902
+ step={graph.step}
1903
+ gridStep={graph.gridStep}
1904
+ markings={graph.markings}
1905
+ backgroundImage={graph.backgroundImage}
1906
+ showProtractor={graph.showProtractor}
1907
+ onGraphieUpdated={this.setupGraphie}
1908
+ setDrawingAreaAvailable={
1909
+ this.props.apiOptions.setDrawingAreaAvailable
1910
+ }
1911
+ />
1912
+
1913
+ {!interactiveToolsMode && i18n._("Add transformations below:")}
1914
+
1915
+ {this.props.graphMode === "static" && [
1916
+ <br key="static-br" />,
1917
+ <em key="static-nomove">
1918
+ {" "}
1919
+ {i18n._(
1920
+ "Note: For this question, the shape will not move.",
1921
+ )}{" "}
1922
+ </em>,
1923
+ ]}
1924
+
1925
+ {interactiveToolsMode && toolsBar}
1926
+
1927
+ <TransformationList
1928
+ // eslint-disable-next-line react/no-string-refs
1929
+ ref="transformationList"
1930
+ mode={this.props.listMode}
1931
+ transformations={this.props.transformations}
1932
+ onChange={this.setTransformationProps}
1933
+ onFocus={this._handleFocus}
1934
+ onBlur={this._handleBlur}
1935
+ keypadElement={this.props.keypadElement}
1936
+ apiOptions={this.props.apiOptions}
1937
+ />
1938
+
1939
+ {!interactiveToolsMode && toolsBar}
1940
+ </div>
1941
+ );
1942
+ }
1943
+
1944
+ componentDidMount() {
1945
+ this.setupGraphie(this.graphie());
1946
+ }
1947
+
1948
+ componentDidUpdate(prevProps: Props) {
1949
+ if (this.shouldSetupGraphie(this.props, prevProps)) {
1950
+ // eslint-disable-next-line react/no-string-refs
1951
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'reset' does not exist on type 'ReactInstance'.
1952
+ this.refs.graph.reset();
1953
+ } else if (!deepEq(this.props.transformations, this.transformations)) {
1954
+ this.setTransformations(this.props.transformations);
1955
+ }
1956
+ }
1957
+
1958
+ shouldSetupGraphie: (arg1: Props, arg2: Props) => boolean = (
1959
+ nextProps,
1960
+ prevProps,
1961
+ ) => {
1962
+ if (!deepEq(prevProps.starting, nextProps.starting)) {
1963
+ return true;
1964
+ }
1965
+ if (prevProps.graphMode !== nextProps.graphMode) {
1966
+ return true;
1967
+ }
1968
+ if (prevProps.listMode !== nextProps.listMode) {
1969
+ return true;
1970
+ }
1971
+ if (prevProps.drawSolutionShape !== nextProps.drawSolutionShape) {
1972
+ return true;
1973
+ }
1974
+ if (
1975
+ nextProps.drawSolutionShape &&
1976
+ !deepEq(prevProps.correct.shape, nextProps.correct.shape)
1977
+ ) {
1978
+ return true;
1979
+ }
1980
+ if (!deepEq(this.tools, nextProps.tools)) {
1981
+ return true;
1982
+ }
1983
+ return false;
1984
+ };
1985
+
1986
+ graphie: () => Graphie = () => {
1987
+ // eslint-disable-next-line react/no-string-refs
1988
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
1989
+ return this.refs.graph.graphie();
1990
+ };
1991
+
1992
+ setupGraphie: (arg1: Graphie) => void = (graphie) => {
1993
+ // A background image of our solution:
1994
+ if (
1995
+ this.props.drawSolutionShape &&
1996
+ this.props.correct.shape &&
1997
+ this.props.correct.shape.coords
1998
+ ) {
1999
+ // @ts-expect-error [FEI-5003] - TS2554 - Expected 3 arguments, but got 2.
2000
+ ShapeTypes.addShape(graphie, {
2001
+ fixed: true,
2002
+ shape: this.props.correct.shape,
2003
+ normalStyle: {
2004
+ stroke: KhanColors.GRAY,
2005
+ "stroke-dasharray": "",
2006
+ "stroke-width": 2,
2007
+ },
2008
+ });
2009
+ }
2010
+
2011
+ this.currentTool = null;
2012
+ // eslint-disable-next-line react/no-string-refs
2013
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'changeSelected' does not exist on type 'ReactInstance'.
2014
+ this.refs.toolsBar.changeSelected(null);
2015
+ this.addTransformerShape(
2016
+ this.props.starting.shape,
2017
+ /* translatable */ false,
2018
+ );
2019
+ this.setTransformations(this.props.transformations);
2020
+
2021
+ // Save a copy of our tools so that we can check future
2022
+ // this.props.tools changes against them
2023
+ // This seems weird, but gives us an easy way to tell whether
2024
+ // props changes were self-inflicted (for which a graphie reset
2025
+ // is not required, and is in fact a bad idea right now because
2026
+ // of resetting the size of the dilation tool).
2027
+ // TODO (jack): A deepClone method would be nice here
2028
+ this.tools = {
2029
+ translation: _.clone(this.props.tools.translation),
2030
+ rotation: _.clone(this.props.tools.rotation),
2031
+ reflection: _.clone(this.props.tools.reflection),
2032
+ dilation: _.clone(this.props.tools.dilation),
2033
+ };
2034
+ };
2035
+
2036
+ /* Applies all transformations in `transformations`
2037
+ * to the starting shape, and updates this.transformations
2038
+ * to reflect this
2039
+ *
2040
+ * Usually called with this.props.transformations
2041
+ */
2042
+ setTransformations: (
2043
+ arg1: ReadonlyArray<TransformerTransformation>,
2044
+ ) => void = (transformations) => {
2045
+ this.resetCoords();
2046
+ this.transformations = _.clone(transformations);
2047
+ _.each(this.transformations, this.applyTransform);
2048
+ };
2049
+
2050
+ // the polygon that we transform
2051
+ addTransformerShape: (arg1: any, arg2: boolean) => void = (
2052
+ shape,
2053
+ translatable,
2054
+ ) => {
2055
+ const self = this;
2056
+ const graphie = this.graphie();
2057
+
2058
+ this.shape = ShapeTypes.addMovableShape(graphie, {
2059
+ shape: shape,
2060
+ editable: false,
2061
+ showPoints: this.props.graphMode !== "static",
2062
+ translatable: translatable,
2063
+ onMove: function (dX, dY) {
2064
+ dX = KhanMath.roundToNearest(graphie.snap[0], dX);
2065
+ dY = KhanMath.roundToNearest(graphie.snap[1], dY);
2066
+ // NOTE(kevinb): object is missing .constraints property
2067
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type '{ type: "translation"; vector: [any, any]; }' is not assignable to parameter of type 'PerseusTransformerTransformation'.
2068
+ self.addTransform({
2069
+ type: "translation",
2070
+ vector: [dX, dY],
2071
+ });
2072
+ return [dX, dY];
2073
+ },
2074
+ normalPointStyle: {
2075
+ fill: translatable
2076
+ ? KhanColors.INTERACTIVE
2077
+ : KhanColors.DYNAMIC,
2078
+ stroke: translatable
2079
+ ? KhanColors.INTERACTIVE
2080
+ : KhanColors.DYNAMIC,
2081
+ },
2082
+ highlightPointStyle: {
2083
+ fill: KhanColors.INTERACTING,
2084
+ stroke: KhanColors.INTERACTING,
2085
+ },
2086
+ });
2087
+ };
2088
+
2089
+ addTool: (arg1: TransformerTransformation["type"]) => void = (toolId) => {
2090
+ const self = this;
2091
+
2092
+ if (this.props.graphMode === "interactive") {
2093
+ if (toolId === "translation") {
2094
+ this.currentTool = this.addTranslationTool();
2095
+ } else if (toolId === "rotation") {
2096
+ this.currentTool = this.addRotationTool();
2097
+ } else if (toolId === "reflection") {
2098
+ this.currentTool = this.addReflectionTool();
2099
+ } else if (toolId === "dilation") {
2100
+ this.currentTool = this.addDilationTool();
2101
+ } else {
2102
+ throw new PerseusError(
2103
+ "Invalid tool id: " + toolId,
2104
+ Errors.InvalidInput,
2105
+ );
2106
+ }
2107
+ } else {
2108
+ let transform: TransformerTransformation;
2109
+ if (toolId === "translation") {
2110
+ // NOTE(kevinb): object is missing .constraints property
2111
+ transform = {
2112
+ type: "translation",
2113
+ // NOTE(kevib): these should be numbers
2114
+ // $FlowFixMe[incompatible-type]
2115
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
2116
+ vector: [null, null],
2117
+ };
2118
+ } else if (toolId === "rotation") {
2119
+ // NOTE(kevinb): object is missing .constraints property
2120
+ transform = {
2121
+ type: "rotation",
2122
+ // NOTE(kevib): these should be numbers
2123
+ // $FlowFixMe[incompatible-type]
2124
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
2125
+ center: [null, null],
2126
+ // NOTE(kevib): this should be a number
2127
+ // $FlowFixMe[incompatible-type]
2128
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'null' is not assignable to type 'number'.
2129
+ angleDeg: null,
2130
+ };
2131
+ } else if (toolId === "reflection") {
2132
+ // Reflections with nulls in them won't be applied until
2133
+ // fills in the blanks
2134
+ transform = {
2135
+ type: "reflection",
2136
+ line: [
2137
+ // NOTE(kevib): these should be numbers
2138
+ // $FlowFixMe[incompatible-type]
2139
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
2140
+ [null, null],
2141
+ // NOTE(kevib): these should be numbers
2142
+ // $FlowFixMe[incompatible-type]
2143
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
2144
+ [null, null],
2145
+ ],
2146
+ };
2147
+ } else if (toolId === "dilation") {
2148
+ // NOTE(kevinb): object is missing .constraints property
2149
+ transform = {
2150
+ type: "dilation",
2151
+ // NOTE(kevib): these should be numbers
2152
+ // $FlowFixMe[incompatible-type]
2153
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
2154
+ center: [null, null],
2155
+ // NOTE(kevib): this should be a number
2156
+ // $FlowFixMe[incompatible-type]
2157
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'null' is not assignable to type 'number'.
2158
+ scale: null,
2159
+ };
2160
+ } else {
2161
+ throw new PerseusError(
2162
+ "Invalid tool id: " + toolId,
2163
+ Errors.InvalidInput,
2164
+ );
2165
+ }
2166
+
2167
+ this.doTransform(transform, function () {
2168
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'focusLast' does not exist on type 'ReactInstance'.
2169
+ self.refs.transformationList.focusLast();
2170
+ });
2171
+ }
2172
+ };
2173
+
2174
+ removeTool: (arg1: string) => void = (toolId) => {
2175
+ if (this.currentTool) {
2176
+ this.currentTool.remove();
2177
+ }
2178
+ this.currentTool = null;
2179
+ };
2180
+
2181
+ addTranslationTool: () => any = () => {
2182
+ const self = this;
2183
+ this.shape?.remove();
2184
+ this.addTransformerShape(this.shape?.toJSON(), /* translatable */ true);
2185
+
2186
+ return {
2187
+ remove: function () {
2188
+ self.shape?.remove();
2189
+ self.addTransformerShape(
2190
+ self.shape?.toJSON(),
2191
+ /* translatable */ false,
2192
+ );
2193
+ },
2194
+ };
2195
+ };
2196
+
2197
+ // Snaps a coord to this.graphie()'s snap
2198
+ // @ts-expect-error [FEI-5003] - TS2322 - Type '(coord: Coord) => number[]' is not assignable to type '(arg1: Coord) => Coord'.
2199
+ snapCoord: (arg1: Coord) => Coord = (coord) => {
2200
+ const graphie = this.graphie();
2201
+ return _.map(coord, function (val, dim) {
2202
+ return KhanMath.roundToNearest(graphie.snap[dim], val);
2203
+ });
2204
+ };
2205
+
2206
+ // Normalize the coords into something that fits the new 45 degree
2207
+ // reflection line.
2208
+ // @ts-expect-error [FEI-5003] - TS2322 - Type '(messyCoords: [Coord, Coord]) => any[]' is not assignable to type '(arg1: [Coord, Coord]) => [Coord, Coord]'.
2209
+ normalizeReflectionCoords: (arg1: [Coord, Coord]) => [Coord, Coord] = (
2210
+ messyCoords,
2211
+ ) => {
2212
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'Point' is not assignable to parameter of type 'Coord'.
2213
+ const midpoint = this.snapCoord(kline.midpoint(messyCoords));
2214
+ const origDirectionPolar = kvector.polarDegFromCart(
2215
+ kvector.subtract(messyCoords[0], messyCoords[1]),
2216
+ );
2217
+
2218
+ const direction = kvector.cartFromPolarDeg(
2219
+ 1,
2220
+ KhanMath.roundToNearest(45, origDirectionPolar[1]),
2221
+ );
2222
+ const coords = _.map(
2223
+ [-1, 1],
2224
+ function (directionCoefficient) {
2225
+ const coord = kvector.add(
2226
+ midpoint,
2227
+ kvector.scale(
2228
+ direction,
2229
+ directionCoefficient *
2230
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
2231
+ this.scaleToCurrentRange(
2232
+ REFLECT_ROTATE_HANDLE_DIST,
2233
+ ),
2234
+ ),
2235
+ );
2236
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
2237
+ return this.snapCoord(coord);
2238
+ },
2239
+ this,
2240
+ );
2241
+ return coords;
2242
+ };
2243
+
2244
+ addReflectionTool: () => ToolCleanup = () => {
2245
+ const options = this.props.tools.reflection;
2246
+ if (!options.enabled) {
2247
+ return;
2248
+ }
2249
+ const self = this;
2250
+ // eslint-disable-next-line react/no-string-refs
2251
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
2252
+ const graphie = this.refs.graph.graphie();
2253
+
2254
+ const updateReflectionTool = function () {
2255
+ self.changeTool("reflection", {
2256
+ coords: _.pluck(reflectPoints, "coord"),
2257
+ });
2258
+ };
2259
+
2260
+ const coords = this.normalizeReflectionCoords(options.coords);
2261
+
2262
+ // The points defining the line of reflection; hidden from the
2263
+ // user.
2264
+ const reflectPoints = _.map(
2265
+ coords,
2266
+ function (coord) {
2267
+ return graphie.addMovablePoint({
2268
+ coord: coord,
2269
+ visible: false,
2270
+ });
2271
+ },
2272
+ this,
2273
+ );
2274
+
2275
+ // the line of reflection
2276
+ // TODO(jack): graphie.style here is a hack to prevent the dashed
2277
+ // style from leaking into the rest of the shapes. Remove when
2278
+ // graphie.addMovableLineSegment doesn't leak styles anymore.
2279
+ let reflectLine;
2280
+ const normalColor = colorForTool(options);
2281
+ graphie.style({}, function () {
2282
+ reflectLine = graphie.addMovableLineSegment({
2283
+ fixed: options.constraints.fixed,
2284
+ constraints: options.constraints,
2285
+ pointA: reflectPoints[0],
2286
+ pointZ: reflectPoints[1],
2287
+ snapX: graphie.snap[0],
2288
+ snapY: graphie.snap[1],
2289
+ extendLine: true,
2290
+ normalStyle: {
2291
+ stroke: normalColor,
2292
+ "stroke-width": 2,
2293
+ "stroke-dasharray": "- ",
2294
+ },
2295
+ highlightStyle: {
2296
+ stroke: KhanColors.INTERACTING,
2297
+ "stroke-width": 2,
2298
+ "stroke-dasharray": "- ", // TODO(jack) solid doesn't
2299
+ // work here, but would be
2300
+ // nicer
2301
+ },
2302
+ movePointsWithLine: true,
2303
+ onMoveEnd: updateReflectionTool,
2304
+ });
2305
+ });
2306
+
2307
+ // the "button" point in the center of the line of reflection
2308
+ const reflectButton = graphie.addReflectButton({
2309
+ fixed: options.constraints.fixed,
2310
+ line: reflectLine,
2311
+ size: this.scaleToCurrentRange(REFLECT_BUTTON_SIZE),
2312
+ onClick: function () {
2313
+ self.doTransform({
2314
+ type: "reflection",
2315
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'any[]' is not assignable to type '[Coord, Coord]'.
2316
+ line: _.pluck(reflectPoints, "coord"),
2317
+ });
2318
+ if (reflectRotateHandle) {
2319
+ // flip the rotation handle
2320
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'setCoord' does not exist on type 'never'.
2321
+ reflectRotateHandle.setCoord(
2322
+ kvector.add(
2323
+ reflectButton.coord,
2324
+ kvector.subtract(
2325
+ reflectButton.coord,
2326
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'coord' does not exist on type 'never'.
2327
+ reflectRotateHandle.coord,
2328
+ ),
2329
+ ),
2330
+ );
2331
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'update' does not exist on type 'never'.
2332
+ reflectRotateHandle.update();
2333
+ }
2334
+ },
2335
+ normalStyle: {
2336
+ stroke: normalColor,
2337
+ "stroke-width": 2,
2338
+ fill: normalColor,
2339
+ },
2340
+ highlightStyle: {
2341
+ stroke: KhanColors.INTERACTING,
2342
+ "stroke-width": 3,
2343
+ fill: KhanColors.INTERACTING,
2344
+ },
2345
+ onMoveEnd: updateReflectionTool,
2346
+ });
2347
+
2348
+ let reflectRotateHandle = null;
2349
+ if (!options.constraints.fixed) {
2350
+ // The rotation handle for rotating the line of reflection
2351
+ const initRotateHandleAngle =
2352
+ kvector.polarDegFromCart(
2353
+ kvector.subtract(
2354
+ reflectPoints[1].coord,
2355
+ reflectPoints[0].coord,
2356
+ ),
2357
+ )[1] + 90; // 90 degrees off of the line
2358
+ reflectRotateHandle = graphie.addRotateHandle({
2359
+ center: reflectButton,
2360
+ radius: this.scaleToCurrentRange(REFLECT_ROTATE_HANDLE_DIST),
2361
+ angleDeg: initRotateHandleAngle,
2362
+ width: this.scaleToCurrentRange(0.24),
2363
+ hoverWidth: this.scaleToCurrentRange(0.4),
2364
+ lengthAngle: 17,
2365
+ onMove: function (newAngle) {
2366
+ return KhanMath.roundToNearest(45, newAngle);
2367
+ },
2368
+ onMoveEnd: updateReflectionTool,
2369
+ });
2370
+ }
2371
+
2372
+ // Move the reflectButton and reflectRotateHandle with the line
2373
+ $(reflectLine).on("move", function () {
2374
+ reflectButton.update();
2375
+ $(reflectButton).trigger("move"); // update the rotation handle,
2376
+ // which watches for this in util/interactive.js.
2377
+ });
2378
+
2379
+ // Update the line and reflect button when the reflectRotateHandle is
2380
+ // rotated
2381
+ if (reflectRotateHandle) {
2382
+ $(reflectRotateHandle).on("move", function () {
2383
+ const rotateHandleApprox = self.snapCoord(
2384
+ // $FlowFixMe[incompatible-use]
2385
+ // @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
2386
+ reflectRotateHandle.coord,
2387
+ );
2388
+
2389
+ const rotateVector = kvector.subtract(
2390
+ rotateHandleApprox,
2391
+ reflectButton.coord,
2392
+ );
2393
+
2394
+ const flipped = reflectButton.isFlipped() ? 1 : 0;
2395
+ reflectPoints[flipped].setCoord(
2396
+ kvector.add(
2397
+ reflectButton.coord,
2398
+ kvector.rotateDeg(rotateVector, 90),
2399
+ ),
2400
+ );
2401
+ reflectPoints[1 - flipped].setCoord(
2402
+ kvector.add(
2403
+ reflectButton.coord,
2404
+ kvector.rotateDeg(rotateVector, -90),
2405
+ ),
2406
+ );
2407
+
2408
+ reflectLine.transform(true);
2409
+ reflectButton.update();
2410
+ });
2411
+ }
2412
+
2413
+ return {
2414
+ remove: function () {
2415
+ reflectButton.remove();
2416
+ if (reflectRotateHandle) {
2417
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'remove' does not exist on type 'never'.
2418
+ reflectRotateHandle.remove();
2419
+ }
2420
+ reflectLine.remove();
2421
+ reflectPoints[0].remove();
2422
+ reflectPoints[1].remove();
2423
+ },
2424
+ };
2425
+ };
2426
+
2427
+ /* Scales a distance from the default range of
2428
+ * [-10, 10] to the current this.props.graph.range
2429
+ *
2430
+ * Used for sizing various transformation tools
2431
+ * (rotation handle, dilation circle)
2432
+ */
2433
+ scaleToCurrentRange: (arg1: number) => number = (dist) => {
2434
+ // eslint-disable-next-line react/no-string-refs
2435
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'props' does not exist on type 'ReactInstance'.
2436
+ return scaleToRange(dist, this.refs.graph.props.range);
2437
+ };
2438
+
2439
+ addRotationTool: () => ToolCleanup = () => {
2440
+ const options = this.props.tools.rotation;
2441
+ if (!options.enabled) {
2442
+ return;
2443
+ }
2444
+ const self = this;
2445
+ // eslint-disable-next-line react/no-string-refs
2446
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
2447
+ const graphie = this.refs.graph.graphie();
2448
+
2449
+ const pointColor = colorForTool(options);
2450
+ // The center of our rotation, which can be moved to change the
2451
+ // center of rotation
2452
+ this.rotatePoint = graphie.addMovablePoint({
2453
+ constraints: options.constraints,
2454
+ coord: options.coord,
2455
+ snapX: graphie.snap[0],
2456
+ snapY: graphie.snap[1],
2457
+ normalStyle: {
2458
+ // ugh, this seems to be a global and
2459
+ "stroke-dasharray": "", // is set to dash above
2460
+ stroke: pointColor,
2461
+ fill: pointColor,
2462
+ },
2463
+ highlightStyle: {
2464
+ "stroke-dasharray": "",
2465
+ stroke: KhanColors.INTERACTING,
2466
+ fill: KhanColors.INTERACTING,
2467
+ },
2468
+ });
2469
+
2470
+ // The point that we move around the center of rotation to actually
2471
+ // cause rotations
2472
+ this.rotateHandle = graphie.addRotateHandle({
2473
+ center: this.rotatePoint,
2474
+ radius: this.scaleToCurrentRange(ROTATE_HANDLE_DIST),
2475
+ width: this.scaleToCurrentRange(0.24),
2476
+ hoverWidth: this.scaleToCurrentRange(0.4),
2477
+ onMove: function (newAngle, oldAngle) {
2478
+ const transform = self.getRotationTransformFromAngle(
2479
+ // $FlowFixMe[incompatible-use]
2480
+ self.rotatePoint.coord,
2481
+ newAngle - oldAngle,
2482
+ );
2483
+
2484
+ // Rotate polygon with rotateHandle
2485
+ self.doTransform(transform);
2486
+
2487
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'angleDeg' does not exist on type 'PerseusTransformerTransformation'.
2488
+ return oldAngle + transform.angleDeg;
2489
+ },
2490
+ });
2491
+
2492
+ // Update tools.rotation.coord
2493
+ this.rotatePoint.onMoveEnd = (x: any, y: any) => {
2494
+ self.changeTool("rotation", {
2495
+ coord: [x, y],
2496
+ });
2497
+ };
2498
+
2499
+ return {
2500
+ remove: function () {
2501
+ self.rotateHandle?.remove();
2502
+ self.rotatePoint?.remove();
2503
+ },
2504
+ };
2505
+ };
2506
+
2507
+ addDilationTool: () => ToolCleanup = () => {
2508
+ const options = this.props.tools.dilation;
2509
+ if (!options.enabled) {
2510
+ return;
2511
+ }
2512
+ const self = this;
2513
+ // eslint-disable-next-line react/no-string-refs
2514
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
2515
+ const graphie = this.refs.graph.graphie();
2516
+
2517
+ const pointColor = colorForTool(options);
2518
+ // the circle for causing dilation transforms
2519
+ self.dilationCircle = graphie.addCircleGraph({
2520
+ centerConstraints: options.constraints,
2521
+ center: options.coord,
2522
+ radius: self.scaleToCurrentRange(2),
2523
+ snapX: graphie.snap[0],
2524
+ snapY: graphie.snap[1],
2525
+ minRadius: self.scaleToCurrentRange(1),
2526
+ snapRadius: self.scaleToCurrentRange(0.5),
2527
+ onResize: function (newRadius, oldRadius) {
2528
+ // NOTE(kevinb): object is missing .constraints property
2529
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type '{ type: "dilation"; center: any; scale: number; }' is not assignable to parameter of type 'PerseusTransformerTransformation'.
2530
+ self.doTransform({
2531
+ type: "dilation",
2532
+ // NOTE(kevinb): It's hard to convince that this.dilationCircle
2533
+ // will still be defined here.
2534
+ // $FlowFixMe[incompatible-use]
2535
+ center: self.dilationCircle.centerPoint.coord,
2536
+ scale: newRadius / oldRadius,
2537
+ });
2538
+ },
2539
+ circleNormalStyle: {
2540
+ stroke: pointColor,
2541
+ "stroke-width": 2,
2542
+ "stroke-dasharray": "- ",
2543
+ "fill-opacity": 0,
2544
+ },
2545
+ circleHighlightStyle: {
2546
+ stroke: KhanColors.INTERACTING,
2547
+ "stroke-width": 2,
2548
+ "stroke-dasharray": "",
2549
+ fill: KhanColors.INTERACTING,
2550
+ "fill-opacity": 0.05,
2551
+ },
2552
+ centerNormalStyle: {
2553
+ stroke: pointColor,
2554
+ fill: pointColor,
2555
+ "stroke-width": 2,
2556
+ "stroke-dasharray": "",
2557
+ },
2558
+ centerHighlightStyle: {
2559
+ stroke: pointColor,
2560
+ fill: pointColor,
2561
+ "stroke-width": 2,
2562
+ "stroke-dasharray": "",
2563
+ },
2564
+ });
2565
+
2566
+ const origOnMoveEnd = this.dilationCircle.centerPoint.onMoveEnd;
2567
+ this.dilationCircle.centerPoint.onMoveEnd = (...args) => {
2568
+ if (origOnMoveEnd) {
2569
+ origOnMoveEnd(args);
2570
+ }
2571
+ self.changeTool("dilation", {
2572
+ // $FlowFixMe[incompatible-use]
2573
+ coord: self.dilationCircle.centerPoint.coord,
2574
+ });
2575
+ };
2576
+
2577
+ return {
2578
+ remove: function () {
2579
+ self.dilationCircle?.remove();
2580
+ },
2581
+ };
2582
+ };
2583
+
2584
+ // returns a transformation object representing a rotation
2585
+ // rounds the angle to the nearest 15 degrees
2586
+ // @ts-expect-error [FEI-5003] - TS2322 - Type '(center: Coord, angleChanged: number) => { type: "rotation"; center: Coord; angleDeg: number; }' is not assignable to type '(arg1: Coord, arg2: number) => PerseusTransformerTransformation'.
2587
+ getRotationTransformFromAngle: (
2588
+ arg1: Coord,
2589
+ arg2: number,
2590
+ ) => TransformerTransformation = (center, angleChanged) => {
2591
+ angleChanged = (angleChanged + 360) % 360;
2592
+ if (angleChanged > 180) {
2593
+ angleChanged -= 360;
2594
+ }
2595
+ const roundedAngle =
2596
+ Math.round(angleChanged / ROTATE_SNAP_DEGREES) *
2597
+ ROTATE_SNAP_DEGREES;
2598
+
2599
+ // NOTE(kevinb): return object is missing .constraints property
2600
+ return {
2601
+ type: "rotation",
2602
+ center: center,
2603
+ angleDeg: roundedAngle,
2604
+ };
2605
+ };
2606
+
2607
+ // apply and save a transform
2608
+ doTransform: (
2609
+ arg1: TransformerTransformation,
2610
+ arg2?: (arg1: any) => unknown | null | undefined,
2611
+ ) => void = (transform, callback) => {
2612
+ this.applyTransform(transform);
2613
+ this.addTransform(transform, callback);
2614
+ };
2615
+
2616
+ // apply a transform to our polygon (without modifying our transformation
2617
+ // list)
2618
+ applyTransform: (arg1: TransformerTransformation) => void = (transform) => {
2619
+ if (this.props.graphMode !== "static") {
2620
+ const transformFunc = TransformOps.apply(transform);
2621
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type '(coord: any) => any' is not assignable to parameter of type 'PerseusTransformerTransformation'.
2622
+ this.applyCoordTransformation(transformFunc);
2623
+ }
2624
+ };
2625
+
2626
+ // transform our polygon by transforming each point using a given function
2627
+ applyCoordTransformation: (arg1: TransformerTransformation) => void = (
2628
+ pointTransform,
2629
+ ) => {
2630
+ _.each(this.shape.points, function (point) {
2631
+ // @ts-expect-error [FEI-5003] - TS2349 - This expression is not callable.
2632
+ const newCoord = pointTransform(point.coord);
2633
+ point.setCoord(newCoord);
2634
+ });
2635
+ this.shape?.update();
2636
+ };
2637
+
2638
+ resetCoords: () => void = () => {
2639
+ const startCoords = this.props.starting.shape.coords;
2640
+ _.each(this.shape.points, function (point, i) {
2641
+ point.setCoord(startCoords[i]);
2642
+ });
2643
+ this.shape?.update();
2644
+ };
2645
+
2646
+ // Remove the last transformation
2647
+ handleUndoClick: () => void = () => {
2648
+ // eslint-disable-next-line react/no-string-refs
2649
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'changeSelected' does not exist on type 'ReactInstance'.
2650
+ this.refs.toolsBar.changeSelected(null);
2651
+ if (this.props.transformations.length) {
2652
+ this.props.onChange({
2653
+ transformations: _.initial(this.props.transformations),
2654
+ });
2655
+ }
2656
+ };
2657
+
2658
+ setTransformationProps: (
2659
+ arg1: ReadonlyArray<TransformerTransformation>,
2660
+ arg2: (arg1: any) => unknown,
2661
+ ) => void = (newTransfomationList, callback) => {
2662
+ this.props.onChange(
2663
+ {
2664
+ transformations: newTransfomationList,
2665
+ },
2666
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type '(arg1: any) => unknown' is not assignable to parameter of type '() => unknown'.
2667
+ callback,
2668
+ );
2669
+ };
2670
+
2671
+ // add a transformation to our props list of transformation
2672
+ addTransform: (
2673
+ arg1: TransformerTransformation,
2674
+ arg2?: (arg1: any) => unknown | null | undefined,
2675
+ ) => void = (transform, callback) => {
2676
+ this.transformations = TransformOps.append(
2677
+ this.transformations,
2678
+ transform,
2679
+ );
2680
+ this.props.onChange(
2681
+ {
2682
+ transformations: _.clone(this.transformations),
2683
+ },
2684
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type '((arg1: any) => unknown) | undefined' is not assignable to parameter of type '(() => unknown) | undefined'.
2685
+ callback,
2686
+ );
2687
+ };
2688
+
2689
+ changeTool: (arg1: Tool, arg2: any) => void = (tool, changes) => {
2690
+ const newTools = _.clone(this.props.tools);
2691
+ newTools[tool] = _.extend({}, this.props.tools[tool], changes);
2692
+ this.tools[tool] = _.clone(newTools[tool]);
2693
+ this.props.onChange({
2694
+ // @ts-expect-error [FEI-5003] - TS2740 - Type '{ dilation: DilationTool; reflection: ReflectionTool; rotation: RotationTool; translation: TranslationTool; }' is missing the following properties from type 'readonly any[]': length, concat, join, slice, and 18 more.
2695
+ tools: newTools,
2696
+ });
2697
+ this.props.trackInteraction();
2698
+ };
2699
+
2700
+ simpleValidate: (arg1: Rubric) => PerseusScore = (rubric) => {
2701
+ return Transformer.validate(this.getUserInput(), rubric);
2702
+ };
2703
+
2704
+ /**
2705
+ * Calculate where the coordinates would be if they were
2706
+ * moved, even if we're in formal mode with no movement
2707
+ * (and thus the actual movablepoints may not have moved
2708
+ */
2709
+ // @ts-expect-error [FEI-5003] - TS2322 - Type '() => [Coord, Coord] | readonly Coord[] | [Coord, Coord, Coord]' is not assignable to type '() => Coord'.
2710
+ getCoords: () => Coord = () => {
2711
+ const startCoords = this.props.starting.shape.coords;
2712
+ const transforms = this.props.transformations;
2713
+ return _.reduce(
2714
+ transforms,
2715
+ function (coords, transform) {
2716
+ return _.map(coords, TransformOps.apply(transform));
2717
+ },
2718
+ startCoords,
2719
+ );
2720
+ };
2721
+
2722
+ getEditorJSON: () => any = () => {
2723
+ const json = _.pick(
2724
+ this.props,
2725
+ "grading",
2726
+ "starting",
2727
+ "graphMode",
2728
+ "listMode",
2729
+ "tools",
2730
+ "drawSolutionShape",
2731
+ "gradeEmpty",
2732
+ );
2733
+ // eslint-disable-next-line react/no-string-refs
2734
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'graph' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'. | TS2339 - Property 'toJSON' does not exist on type 'ReactInstance'.
2735
+ json.graph = this.refs.graph.toJSON();
2736
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'version' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'.
2737
+ json.version = 1.2; // Give us some safety to change the format
2738
+ // when we realize that I wrote
2739
+ // a horrible json spec for this widget
2740
+
2741
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'answer' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'.
2742
+ json.answer = this.getUserInput();
2743
+ return json;
2744
+ };
2745
+
2746
+ getUserInput: UserInput = () => {
2747
+ return {
2748
+ transformations: this.props.transformations,
2749
+ // This doesn't call this.shape.toJSON() because that doesn't
2750
+ // handle coordinates in formal mode without movement, since
2751
+ // the movablepoints never move
2752
+ shape: {
2753
+ // $FlowFixMe[incompatible-use]
2754
+ type: this.shape.type,
2755
+ coords: this.getCoords(),
2756
+ options: this.shape?.getOptions(),
2757
+ },
2758
+ };
2759
+ };
2760
+
2761
+ /* InputPath API */
2762
+
2763
+ _handleFocus: (...rest: ReadonlyArray<string>) => void = (...path) => {
2764
+ this.props.onFocus(path);
2765
+ };
2766
+
2767
+ _handleBlur: (...rest: ReadonlyArray<string>) => void = (...path) => {
2768
+ this.props.onBlur(path);
2769
+ };
2770
+
2771
+ _getTransformationForID: (arg1: string) => any = (transformationID) => {
2772
+ // Returns the 'transformation' component corresponding to a given ID
2773
+ const refPath = [
2774
+ "transformationList",
2775
+ "transformation" + transformationID,
2776
+ ];
2777
+
2778
+ // Follow the path of references
2779
+ let component = this;
2780
+ _.each(refPath, (ref) => {
2781
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'ReactInstance' is not assignable to type 'this'.
2782
+ component = component.refs[ref];
2783
+ });
2784
+ return component;
2785
+ };
2786
+
2787
+ getInputPaths: () => ReadonlyArray<Path> = () => {
2788
+ // If we're in static mode, then there is no transformation list, and,
2789
+ // as a result, no input paths.
2790
+ if (this.props.listMode === "static") {
2791
+ return [];
2792
+ }
2793
+
2794
+ let inputPaths: Array<never> | Array<any> = [];
2795
+ _.each(this.props.transformations, (transformation, i) => {
2796
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'number' is not assignable to parameter of type 'string'.
2797
+ transformation = this._getTransformationForID(i);
2798
+ // @ts-expect-error [FEI-5003] - TS2339 - Property 'getInputPaths' does not exist on type 'PerseusTransformerTransformation'.
2799
+ const innerPaths = transformation.getInputPaths();
2800
+ const fullPaths = _.map(innerPaths, (innerPath) => {
2801
+ return ["" + i].concat(innerPath);
2802
+ });
2803
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'string[][]' is not assignable to parameter of type 'ConcatArray<never>'.
2804
+ inputPaths = inputPaths.concat(fullPaths);
2805
+ });
2806
+ return inputPaths;
2807
+ };
2808
+
2809
+ _passToInner: (
2810
+ arg1: string,
2811
+ arg2: ReadonlyArray<string>,
2812
+ arg3?: any | null | undefined,
2813
+ arg4?: (arg1: any) => unknown | null | undefined,
2814
+ ) => any = function (functionName, path, ...args) {
2815
+ if (!path || !path.length) {
2816
+ return;
2817
+ }
2818
+
2819
+ // First argument tells us which transformation will receive the call;
2820
+ // remaining arguments are used within that transformation to identify
2821
+ // a specific input.
2822
+ const innerPath = _.rest(path);
2823
+
2824
+ // Pass arguments down to appropriate 'transformation' component
2825
+ const transformationID = _.head(path);
2826
+ // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
2827
+ const caller = this._getTransformationForID(transformationID);
2828
+ return caller[functionName](innerPath, ...args);
2829
+ };
2830
+
2831
+ focus: () => boolean = () => {
2832
+ // Just focus the first showing input
2833
+ const inputs = this.getInputPaths();
2834
+ if (inputs.length > 0) {
2835
+ this.focusInputPath(inputs[0]);
2836
+ return true;
2837
+ }
2838
+ return false;
2839
+ };
2840
+
2841
+ focusInputPath: (arg1: Path) => boolean = (path) => {
2842
+ // Since the transformer exposes the input API, it needs to be robust
2843
+ // to empty paths. We don't expect this to happen, as entire-widget
2844
+ // focusing is typically done through the focus() method, which already
2845
+ // handles the empty path case properly, but it's better to be safe
2846
+ // here.
2847
+ if (path.length === 0) {
2848
+ return false;
2849
+ }
2850
+
2851
+ assert(path.length >= 2);
2852
+ return this._passToInner("focusInputPath", path);
2853
+ };
2854
+
2855
+ blurInputPath: (arg1: Path) => boolean = (path) => {
2856
+ // Since the transformer exposes the input API, it needs to be robust
2857
+ // to empty paths (which indicate a blurring of the entire widget,
2858
+ // e.g., when switching from interacting with the transformer to
2859
+ // interacting with some other widget).
2860
+ if (path.length === 0) {
2861
+ return false;
2862
+ }
2863
+
2864
+ assert(path.length >= 2);
2865
+ return this._passToInner("blurInputPath", path);
2866
+ };
2867
+
2868
+ setInputValue: (
2869
+ arg1: Path,
2870
+ arg2: any,
2871
+ arg3: (arg1: any) => unknown,
2872
+ ) => any = (path, value, cb) => {
2873
+ assert(path.length >= 2);
2874
+ return this._passToInner("setInputValue", path, value, cb);
2875
+ };
2876
+
2877
+ getDOMNodeForPath: (arg1: Path) => any = (path) => {
2878
+ assert(path.length >= 2);
2879
+ return this._passToInner("getDOMNodeForPath", path);
2880
+ };
2881
+
2882
+ getGrammarTypeForPath: (arg1: Path) => any = (path) => {
2883
+ assert(path.length >= 2);
2884
+ return this._passToInner("getGrammarTypeForPath", path);
2885
+ };
2886
+
2887
+ static validate(guess: UserInput, rubric: Rubric): PerseusScore {
2888
+ // Check for any required transformations
2889
+ for (const type in Transformations) {
2890
+ if (rubric.tools[type].required) {
2891
+ const isUsed = _.any(
2892
+ _.map(guess.transformations, function (transform) {
2893
+ // Required transformations must appear in the
2894
+ // transformation list, and must not be no-ops
2895
+ return (
2896
+ transform.type === type &&
2897
+ !TransformOps.isEmpty(transform) &&
2898
+ !TransformOps.isNoOp(transform)
2899
+ );
2900
+ }),
2901
+ );
2902
+
2903
+ if (!isUsed) {
2904
+ return {
2905
+ type: "invalid",
2906
+ message: i18n._(
2907
+ "Your transformation must use a " + "%(type)s.",
2908
+ {
2909
+ type: Transformations[type].lowerNounName,
2910
+ },
2911
+ ),
2912
+ };
2913
+ }
2914
+ }
2915
+ }
2916
+
2917
+ // Compare shapes
2918
+ if (ShapeTypes.equal(guess.shape, rubric.correct.shape)) {
2919
+ return {
2920
+ type: "points",
2921
+ earned: 1,
2922
+ total: 1,
2923
+ message: null,
2924
+ };
2925
+ }
2926
+ if (
2927
+ !rubric.gradeEmpty &&
2928
+ deepEq(guess.shape.coords, rubric.starting.shape.coords)
2929
+ ) {
2930
+ return {
2931
+ type: "invalid",
2932
+ message: i18n._(
2933
+ "Use the interactive graph to define a " +
2934
+ "correct transformation.",
2935
+ ),
2936
+ };
2937
+ }
2938
+ return {
2939
+ type: "points",
2940
+ earned: 0,
2941
+ total: 1,
2942
+ message: null,
2943
+ };
2944
+ }
2945
+ }
2946
+
2947
+ export default {
2948
+ name: "transformer",
2949
+ displayName: "Transformer",
2950
+ widget: Transformer,
2951
+ } as WidgetExports<typeof Transformer>;