@khanacademy/perseus 19.1.4 → 19.1.6

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 (487) hide show
  1. package/dist/components/graphie.d.ts +9 -1
  2. package/dist/es/index.js +255 -122
  3. package/dist/es/index.js.map +1 -1
  4. package/dist/index.js +261 -126
  5. package/dist/index.js.map +1 -1
  6. package/dist/interactive2/interactive-util.d.ts +1 -1
  7. package/dist/interactive2/movable-point-options.d.ts +5 -4
  8. package/dist/interactive2/movable.d.ts +90 -13
  9. package/dist/interactive2/types.d.ts +6 -0
  10. package/dist/util/graphie.d.ts +5 -0
  11. package/dist/widgets/expression.d.ts +4 -4
  12. package/package.json +11 -8
  13. package/.babelrc.js +0 -8
  14. package/.eslintrc.js +0 -12
  15. package/CHANGELOG.md +0 -1422
  16. package/src/__stories__/article-renderer.stories.tsx +0 -100
  17. package/src/__stories__/hints-renderer.stories.tsx +0 -55
  18. package/src/__stories__/server-item-renderer.stories.tsx +0 -44
  19. package/src/__testdata__/article-renderer.testdata.ts +0 -212
  20. package/src/__testdata__/graphie.testdata.ts +0 -51
  21. package/src/__testdata__/renderer.testdata.ts +0 -274
  22. package/src/__testdata__/server-item-renderer.testdata.ts +0 -171
  23. package/src/__tests__/__snapshots__/perseus-markdown.test.ts.snap +0 -507
  24. package/src/__tests__/__snapshots__/renderer.test.tsx.snap +0 -525
  25. package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +0 -285
  26. package/src/__tests__/a11y.test.ts +0 -303
  27. package/src/__tests__/article-renderer.test.tsx +0 -130
  28. package/src/__tests__/error-boundary.test.tsx +0 -76
  29. package/src/__tests__/extract-perseus-data.test.ts +0 -1027
  30. package/src/__tests__/init.test.ts +0 -10
  31. package/src/__tests__/jipt-paragraphs.test.ts +0 -32
  32. package/src/__tests__/mock-asset-loading-widget.tsx +0 -53
  33. package/src/__tests__/mock-widget.tsx +0 -33
  34. package/src/__tests__/perseus-markdown.test.ts +0 -764
  35. package/src/__tests__/renderability.test.ts +0 -480
  36. package/src/__tests__/renderer-api.test.tsx +0 -302
  37. package/src/__tests__/renderer.test.tsx +0 -1816
  38. package/src/__tests__/server-item-renderer.test.tsx +0 -582
  39. package/src/__tests__/test-items/image-item.ts +0 -24
  40. package/src/__tests__/test-items/input-number-1-item.ts +0 -26
  41. package/src/__tests__/test-items/input-number-2-item.ts +0 -38
  42. package/src/__tests__/test-items/table-item.ts +0 -29
  43. package/src/__tests__/tex-wrangler.test.ts +0 -82
  44. package/src/__tests__/util.test.ts +0 -40
  45. package/src/__tests__/widget-container.test.tsx +0 -126
  46. package/src/__tests__/widgets.test.ts +0 -91
  47. package/src/a11y.ts +0 -45
  48. package/src/all-widgets.ts +0 -9
  49. package/src/article-renderer.tsx +0 -237
  50. package/src/asset-context.ts +0 -30
  51. package/src/basic-widgets.ts +0 -16
  52. package/src/components/__stories__/button-group.stories.tsx +0 -55
  53. package/src/components/__stories__/fixed-to-responsive.stories.tsx +0 -141
  54. package/src/components/__stories__/graph.stories.tsx +0 -28
  55. package/src/components/__stories__/graphie.stories.tsx +0 -33
  56. package/src/components/__stories__/hud.stories.tsx +0 -35
  57. package/src/components/__stories__/icon.stories.tsx +0 -63
  58. package/src/components/__stories__/image-loader.stories.tsx +0 -63
  59. package/src/components/__stories__/info-tip.stories.tsx +0 -31
  60. package/src/components/__stories__/inline-icon.stories.tsx +0 -40
  61. package/src/components/__stories__/input-with-examples.stories.tsx +0 -53
  62. package/src/components/__stories__/lint.stories.tsx +0 -86
  63. package/src/components/__stories__/math-input.stories.tsx +0 -43
  64. package/src/components/__stories__/math-output.stories.tsx +0 -23
  65. package/src/components/__stories__/multi-button-group.stories.tsx +0 -66
  66. package/src/components/__stories__/number-input.stories.tsx +0 -41
  67. package/src/components/__stories__/prop-check-box.stories.tsx +0 -65
  68. package/src/components/__stories__/range-input.stories.tsx +0 -29
  69. package/src/components/__stories__/simple-keypad-input.stories.tsx +0 -27
  70. package/src/components/__stories__/sortable.stories.tsx +0 -77
  71. package/src/components/__stories__/stub-tag-editor.stories.tsx +0 -45
  72. package/src/components/__stories__/svg-image.stories.tsx +0 -74
  73. package/src/components/__stories__/tex.stories.tsx +0 -23
  74. package/src/components/__stories__/text-input.stories.tsx +0 -33
  75. package/src/components/__stories__/text-list-editor.stories.tsx +0 -32
  76. package/src/components/__stories__/tooltip.stories.tsx +0 -52
  77. package/src/components/__stories__/zoomable-tex.stories.tsx +0 -41
  78. package/src/components/__stories__/zoomable.stories.tsx +0 -49
  79. package/src/components/__testdata__/sorter.testdata.ts +0 -19
  80. package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +0 -163
  81. package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +0 -265
  82. package/src/components/__tests__/math-input.test.tsx +0 -147
  83. package/src/components/__tests__/number-input.test.tsx +0 -128
  84. package/src/components/__tests__/sortable.test.tsx +0 -269
  85. package/src/components/__tests__/sorter.test.tsx +0 -114
  86. package/src/components/__tests__/zoomable.test.tsx +0 -399
  87. package/src/components/button-group.tsx +0 -130
  88. package/src/components/constants.ts +0 -14
  89. package/src/components/fixed-to-responsive.tsx +0 -169
  90. package/src/components/graph.tsx +0 -444
  91. package/src/components/graphie-classes.ts +0 -153
  92. package/src/components/graphie-movables.ts +0 -338
  93. package/src/components/graphie.tsx +0 -392
  94. package/src/components/highlighting/highlightable-content.tsx +0 -240
  95. package/src/components/highlighting/highlights.ts +0 -207
  96. package/src/components/highlighting/ranges.ts +0 -304
  97. package/src/components/highlighting/types.ts +0 -73
  98. package/src/components/highlighting/ui/highlight-renderer.tsx +0 -172
  99. package/src/components/highlighting/ui/highlight-set-renderer.tsx +0 -185
  100. package/src/components/highlighting/ui/highlight-tooltip.tsx +0 -141
  101. package/src/components/highlighting/ui/highlighting-ui.tsx +0 -143
  102. package/src/components/highlighting/ui/selection-tracker.tsx +0 -186
  103. package/src/components/highlighting/ui/types.ts +0 -21
  104. package/src/components/highlighting/ui/util.ts +0 -165
  105. package/src/components/highlighting/word-indexer.tsx +0 -152
  106. package/src/components/hud.tsx +0 -167
  107. package/src/components/icon.tsx +0 -141
  108. package/src/components/image-loader.tsx +0 -177
  109. package/src/components/info-tip/info-tip.tsx +0 -144
  110. package/src/components/info-tip.tsx +0 -39
  111. package/src/components/inline-icon.tsx +0 -60
  112. package/src/components/input-with-examples.tsx +0 -249
  113. package/src/components/lint.tsx +0 -459
  114. package/src/components/math-input.tsx +0 -474
  115. package/src/components/math-output.tsx +0 -134
  116. package/src/components/multi-button-group.tsx +0 -135
  117. package/src/components/number-input.tsx +0 -249
  118. package/src/components/prop-check-box.tsx +0 -79
  119. package/src/components/range-input.tsx +0 -60
  120. package/src/components/simple-keypad-input.tsx +0 -88
  121. package/src/components/sortable.tsx +0 -958
  122. package/src/components/stub-tag-editor.tsx +0 -53
  123. package/src/components/svg-image.tsx +0 -779
  124. package/src/components/tex.tsx +0 -67
  125. package/src/components/text-input.tsx +0 -129
  126. package/src/components/text-list-editor.tsx +0 -166
  127. package/src/components/tooltip.tsx +0 -410
  128. package/src/components/visibility-observer/__stories__/visibility-observer.stories.tsx +0 -141
  129. package/src/components/visibility-observer/create-visibility-observer.ts +0 -108
  130. package/src/components/visibility-observer/get-scroll-parent.ts +0 -46
  131. package/src/components/visibility-observer/visibility-observer.tsx +0 -124
  132. package/src/components/zoomable-tex.tsx +0 -78
  133. package/src/components/zoomable.tsx +0 -304
  134. package/src/components.ts +0 -15
  135. package/src/definition-context.tsx +0 -59
  136. package/src/dependencies.ts +0 -40
  137. package/src/error-boundary.tsx +0 -70
  138. package/src/extra-widgets.ts +0 -75
  139. package/src/hint-renderer.tsx +0 -151
  140. package/src/hints-renderer.tsx +0 -372
  141. package/src/icon-paths.ts +0 -119
  142. package/src/index.ts +0 -171
  143. package/src/init.ts +0 -56
  144. package/src/interaction-tracker.ts +0 -62
  145. package/src/interactive2/__tests__/movable-mock.ts +0 -43
  146. package/src/interactive2/__tests__/movable-point.test.ts +0 -144
  147. package/src/interactive2/__tests__/movable.test.ts +0 -157
  148. package/src/interactive2/interactive-util.test.ts +0 -93
  149. package/src/interactive2/interactive-util.ts +0 -159
  150. package/src/interactive2/movable-helper-methods.ts +0 -166
  151. package/src/interactive2/movable-line-options.ts +0 -419
  152. package/src/interactive2/movable-line.ts +0 -307
  153. package/src/interactive2/movable-point-options.ts +0 -212
  154. package/src/interactive2/movable-point.tsx +0 -585
  155. package/src/interactive2/movable-polygon-options.ts +0 -389
  156. package/src/interactive2/movable-polygon.ts +0 -360
  157. package/src/interactive2/movable.ts +0 -279
  158. package/src/interactive2/objective_.ts +0 -79
  159. package/src/interactive2/types.ts +0 -2
  160. package/src/interactive2/wrapped-defaults.ts +0 -87
  161. package/src/interactive2/wrapped-ellipse.ts +0 -94
  162. package/src/interactive2/wrapped-line.ts +0 -116
  163. package/src/interactive2/wrapped-path.ts +0 -51
  164. package/src/interactive2.ts +0 -70
  165. package/src/item-version.ts +0 -10
  166. package/src/jipt-paragraphs.ts +0 -49
  167. package/src/jquery.mobile.vmouse.js +0 -545
  168. package/src/loading-context.ts +0 -21
  169. package/src/logging/log.test.ts +0 -39
  170. package/src/logging/log.ts +0 -97
  171. package/src/mixins/__tests__/widget-prop-denylist.test.ts +0 -21
  172. package/src/mixins/changeable.ts +0 -133
  173. package/src/mixins/editor-jsonify.ts +0 -13
  174. package/src/mixins/widget-jsonify-deprecated.ts +0 -23
  175. package/src/mixins/widget-prop-denylist.ts +0 -48
  176. package/src/multi-items/__stories__/multi-renderer.stories.tsx +0 -83
  177. package/src/multi-items/__testdata__/multi-renderer.testdata.ts +0 -172
  178. package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +0 -1164
  179. package/src/multi-items/__tests__/items.test.ts +0 -240
  180. package/src/multi-items/__tests__/multi-renderer.test.tsx +0 -914
  181. package/src/multi-items/__tests__/prop-type-builders.test.ts +0 -133
  182. package/src/multi-items/__tests__/shapes.test.ts +0 -43
  183. package/src/multi-items/__tests__/trees.test.ts +0 -317
  184. package/src/multi-items/item-types.ts +0 -56
  185. package/src/multi-items/items.ts +0 -176
  186. package/src/multi-items/multi-renderer.tsx +0 -569
  187. package/src/multi-items/prop-type-builders.ts +0 -106
  188. package/src/multi-items/shape-types.ts +0 -52
  189. package/src/multi-items/shapes.ts +0 -52
  190. package/src/multi-items/tree-types.ts +0 -47
  191. package/src/multi-items/trees.ts +0 -360
  192. package/src/multi-items.ts +0 -75
  193. package/src/perseus-api.tsx +0 -188
  194. package/src/perseus-env.ts +0 -27
  195. package/src/perseus-error.ts +0 -17
  196. package/src/perseus-markdown.tsx +0 -405
  197. package/src/perseus-types.ts +0 -1366
  198. package/src/perseus-version.ts +0 -9
  199. package/src/question-paragraph.tsx +0 -34
  200. package/src/renderability.ts +0 -109
  201. package/src/renderer.tsx +0 -2000
  202. package/src/server-item-renderer.tsx +0 -495
  203. package/src/sigfigs.ts +0 -490
  204. package/src/styles/articles.less +0 -749
  205. package/src/styles/constants.ts +0 -94
  206. package/src/styles/global-constants.ts +0 -343
  207. package/src/styles/global-styles.ts +0 -306
  208. package/src/styles/khan-exercise.css +0 -1468
  209. package/src/styles/media-queries.ts +0 -47
  210. package/src/styles/perseus-renderer.less +0 -732
  211. package/src/styles/shared.ts +0 -130
  212. package/src/styles/util.less +0 -47
  213. package/src/styles/variables.boostrap.less +0 -277
  214. package/src/styles/variables.less +0 -56
  215. package/src/styles/variables.shared.less +0 -340
  216. package/src/styles/widgets/categorizer.less +0 -38
  217. package/src/styles/widgets/dropdown.less +0 -3
  218. package/src/styles/widgets/expression.less +0 -65
  219. package/src/styles/widgets/graded-group.less +0 -36
  220. package/src/styles/widgets/grapher.less +0 -12
  221. package/src/styles/widgets/group.less +0 -19
  222. package/src/styles/widgets/image.less +0 -54
  223. package/src/styles/widgets/interactive-graph.less +0 -64
  224. package/src/styles/widgets/label-image.less +0 -57
  225. package/src/styles/widgets/matcher.less +0 -8
  226. package/src/styles/widgets/matrix.less +0 -126
  227. package/src/styles/widgets/measurer.less +0 -20
  228. package/src/styles/widgets/orderer.less +0 -98
  229. package/src/styles/widgets/passage.less +0 -154
  230. package/src/styles/widgets/plotter.less +0 -31
  231. package/src/styles/widgets/radio.less +0 -58
  232. package/src/styles/widgets/reaction-diagram.less +0 -35
  233. package/src/styles/widgets/sequence.less +0 -5
  234. package/src/styles/widgets/sortable.less +0 -113
  235. package/src/styles/widgets/table.less +0 -57
  236. package/src/styles/widgets/unit.less +0 -15
  237. package/src/tex-wrangler.ts +0 -182
  238. package/src/translation-linter.ts +0 -126
  239. package/src/traversal.ts +0 -138
  240. package/src/types.ts +0 -513
  241. package/src/util/a11y.ts +0 -23
  242. package/src/util/answer-types.test.ts +0 -114
  243. package/src/util/answer-types.ts +0 -876
  244. package/src/util/colors.ts +0 -93
  245. package/src/util/drawing-transform.test.ts +0 -67
  246. package/src/util/drawing-transform.ts +0 -102
  247. package/src/util/extract-perseus-data.ts +0 -539
  248. package/src/util/fix-passage-refs.ts +0 -121
  249. package/src/util/geometry.test.ts +0 -75
  250. package/src/util/geometry.ts +0 -312
  251. package/src/util/graph-bounds.ts +0 -23
  252. package/src/util/graph-utils.ts +0 -15
  253. package/src/util/graphie.test.ts +0 -1277
  254. package/src/util/graphie.ts +0 -1566
  255. package/src/util/interactive.ts +0 -4172
  256. package/src/util/interval.ts +0 -4
  257. package/src/util/katex-preprocess.ts +0 -14
  258. package/src/util/math.test.ts +0 -11
  259. package/src/util/math.ts +0 -294
  260. package/src/util/mobile-native-utils.test.ts +0 -22
  261. package/src/util/mobile-native-utils.ts +0 -12
  262. package/src/util/parse-perseus-json.test.ts +0 -10
  263. package/src/util/parse-perseus-json.ts +0 -13
  264. package/src/util/react-render.tsx +0 -27
  265. package/src/util/register-all-widgets-for-testing.ts +0 -13
  266. package/src/util/scroll-utils.ts +0 -155
  267. package/src/util/sizing-utils.ts +0 -46
  268. package/src/util/tex.ts +0 -73
  269. package/src/util/url-utils.ts +0 -34
  270. package/src/util.graphie.test.ts +0 -45
  271. package/src/util.graphie.ts +0 -59
  272. package/src/util.ts +0 -966
  273. package/src/version.ts +0 -10
  274. package/src/widget-container.tsx +0 -199
  275. package/src/widgets/__stories__/categorizer.stories.tsx +0 -14
  276. package/src/widgets/__stories__/cs-program.stories.tsx +0 -14
  277. package/src/widgets/__stories__/definition.stories.tsx +0 -114
  278. package/src/widgets/__stories__/dropdown.stories.tsx +0 -14
  279. package/src/widgets/__stories__/explanation.stories.tsx +0 -18
  280. package/src/widgets/__stories__/expression.stories.tsx +0 -145
  281. package/src/widgets/__stories__/graded-group-set.stories.tsx +0 -31
  282. package/src/widgets/__stories__/graded-group.stories.tsx +0 -31
  283. package/src/widgets/__stories__/grapher.stories.tsx +0 -46
  284. package/src/widgets/__stories__/group.stories.tsx +0 -14
  285. package/src/widgets/__stories__/iframe.stories.tsx +0 -14
  286. package/src/widgets/__stories__/image.stories.tsx +0 -85
  287. package/src/widgets/__stories__/input-number.stories.tsx +0 -101
  288. package/src/widgets/__stories__/interaction.stories.tsx +0 -14
  289. package/src/widgets/__stories__/interactive-graph.stories.tsx +0 -60
  290. package/src/widgets/__stories__/label-image.stories.tsx +0 -130
  291. package/src/widgets/__stories__/matcher.stories.tsx +0 -14
  292. package/src/widgets/__stories__/matrix.stories.tsx +0 -14
  293. package/src/widgets/__stories__/number-line.stories.tsx +0 -14
  294. package/src/widgets/__stories__/numeric-input.stories.tsx +0 -105
  295. package/src/widgets/__stories__/orderer.stories.tsx +0 -18
  296. package/src/widgets/__stories__/passage-ref.stories.tsx +0 -33
  297. package/src/widgets/__stories__/passage.stories.tsx +0 -39
  298. package/src/widgets/__stories__/plotter.stories.tsx +0 -27
  299. package/src/widgets/__stories__/radio.stories.tsx +0 -86
  300. package/src/widgets/__stories__/random-widgets.stories.tsx +0 -59
  301. package/src/widgets/__stories__/sorter.stories.tsx +0 -14
  302. package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +0 -66
  303. package/src/widgets/__stories__/unit.stories.tsx +0 -28
  304. package/src/widgets/__stories__/video-transcript-link.stories.tsx +0 -23
  305. package/src/widgets/__stories__/video.stories.tsx +0 -22
  306. package/src/widgets/__testdata__/base-radio.testdata.ts +0 -21
  307. package/src/widgets/__testdata__/categorizer.testdata.ts +0 -89
  308. package/src/widgets/__testdata__/cs-program.testdata.ts +0 -27
  309. package/src/widgets/__testdata__/dropdown.testdata.ts +0 -71
  310. package/src/widgets/__testdata__/explanation.testdata.ts +0 -85
  311. package/src/widgets/__testdata__/expression.testdata.ts +0 -198
  312. package/src/widgets/__testdata__/graded-group-set.testdata.ts +0 -356
  313. package/src/widgets/__testdata__/graded-group.testdata.ts +0 -77
  314. package/src/widgets/__testdata__/grapher.testdata.ts +0 -374
  315. package/src/widgets/__testdata__/group.testdata.ts +0 -153
  316. package/src/widgets/__testdata__/iframe.testdata.ts +0 -35
  317. package/src/widgets/__testdata__/image.testdata.ts +0 -36
  318. package/src/widgets/__testdata__/input-number.testdata.ts +0 -72
  319. package/src/widgets/__testdata__/interaction.testdata.ts +0 -262
  320. package/src/widgets/__testdata__/interactive-graph-random.testdata.ts +0 -269
  321. package/src/widgets/__testdata__/interactive-graph.testdata.ts +0 -644
  322. package/src/widgets/__testdata__/label-image.testdata.ts +0 -308
  323. package/src/widgets/__testdata__/matcher.testdata.ts +0 -33
  324. package/src/widgets/__testdata__/matrix.testdata.ts +0 -28
  325. package/src/widgets/__testdata__/number-line.testdata.ts +0 -30
  326. package/src/widgets/__testdata__/numeric-input.testdata.ts +0 -265
  327. package/src/widgets/__testdata__/orderer.testdata.ts +0 -123
  328. package/src/widgets/__testdata__/passage-ref.testdata.ts +0 -101
  329. package/src/widgets/__testdata__/passage.testdata.ts +0 -95
  330. package/src/widgets/__testdata__/plotter.testdata.ts +0 -36
  331. package/src/widgets/__testdata__/radio.testdata.ts +0 -324
  332. package/src/widgets/__testdata__/randomizers.ts +0 -51
  333. package/src/widgets/__testdata__/sorter.testdata.ts +0 -19
  334. package/src/widgets/__testdata__/video.testdata.ts +0 -61
  335. package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +0 -940
  336. package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +0 -67
  337. package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +0 -97
  338. package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +0 -133
  339. package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +0 -425
  340. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +0 -729
  341. package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +0 -339
  342. package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +0 -801
  343. package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +0 -2673
  344. package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +0 -1211
  345. package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +0 -61
  346. package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +0 -378
  347. package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +0 -495
  348. package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +0 -292
  349. package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +0 -2889
  350. package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +0 -883
  351. package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +0 -514
  352. package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +0 -814
  353. package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +0 -470
  354. package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +0 -243
  355. package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +0 -434
  356. package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +0 -1956
  357. package/src/widgets/__tests__/__snapshots__/plotter.test.tsx.snap +0 -827
  358. package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +0 -4237
  359. package/src/widgets/__tests__/__snapshots__/unit.test.tsx.snap +0 -20
  360. package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +0 -153
  361. package/src/widgets/__tests__/categorizer.test.ts +0 -203
  362. package/src/widgets/__tests__/cs-program.test.ts +0 -43
  363. package/src/widgets/__tests__/definition.test.ts +0 -136
  364. package/src/widgets/__tests__/dropdown.test.ts +0 -105
  365. package/src/widgets/__tests__/explanation.test.ts +0 -198
  366. package/src/widgets/__tests__/expression-mobile.test.tsx +0 -363
  367. package/src/widgets/__tests__/expression.test.tsx +0 -484
  368. package/src/widgets/__tests__/graded-group-set-jipt.test.ts +0 -30
  369. package/src/widgets/__tests__/graded-group-set.test.ts +0 -288
  370. package/src/widgets/__tests__/graded-group.test.ts +0 -232
  371. package/src/widgets/__tests__/grapher.cypress.ts +0 -576
  372. package/src/widgets/__tests__/grapher.test.ts +0 -33
  373. package/src/widgets/__tests__/group.test.tsx +0 -510
  374. package/src/widgets/__tests__/iframe.test.ts +0 -45
  375. package/src/widgets/__tests__/image.test.ts +0 -62
  376. package/src/widgets/__tests__/input-number.test.ts +0 -354
  377. package/src/widgets/__tests__/interaction.test.ts +0 -31
  378. package/src/widgets/__tests__/interactive-graph.cypress.ts +0 -815
  379. package/src/widgets/__tests__/interactive-graph.test.ts +0 -106
  380. package/src/widgets/__tests__/matcher.test.tsx +0 -176
  381. package/src/widgets/__tests__/matrix.test.ts +0 -82
  382. package/src/widgets/__tests__/number-line.test.ts +0 -79
  383. package/src/widgets/__tests__/numeric-input.test.ts +0 -575
  384. package/src/widgets/__tests__/orderer.test.ts +0 -73
  385. package/src/widgets/__tests__/passage-ref.test.ts +0 -168
  386. package/src/widgets/__tests__/passage.test.tsx +0 -224
  387. package/src/widgets/__tests__/plotter.test.tsx +0 -69
  388. package/src/widgets/__tests__/radio/base-radio.test.tsx +0 -470
  389. package/src/widgets/__tests__/radio/choice-icon.test.tsx +0 -90
  390. package/src/widgets/__tests__/radio/choice.test.tsx +0 -310
  391. package/src/widgets/__tests__/radio/focus-ring.test.tsx +0 -22
  392. package/src/widgets/__tests__/radio/option-status.test.tsx +0 -77
  393. package/src/widgets/__tests__/radio.test.ts +0 -807
  394. package/src/widgets/__tests__/randomizers.test.ts +0 -53
  395. package/src/widgets/__tests__/renderQuestion.tsx +0 -101
  396. package/src/widgets/__tests__/unit.test.tsx +0 -168
  397. package/src/widgets/__tests__/video.test.ts +0 -69
  398. package/src/widgets/categorizer.tsx +0 -344
  399. package/src/widgets/cs-program.tsx +0 -227
  400. package/src/widgets/definition.tsx +0 -121
  401. package/src/widgets/deprecated-standin/__stories__/deprecated-standin.stories.tsx +0 -30
  402. package/src/widgets/deprecated-standin/__tests__/__snapshots__/deprecated-standin.test.ts.snap +0 -70
  403. package/src/widgets/deprecated-standin/__tests__/deprecated-standin.test.ts +0 -93
  404. package/src/widgets/deprecated-standin/index.tsx +0 -58
  405. package/src/widgets/dropdown.tsx +0 -142
  406. package/src/widgets/explanation.tsx +0 -317
  407. package/src/widgets/expression.tsx +0 -707
  408. package/src/widgets/graded-group-answer-bar.tsx +0 -142
  409. package/src/widgets/graded-group-set.tsx +0 -338
  410. package/src/widgets/graded-group.tsx +0 -471
  411. package/src/widgets/grapher/util.tsx +0 -799
  412. package/src/widgets/grapher.tsx +0 -660
  413. package/src/widgets/group.tsx +0 -195
  414. package/src/widgets/iframe.tsx +0 -195
  415. package/src/widgets/image.tsx +0 -312
  416. package/src/widgets/input-number.tsx +0 -412
  417. package/src/widgets/interaction/arrow-picker.tsx +0 -38
  418. package/src/widgets/interaction/color-picker.tsx +0 -69
  419. package/src/widgets/interaction/dash-picker.tsx +0 -45
  420. package/src/widgets/interaction/element-container.tsx +0 -100
  421. package/src/widgets/interaction.tsx +0 -826
  422. package/src/widgets/interactive-graph.tsx +0 -2597
  423. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -91
  424. package/src/widgets/label-image/__stories__/answer-pill.stories.tsx +0 -62
  425. package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -171
  426. package/src/widgets/label-image/__tests__/answer-pill.test.tsx +0 -75
  427. package/src/widgets/label-image/__tests__/hide-answers-toggle.test.tsx +0 -39
  428. package/src/widgets/label-image/answer-choices.tsx +0 -88
  429. package/src/widgets/label-image/answer-pill.tsx +0 -103
  430. package/src/widgets/label-image/hide-answers-toggle.tsx +0 -40
  431. package/src/widgets/label-image/marker.tsx +0 -268
  432. package/src/widgets/label-image/strings.ts +0 -5
  433. package/src/widgets/label-image/types.ts +0 -27
  434. package/src/widgets/label-image.test.ts +0 -928
  435. package/src/widgets/label-image.tsx +0 -819
  436. package/src/widgets/lights-puzzle.tsx +0 -359
  437. package/src/widgets/matcher.tsx +0 -298
  438. package/src/widgets/matrix.tsx +0 -634
  439. package/src/widgets/measurer.tsx +0 -222
  440. package/src/widgets/molecule/__tests__/layout.test.ts +0 -162
  441. package/src/widgets/molecule/__tests__/parser.test.ts +0 -155
  442. package/src/widgets/molecule/molecule-drawing.ts +0 -173
  443. package/src/widgets/molecule/molecule-layout.ts +0 -362
  444. package/src/widgets/molecule/smiles-parser.ts +0 -296
  445. package/src/widgets/molecule.tsx +0 -172
  446. package/src/widgets/number-line.tsx +0 -862
  447. package/src/widgets/numeric-input.tsx +0 -576
  448. package/src/widgets/orderer.tsx +0 -786
  449. package/src/widgets/passage/__tests__/passage-markdown.test.ts +0 -376
  450. package/src/widgets/passage/passage-markdown.tsx +0 -475
  451. package/src/widgets/passage-ref-target.tsx +0 -76
  452. package/src/widgets/passage-ref.tsx +0 -213
  453. package/src/widgets/passage.tsx +0 -582
  454. package/src/widgets/plotter.tsx +0 -1194
  455. package/src/widgets/radio/__stories__/base-radio.stories.tsx +0 -196
  456. package/src/widgets/radio/__stories__/choice-icon.stories.tsx +0 -166
  457. package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +0 -40
  458. package/src/widgets/radio/__stories__/choice.stories.tsx +0 -137
  459. package/src/widgets/radio/__stories__/focus-ring.stories.tsx +0 -43
  460. package/src/widgets/radio/__stories__/option-status.stories.tsx +0 -103
  461. package/src/widgets/radio/base-radio.tsx +0 -511
  462. package/src/widgets/radio/choice-a11y-text.ts +0 -61
  463. package/src/widgets/radio/choice-icon/choice-icon.tsx +0 -218
  464. package/src/widgets/radio/choice-icon/cross-out-line.tsx +0 -51
  465. package/src/widgets/radio/choice-icon/shared-styles.ts +0 -15
  466. package/src/widgets/radio/choice-none-above.tsx +0 -56
  467. package/src/widgets/radio/choice.jsx.fixture.ts +0 -45
  468. package/src/widgets/radio/choice.tsx +0 -359
  469. package/src/widgets/radio/focus-ring.tsx +0 -57
  470. package/src/widgets/radio/option-status.tsx +0 -98
  471. package/src/widgets/radio/util.test.ts +0 -18
  472. package/src/widgets/radio/util.ts +0 -31
  473. package/src/widgets/radio/widget.tsx +0 -520
  474. package/src/widgets/radio.ts +0 -157
  475. package/src/widgets/reaction-diagram.tsx +0 -144
  476. package/src/widgets/sequence.tsx +0 -142
  477. package/src/widgets/simulator.tsx +0 -829
  478. package/src/widgets/sorter.tsx +0 -155
  479. package/src/widgets/table.tsx +0 -393
  480. package/src/widgets/unit.tsx +0 -374
  481. package/src/widgets/video-transcript-link.test.tsx +0 -213
  482. package/src/widgets/video-transcript-link.tsx +0 -84
  483. package/src/widgets/video.tsx +0 -135
  484. package/src/widgets.ts +0 -489
  485. package/src/zoom.ts +0 -555
  486. package/tsconfig-build.json +0 -26
  487. package/tsconfig-build.tsbuildinfo +0 -1
package/src/util.ts DELETED
@@ -1,966 +0,0 @@
1
- /* eslint-disable @babel/no-invalid-this, getter-return, one-var */
2
- import _ from "underscore";
3
-
4
- import {Errors} from "./logging/log";
5
- import {PerseusError} from "./perseus-error";
6
- import KhanAnswerTypes from "./util/answer-types";
7
- import * as GraphieUtil from "./util.graphie";
8
-
9
- import type {Range} from "./perseus-types";
10
- import type {Widget, PerseusScore} from "./types";
11
- import type {KEScore} from "@khanacademy/perseus-core";
12
-
13
- type WordPosition = {
14
- start: number;
15
- end: number;
16
- };
17
-
18
- type WordAndPosition = {
19
- string: string;
20
- pos: WordPosition;
21
- };
22
-
23
- type RNG = () => number;
24
-
25
- export type ParsedValue = {
26
- value: number;
27
- exact: boolean;
28
- };
29
-
30
- // TODO: dedupe this with Coord in interactive2/types.js
31
- type Coordinates = [number, number];
32
-
33
- export type GridDimensions = {
34
- scale: number;
35
- tickStep: number;
36
- unityLabel: boolean;
37
- };
38
-
39
- type QueryParams = {
40
- [param: string]: string;
41
- };
42
-
43
- export type Position = {
44
- top: number;
45
- left: number;
46
- };
47
-
48
- type TouchHandlers = {
49
- pointerDown: boolean;
50
- currentTouchIdentifier: string | null | undefined;
51
- };
52
-
53
- let supportsPassive = false;
54
-
55
- const nestedMap = function <T, M>(
56
- children: T | ReadonlyArray<T>,
57
- func: (arg1: T) => M,
58
- context: unknown,
59
- ): M | ReadonlyArray<M> {
60
- if (Array.isArray(children)) {
61
- // @ts-expect-error - TS2322 - Type '(M | readonly M[])[]' is not assignable to type 'M | readonly M[]'.
62
- return _.map(children, function (child) {
63
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 2.
64
- return nestedMap(child, func);
65
- });
66
- }
67
- return func.call(context, children);
68
- };
69
-
70
- /**
71
- * Used to compare equality of two input paths, which are represented as
72
- * arrays of strings.
73
- */
74
- function inputPathsEqual(
75
- a?: ReadonlyArray<string> | null,
76
- b?: ReadonlyArray<string> | null,
77
- ): boolean {
78
- if (a == null || b == null) {
79
- return (a == null) === (b == null);
80
- }
81
-
82
- return (
83
- a.length === b.length &&
84
- a.every((item, index) => {
85
- return b[index] === item;
86
- })
87
- );
88
- }
89
-
90
- const rWidgetRule = /^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;
91
- const rTypeFromWidgetId = /^([a-z-]+) ([0-9]+)$/;
92
-
93
- const rWidgetParts = new RegExp(rWidgetRule.source + "$");
94
- const snowman = "\u2603";
95
- const noScore: PerseusScore = {
96
- type: "points",
97
- earned: 0,
98
- total: 0,
99
- message: null,
100
- };
101
-
102
- const seededRNG: (seed: number) => RNG = function (seed: number): RNG {
103
- let randomSeed = seed;
104
-
105
- return function () {
106
- // Robert Jenkins' 32 bit integer hash function.
107
- let seed = randomSeed;
108
- seed = (seed + 0x7ed55d16 + (seed << 12)) & 0xffffffff;
109
- seed = (seed ^ 0xc761c23c ^ (seed >>> 19)) & 0xffffffff;
110
- seed = (seed + 0x165667b1 + (seed << 5)) & 0xffffffff;
111
- seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
112
- seed = (seed + 0xfd7046c5 + (seed << 3)) & 0xffffffff;
113
- seed = (seed ^ 0xb55a4f09 ^ (seed >>> 16)) & 0xffffffff;
114
- return (randomSeed = seed & 0xfffffff) / 0x10000000;
115
- };
116
- };
117
-
118
- // Shuffle an array using a given random seed or function.
119
- // If `ensurePermuted` is true, the input and ouput are guaranteed to be
120
- // distinct permutations.
121
- function shuffle<T>(
122
- array: ReadonlyArray<T>,
123
- randomSeed: number | RNG,
124
- ensurePermuted = false,
125
- ): ReadonlyArray<T> {
126
- // Always return a copy of the input array
127
- const shuffled = _.clone(array);
128
-
129
- // Handle edge cases (input array is empty or uniform)
130
- if (
131
- !shuffled.length ||
132
- _.all(shuffled, function (value) {
133
- return _.isEqual(value, shuffled[0]);
134
- })
135
- ) {
136
- return shuffled;
137
- }
138
-
139
- let random;
140
- if (typeof randomSeed === "function") {
141
- random = randomSeed;
142
- } else {
143
- random = seededRNG(randomSeed);
144
- }
145
-
146
- do {
147
- // Fischer-Yates shuffle
148
- for (let top = shuffled.length; top > 0; top--) {
149
- const newEnd = Math.floor(random() * top),
150
- temp = shuffled[newEnd];
151
-
152
- // @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
153
- shuffled[newEnd] = shuffled[top - 1];
154
- // @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
155
- shuffled[top - 1] = temp;
156
- }
157
- } while (ensurePermuted && _.isEqual(array, shuffled));
158
-
159
- return shuffled;
160
- }
161
-
162
- /**
163
- * TODO(somewhatabstract, FEI-3463):
164
- * Drop this custom split thing.
165
- */
166
- // In IE8, split doesn't work right. Implement it ourselves.
167
- const split: (str: string, r: RegExp) => ReadonlyArray<string> = "x".split(
168
- /(.)/g,
169
- ).length
170
- ? function (str: string, r) {
171
- return str.split(r);
172
- }
173
- : function (str: string, r: RegExp) {
174
- // Based on Steven Levithan's MIT-licensed split, available at
175
- // http://blog.stevenlevithan.com/archives/cross-browser-split
176
- const output = [];
177
- let lastIndex = (r.lastIndex = 0);
178
- let match;
179
-
180
- while ((match = r.exec(str))) {
181
- const m = match;
182
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
183
- output.push(str.slice(lastIndex, m.index));
184
- // @ts-expect-error - TS2345 - Argument of type 'any' is not assignable to parameter of type 'never'.
185
- output.push(...m.slice(1));
186
- lastIndex = m.index + m[0].length;
187
- }
188
-
189
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
190
- output.push(str.slice(lastIndex));
191
- return output;
192
- };
193
-
194
- /**
195
- * Combine two score objects.
196
- *
197
- * Given two score objects for two different widgets, combine them so that
198
- * if one is wrong, the total score is wrong, etc.
199
- */
200
- function combineScores(
201
- scoreA: PerseusScore,
202
- scoreB: PerseusScore,
203
- ): PerseusScore {
204
- let message;
205
-
206
- if (scoreA.type === "points" && scoreB.type === "points") {
207
- if (
208
- scoreA.message &&
209
- scoreB.message &&
210
- scoreA.message !== scoreB.message
211
- ) {
212
- // TODO(alpert): Figure out how to combine messages usefully
213
- message = null;
214
- } else {
215
- message = scoreA.message || scoreB.message;
216
- }
217
-
218
- return {
219
- type: "points",
220
- earned: scoreA.earned + scoreB.earned,
221
- total: scoreA.total + scoreB.total,
222
- message: message,
223
- };
224
- }
225
- if (scoreA.type === "points" && scoreB.type === "invalid") {
226
- return scoreB;
227
- }
228
- if (scoreA.type === "invalid" && scoreB.type === "points") {
229
- return scoreA;
230
- }
231
- if (scoreA.type === "invalid" && scoreB.type === "invalid") {
232
- if (
233
- scoreA.message &&
234
- scoreB.message &&
235
- scoreA.message !== scoreB.message
236
- ) {
237
- // TODO(alpert): Figure out how to combine messages usefully
238
- message = null;
239
- } else {
240
- message = scoreA.message || scoreB.message;
241
- }
242
-
243
- return {
244
- type: "invalid",
245
- message: message,
246
- };
247
- }
248
-
249
- /**
250
- * The above checks cover all combinations of score type, so if we get here
251
- * then something is amiss with our inputs.
252
- */
253
- throw new PerseusError(
254
- "PerseusScore with unknown type encountered",
255
- Errors.InvalidInput,
256
- {
257
- metadata: {
258
- scoreA: JSON.stringify(scoreA),
259
- scoreB: JSON.stringify(scoreB),
260
- },
261
- },
262
- );
263
- }
264
-
265
- function keScoreFromPerseusScore(
266
- score: PerseusScore,
267
- guess: any,
268
- state: any,
269
- ): KEScore {
270
- if (score.type === "points") {
271
- return {
272
- empty: false,
273
- correct: score.earned >= score.total,
274
- message: score.message,
275
- guess: guess,
276
- state: state,
277
- };
278
- }
279
- if (score.type === "invalid") {
280
- return {
281
- empty: true,
282
- correct: false,
283
- message: score.message,
284
- suppressAlmostThere: score.suppressAlmostThere,
285
- guess: guess,
286
- state: state,
287
- };
288
- }
289
- throw new PerseusError(
290
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
291
- "Invalid score type: " + score.type,
292
- Errors.InvalidInput,
293
- {
294
- metadata: {
295
- score: JSON.stringify(score),
296
- guess: JSON.stringify(guess),
297
- state: JSON.stringify(state),
298
- },
299
- },
300
- );
301
- }
302
-
303
- /**
304
- * Return the first valid interpretation of 'text' as a number, in the form
305
- * {value: 2.3, exact: true}.
306
- */
307
- function firstNumericalParse(text: string): ParsedValue | null | undefined {
308
- // TODO(alpert): This is sort of hacky...
309
- let first;
310
- const val = KhanAnswerTypes.predicate.createValidatorFunctional(
311
- function (ans) {
312
- first = ans;
313
- return true; /* break */
314
- },
315
- {
316
- simplify: "optional",
317
- inexact: true,
318
- forms: "integer, proper, improper, pi, log, mixed, decimal",
319
- },
320
- );
321
-
322
- val(text);
323
- return first;
324
- }
325
-
326
- function stringArrayOfSize(size: number): ReadonlyArray<string> {
327
- return _(size).times(function () {
328
- return "";
329
- });
330
- }
331
-
332
- /**
333
- * For a graph's x or y dimension, given the tick step,
334
- * the ranges extent (e.g. [-10, 10]), the pixel dimension constraint,
335
- * and the grid step, return a bunch of configurations for that dimension.
336
- *
337
- * Example:
338
- * gridDimensionConfig(10, [-50, 50], 400, 5)
339
- *
340
- * Returns: {
341
- * scale: 4,
342
- * snap: 2.5,
343
- * tickStep: 2,
344
- * unityLabel: true
345
- * };
346
- */
347
- function gridDimensionConfig(
348
- absTickStep: number,
349
- extent: Coordinates,
350
- dimensionConstraint: number,
351
- gridStep: number,
352
- ): GridDimensions {
353
- const scale = scaleFromExtent(extent, dimensionConstraint);
354
- const stepPx = absTickStep * scale;
355
- const unityLabel = stepPx > 30;
356
- return {
357
- scale: scale,
358
- tickStep: absTickStep / gridStep,
359
- unityLabel: unityLabel,
360
- };
361
- }
362
- /**
363
- * Given the range, step, and boxSize, calculate the reasonable gridStep.
364
- * Used for when one was not given explicitly.
365
- *
366
- * Example:
367
- * getGridStep([[-10, 10], [-10, 10]], [1, 1], 340)
368
- *
369
- * Returns: [1, 1]
370
- *
371
- * TODO(somewhatabstract, FEI-3464): Consolidate query string parsing functions.
372
- */
373
- function getGridStep(
374
- range: [Coordinates, Coordinates],
375
- step: Coordinates,
376
- boxSize: number,
377
- ): Coordinates {
378
- // @ts-expect-error - TS2322 - Type '(number | null | undefined)[]' is not assignable to type 'Coordinates'.
379
- return _(2).times(function (i) {
380
- const scale = scaleFromExtent(range[i], boxSize);
381
- const gridStep = gridStepFromTickStep(step[i], scale);
382
- return gridStep;
383
- });
384
- }
385
-
386
- function snapStepFromGridStep(gridStep: [number, number]): [number, number] {
387
- return [gridStep[0] / 2, gridStep[1] / 2];
388
- }
389
-
390
- /**
391
- * Given the tickStep and the graph's scale, find a
392
- * grid step.
393
- * Example:
394
- * gridStepFromTickStep(200, 0.2) // returns 100
395
- */
396
- function gridStepFromTickStep(
397
- tickStep: number,
398
- scale: number,
399
- ): number | null | undefined {
400
- const tickWidth = tickStep * scale;
401
- const x = tickStep;
402
- const y = Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
403
- const leadingDigit = Math.floor(x / y);
404
- if (tickWidth < 25) {
405
- return tickStep;
406
- }
407
- if (tickWidth < 50) {
408
- if (leadingDigit === 5) {
409
- return tickStep;
410
- }
411
- return tickStep / 2;
412
- }
413
- if (leadingDigit === 1) {
414
- return tickStep / 2;
415
- }
416
- if (leadingDigit === 2) {
417
- return tickStep / 4;
418
- }
419
- if (leadingDigit === 5) {
420
- return tickStep / 5;
421
- }
422
- }
423
-
424
- /**
425
- * Given the range and a dimension, come up with the appropriate
426
- * scale.
427
- * Example:
428
- * scaleFromExtent([-25, 25], 500) // returns 10
429
- */
430
- function scaleFromExtent(
431
- extent: Coordinates,
432
- dimensionConstraint: number,
433
- ): number {
434
- const span = extent[1] - extent[0];
435
- const scale = dimensionConstraint / span;
436
- return scale;
437
- }
438
-
439
- /**
440
- * Return a reasonable tick step given extent and dimension.
441
- * (extent is [begin, end] of the domain.)
442
- * Example:
443
- * tickStepFromExtent([-10, 10], 300) // returns 2
444
- */
445
- function tickStepFromExtent(
446
- extent: Coordinates,
447
- dimensionConstraint: number,
448
- ): number {
449
- const span = extent[1] - extent[0];
450
-
451
- let tickFactor;
452
- // If single number digits
453
- if (15 < span && span <= 20) {
454
- tickFactor = 23;
455
-
456
- // triple digit or decimal
457
- } else if (span > 100 || span < 5) {
458
- tickFactor = 10;
459
-
460
- // double digit
461
- } else {
462
- tickFactor = 16;
463
- }
464
- const constraintFactor = dimensionConstraint / 500;
465
- const desiredNumTicks = tickFactor * constraintFactor;
466
- return tickStepFromNumTicks(span, desiredNumTicks);
467
- }
468
-
469
- /**
470
- * Find a good tick step for the desired number of ticks in the range
471
- * Modified from d3.scale.linear: d3_scale_linearTickRange.
472
- * Thanks, mbostock!
473
- * Example:
474
- * tickStepFromNumTicks(50, 6) // returns 10
475
- */
476
- function tickStepFromNumTicks(span: number, numTicks: number): number {
477
- let step = Math.pow(10, Math.floor(Math.log(span / numTicks) / Math.LN10));
478
- const err = (numTicks / span) * step;
479
-
480
- // Filter ticks to get closer to the desired count.
481
- if (err <= 0.15) {
482
- step *= 10;
483
- } else if (err <= 0.35) {
484
- step *= 5;
485
- } else if (err <= 0.75) {
486
- step *= 2;
487
- }
488
-
489
- // Round start and stop values to step interval.
490
- return step;
491
- }
492
-
493
- const constrainTickStep = (step: number, range: Range): number => {
494
- const span = range[1] - range[0];
495
- const numTicks = span / step;
496
- if (numTicks <= 10) {
497
- // Will displays fine on mobile
498
- return step;
499
- }
500
- if (numTicks <= 20) {
501
- // Will be crowded on mobile, so hide every other tick
502
- return step * 2;
503
- }
504
- // Fallback in case we somehow have more than 20 ticks
505
- // Note: This shouldn't happen due to GraphSettings.validStep
506
- return tickStepFromNumTicks(span, 10);
507
- };
508
-
509
- /**
510
- * Constrain tick steps intended for desktop size graphs
511
- * to something more suitable for mobile size graphs.
512
- * Specifically, we aim for 10 or fewer ticks per graph axis.
513
- */
514
- function constrainedTickStepsFromTickSteps(
515
- tickSteps: [number, number],
516
- ranges: [Range, Range],
517
- ): Coordinates {
518
- return [
519
- constrainTickStep(tickSteps[0], ranges[0]),
520
- constrainTickStep(tickSteps[1], ranges[1]),
521
- ];
522
- }
523
-
524
- /**
525
- * Transparently update deprecated props so that the code to deal
526
- * with them only lives in one place: (Widget).deprecatedProps
527
- *
528
- * For example, if a boolean `foo` was deprecated in favor of a
529
- * number 'bar':
530
- * deprecatedProps: {
531
- * foo: function(props) {
532
- * return {bar: props.foo ? 1 : 0};
533
- * }
534
- * }
535
- */
536
- const DeprecationMixin: any = {
537
- // This lifecycle stage is only called before first render
538
- // TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
539
- UNSAFE_componentWillMount: function () {
540
- const newProps: Record<string, any> = {};
541
-
542
- _.each(
543
- this.deprecatedProps,
544
- function (func, prop) {
545
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
546
- if (_.has(this.props, prop)) {
547
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
548
- _.extend(newProps, func(this.props));
549
- }
550
- },
551
- this,
552
- );
553
-
554
- if (!_.isEmpty(newProps)) {
555
- // Set new props directly so that widget renders correctly
556
- // when it first mounts, even though these will be overwritten
557
- // almost immediately afterwards...
558
- _.extend(this.props, newProps);
559
-
560
- // ...when we propagate the new props upwards and they come
561
- // back down again.
562
- // TODO(jeff, CP-3128): Use Wonder Blocks Timing API
563
- // eslint-disable-next-line no-restricted-syntax
564
- setTimeout(this.props.onChange, 0, newProps);
565
- }
566
- },
567
- };
568
-
569
- /**
570
- * Approximate equality on numbers and primitives.
571
- */
572
- function eq<T>(x: T, y: T): boolean {
573
- if (typeof x === "number" && typeof y === "number") {
574
- return Math.abs(x - y) < 1e-9;
575
- }
576
- return x === y;
577
- }
578
-
579
- /**
580
- * Deep approximate equality on primitives, numbers, arrays, and objects.
581
- * Recursive.
582
- */
583
- function deepEq<T>(x: T, y: T): boolean {
584
- if (Array.isArray(x) && Array.isArray(y)) {
585
- if (x.length !== y.length) {
586
- return false;
587
- }
588
- for (let i = 0; i < x.length; i++) {
589
- if (!deepEq(x[i], y[i])) {
590
- return false;
591
- }
592
- }
593
- return true;
594
- }
595
- if (Array.isArray(x) || Array.isArray(y)) {
596
- return false;
597
- }
598
- if (typeof x === "function" && typeof y === "function") {
599
- return eq(x, y);
600
- }
601
- if (typeof x === "function" || typeof y === "function") {
602
- return false;
603
- }
604
- if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
605
- return (
606
- x === y ||
607
- (_.all(x, function (v, k) {
608
- // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
609
- return deepEq(y[k], v);
610
- }) &&
611
- _.all(y, function (v, k) {
612
- // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
613
- return deepEq(x[k], v);
614
- }))
615
- );
616
- }
617
- if ((typeof x === "object" && !!x) || (typeof y === "object" && !!y)) {
618
- return false;
619
- }
620
- return eq(x, y);
621
- }
622
-
623
- /**
624
- * Query String Parser
625
- *
626
- * Original from:
627
- * http://stackoverflow.com/questions/901115/get-querystring-values-in-javascript/2880929#2880929
628
- */
629
- function parseQueryString(query: string): QueryParams {
630
- // TODO(jangmi, CP-3340): Use withLocation to access SSR safe location.
631
- // eslint-disable-next-line no-restricted-syntax
632
- query = query || window.location.search.substring(1);
633
- const urlParams: Record<string, any> = {};
634
- // Regex for replacing addition symbol with a space
635
- const a = /\+/g;
636
- const r = /([^&=]+)=?([^&]*)/g;
637
- const d = function (s) {
638
- return decodeURIComponent(s.replace(a, " "));
639
- };
640
-
641
- let e;
642
- while ((e = r.exec(query))) {
643
- const m = e;
644
- urlParams[d(m[1])] = d(m[2]);
645
- }
646
-
647
- return urlParams;
648
- }
649
-
650
- /**
651
- * Query string adder
652
- * Works for URLs without #.
653
- * Original from:
654
- * http://stackoverflow.com/questions/5999118/add-or-update-query-string-parameter
655
- */
656
- function updateQueryString(uri: string, key: string, value: string): string {
657
- value = encodeURIComponent(value);
658
- const re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
659
- const separator = uri.indexOf("?") !== -1 ? "&" : "?";
660
- if (uri.match(re)) {
661
- return uri.replace(re, "$1" + key + "=" + value + "$2");
662
- }
663
- return uri + separator + key + "=" + value;
664
- }
665
-
666
- /**
667
- * A more strict encodeURIComponent that escapes `()'!`s
668
- * Especially useful for creating URLs that are embeddable in markdown
669
- *
670
- * Adapted from
671
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
672
- * This function and the above original available under the
673
- * CC-BY-SA 2.5 license.
674
- */
675
- function strongEncodeURIComponent(str: string): string {
676
- return (
677
- encodeURIComponent(str)
678
- // Note that although RFC3986 reserves "!", RFC5987 does not,
679
- // so we do not need to escape it
680
- .replace(/['()!]/g, window.escape) // i.e., %27 %28 %29
681
- .replace(/\*/g, "%2A")
682
- );
683
- }
684
-
685
- /**
686
- * TODO(somewhatabstract, JIRA-XXXX):
687
- * This does not appear to be used within webapp. Could be dead code.
688
- * Need to check with mobile.
689
- */
690
- // There are certain widgets where we don't want to provide the "answered"
691
- // highlight indicator.
692
- // The issue with just using the `graded` flag on questions is that showing
693
- // that a certain widget is ungraded can sometimes reveal the answer to a
694
- // question ("is this transformation possible? if so, do it")
695
- // This is kind of a hack to get around this.
696
- function widgetShouldHighlight(widget: Widget): boolean {
697
- if (!widget) {
698
- return false;
699
- }
700
- switch (widget.type) {
701
- /**
702
- * Highlight bar denylist
703
- */
704
- case "measurer":
705
- case "protractor":
706
- return true;
707
-
708
- default:
709
- return false;
710
- }
711
- }
712
-
713
- /**
714
- * If a widget says that it is empty once it is graded.
715
- * Trying to encapsulate references to the score format.
716
- */
717
- function scoreIsEmpty(score: PerseusScore): boolean {
718
- // HACK(benkomalo): ugh. this isn't great; the Perseus score objects
719
- // overload the type "invalid" for what should probably be three
720
- // distinct cases:
721
- // - truly empty or not fully filled out
722
- // - invalid or malformed inputs
723
- // - "almost correct" like inputs where the widget wants to give
724
- // feedback (e.g. a fraction needs to be reduced, or `pi` should
725
- // be used instead of 3.14)
726
- //
727
- // Unfortunately the coercion happens all over the place, as these
728
- // Perseus style score objects are created *everywhere* (basically
729
- // in every widget), so it's hard to change now. We assume that
730
- // anything with a "message" is not truly empty, and one of the
731
- // latter two cases for now.
732
- return (
733
- score.type === "invalid" &&
734
- (!score.message || score.message.length === 0)
735
- );
736
- }
737
-
738
- /*
739
- * The touchHandlers are used to track the current state of the touch
740
- * event, such as whether or not the user is currently pressed down (either
741
- * through touch or mouse) on the screen.
742
- */
743
- const touchHandlers: TouchHandlers = {
744
- pointerDown: false,
745
- currentTouchIdentifier: null,
746
- };
747
-
748
- function resetTouchHandlers() {
749
- Object.assign(touchHandlers, {
750
- pointerDown: false,
751
- currentTouchIdentifier: null,
752
- });
753
- }
754
-
755
- /**
756
- * Extracts the location of a touch or mouse event, allowing you to pass
757
- * in a "mouseup", "mousedown", or "mousemove" event and receive the
758
- * correct coordinates. Shouldn't be used with "vmouse" events.
759
- */
760
- function extractPointerLocation(event: any): Position | null | undefined {
761
- let touchOrEvent;
762
-
763
- if (touchHandlers.pointerDown) {
764
- // Look for the touch matching the one we're tracking; ignore others
765
- if (touchHandlers.currentTouchIdentifier != null) {
766
- const len = event.changedTouches ? event.changedTouches.length : 0;
767
- for (let i = 0; i < len; i++) {
768
- if (
769
- event.changedTouches[i].identifier ===
770
- touchHandlers.currentTouchIdentifier
771
- ) {
772
- touchOrEvent = event.changedTouches[i];
773
- }
774
- }
775
- } else {
776
- touchOrEvent = event;
777
- }
778
-
779
- const isEndish =
780
- event.type === "touchend" || event.type === "touchcancel";
781
- if (touchOrEvent && isEndish) {
782
- touchHandlers.pointerDown = false;
783
- touchHandlers.currentTouchIdentifier = null;
784
- }
785
- } else {
786
- // touchstart or mousedown
787
- touchHandlers.pointerDown = true;
788
- if (event.changedTouches) {
789
- touchOrEvent = event.changedTouches[0];
790
- touchHandlers.currentTouchIdentifier = touchOrEvent.identifier;
791
- } else {
792
- touchOrEvent = event;
793
- }
794
- }
795
-
796
- if (touchOrEvent) {
797
- return {
798
- left: touchOrEvent.pageX,
799
- top: touchOrEvent.pageY,
800
- };
801
- }
802
- }
803
-
804
- // Older browsers don't support passive events and so we need to feature-
805
- // detect them and do event subscription differently for them.
806
- // See: orderer.jsx
807
- const supportsPassiveEvents: () => boolean = () => {
808
- // Test via a getter in the options object to see if the passive
809
- // property is accessed
810
- try {
811
- const opts = Object.defineProperty({}, "passive", {
812
- get: function () {
813
- supportsPassive = true;
814
- },
815
- });
816
- // @ts-expect-error - TS2769 - No overload matches this call.
817
- window.addEventListener("testPassive", null, opts);
818
- // @ts-expect-error - TS2769 - No overload matches this call.
819
- window.removeEventListener("testPassive", null, opts);
820
- } catch (e: any) {
821
- // Intentionally left empty!
822
- }
823
-
824
- return supportsPassive;
825
- };
826
-
827
- /**
828
- * Pass this function as the touchstart for an element to
829
- * avoid sending the touch to the mobile scratchpad
830
- */
831
- function captureScratchpadTouchStart(e: TouchEvent) {
832
- e.stopPropagation();
833
- }
834
-
835
- function getImageSize(
836
- url: string,
837
- callback: (width: number, height: number) => void,
838
- ): void {
839
- const img = new Image();
840
- img.onload = function () {
841
- // IE 11 seems to have problems calculating the heights of svgs
842
- // if they're not in the DOM. To solve this, we add the element to
843
- // the dom, wait for a rerender, and use `.clientWidth` and
844
- // `.clientHeight`. I think we could also solve the problem by
845
- // adding the image to the document before setting the src, but then
846
- // the experience would be worse for other browsers.
847
- // TODO(scottgrant): This is correctly calculating the width of SVG
848
- // images in browsers, but incorrectly saving the width of what may
849
- // be a smaller viewport when using the editor, and reusing that
850
- // width in a full-screen article.
851
- if (img.width === 0 && img.height === 0) {
852
- document.body?.appendChild(img);
853
- // TODO(scottgrant): Remove this use of _.defer.
854
- _.defer(function () {
855
- callback(img.clientWidth, img.clientHeight);
856
- document.body?.removeChild(img);
857
- });
858
- } else {
859
- callback(img.width, img.height);
860
- }
861
- };
862
-
863
- img.src = GraphieUtil.getRealImageUrl(url);
864
- }
865
-
866
- /**
867
- * Gets the word right before where the textarea cursor is
868
- *
869
- * @param {Element} textarea - The textarea DOM element
870
- * @return {JSON} - An object with the word and its starting and ending positions in the textarea
871
- */
872
- function getWordBeforeCursor(textarea: HTMLTextAreaElement): WordAndPosition {
873
- const text = textarea.value;
874
-
875
- const endPos = textarea.selectionStart - 1;
876
- const startPos =
877
- Math.max(
878
- text.lastIndexOf("\n", endPos),
879
- text.lastIndexOf(" ", endPos),
880
- ) + 1;
881
-
882
- return {
883
- string: text.substring(startPos, endPos + 1),
884
- pos: {
885
- start: startPos,
886
- end: endPos,
887
- },
888
- };
889
- }
890
-
891
- /**
892
- * Moves the textarea cursor at the specified position
893
- *
894
- * @param {Element} textarea - The textarea DOM element
895
- * @param {int} pos - The position where the cursor will be moved
896
- */
897
- function moveCursor(textarea: HTMLTextAreaElement, pos: number): void {
898
- textarea.selectionStart = pos;
899
- textarea.selectionEnd = pos;
900
- }
901
-
902
- const textarea = {
903
- getWordBeforeCursor,
904
- moveCursor,
905
- } as const;
906
-
907
- /**
908
- * Many of our labels are automatically converted into math mode without
909
- * the dollar signs. Unfortunately, this makes them untranslatable! This
910
- * helper function removes the math mode symbols from a string if we want
911
- * to translate it but don't need the extra dollar signs.
912
- */
913
- const unescapeMathMode: (label: string) => string = (label) =>
914
- label.startsWith("$") && label.endsWith("$") ? label.slice(1, -1) : label;
915
-
916
- const random: RNG = seededRNG(new Date().getTime() & 0xffffffff);
917
-
918
- const Util = {
919
- inputPathsEqual,
920
- nestedMap,
921
- rWidgetRule,
922
- rTypeFromWidgetId,
923
- rWidgetParts,
924
- snowman,
925
- noScore,
926
- seededRNG,
927
- shuffle,
928
- split,
929
- combineScores,
930
- keScoreFromPerseusScore,
931
- firstNumericalParse,
932
- stringArrayOfSize,
933
- gridDimensionConfig,
934
- getGridStep,
935
- snapStepFromGridStep,
936
- scaleFromExtent,
937
- tickStepFromExtent,
938
- gridStepFromTickStep,
939
- tickStepFromNumTicks,
940
- constrainedTickStepsFromTickSteps,
941
- DeprecationMixin,
942
- eq,
943
- deepEq,
944
- parseQueryString,
945
- updateQueryString,
946
- strongEncodeURIComponent,
947
- widgetShouldHighlight,
948
- scoreIsEmpty,
949
- touchHandlers,
950
- resetTouchHandlers,
951
- extractPointerLocation,
952
- supportsPassiveEvents,
953
- captureScratchpadTouchStart,
954
- getImageSize,
955
- getImageSizeModern: GraphieUtil.getImageSizeModern,
956
- getRealImageUrl: GraphieUtil.getRealImageUrl,
957
- isLabeledSVG: GraphieUtil.isLabeledSVG,
958
- getBaseUrl: GraphieUtil.getBaseUrl,
959
- getSvgUrl: GraphieUtil.getSvgUrl,
960
- getDataUrl: GraphieUtil.getDataUrl,
961
- textarea,
962
- unescapeMathMode,
963
- random,
964
- } as const;
965
-
966
- export default Util;