@khanacademy/perseus 0.0.1 → 0.2.1

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 (507) hide show
  1. package/.babelrc.js +1 -1
  2. package/CHANGELOG.md +29 -0
  3. package/dist/es/index.css +4361 -0
  4. package/dist/es/index.js +7 -1
  5. package/dist/es/index.js.map +1 -1
  6. package/dist/index.css +4361 -0
  7. package/dist/index.js +7 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/strings.js +148 -46
  10. package/package.json +50 -4
  11. package/src/README.md +35 -0
  12. package/src/__stories__/item-renderer.stories.jsx +27 -0
  13. package/src/__stories__/server-item-renderer.stories.jsx +27 -0
  14. package/src/__testdata__/item-renderer_testdata.js +161 -0
  15. package/src/__testdata__/renderer_testdata.js +123 -0
  16. package/src/__tests__/__snapshots__/item-renderer_test.jsx.snap +233 -0
  17. package/src/__tests__/__snapshots__/perseus-markdown_test.jsx.snap +516 -0
  18. package/src/__tests__/__snapshots__/pure-markdown_test.js.snap +113 -0
  19. package/src/__tests__/__snapshots__/renderer_test.jsx.snap +576 -0
  20. package/src/__tests__/__snapshots__/server-item-renderer_test.jsx.snap +306 -0
  21. package/src/__tests__/a11y_test.jsx +304 -0
  22. package/src/__tests__/item-renderer_test.jsx +892 -0
  23. package/src/__tests__/mock-asset-loading-widget.jsx +57 -0
  24. package/src/__tests__/mock-widget.jsx +35 -0
  25. package/src/__tests__/perseus-markdown_test.jsx +747 -0
  26. package/src/__tests__/pure-markdown_test.js +552 -0
  27. package/src/__tests__/renderability_test.jsx +481 -0
  28. package/src/__tests__/renderer-api_test.jsx +333 -0
  29. package/src/__tests__/renderer_test.jsx +1792 -0
  30. package/src/__tests__/server-item-renderer_test.jsx +516 -0
  31. package/src/__tests__/test-items/image-item.js +25 -0
  32. package/src/__tests__/test-items/input-number-1-item.js +27 -0
  33. package/src/__tests__/test-items/input-number-2-item.js +39 -0
  34. package/src/__tests__/test-items/table-item.js +30 -0
  35. package/src/__tests__/tex-wrangler_test.js +83 -0
  36. package/src/__tests__/util_test.js +41 -0
  37. package/src/a11y.js +46 -0
  38. package/src/all-widgets.js +9 -0
  39. package/src/article-renderer.jsx +215 -0
  40. package/src/asset-context.js +30 -0
  41. package/src/basic-widgets.js +13 -0
  42. package/src/components/__stories__/button-group.stories.jsx +61 -0
  43. package/src/components/__stories__/fixed-to-responsive.stories.jsx +132 -0
  44. package/src/components/__stories__/graph.stories.jsx +27 -0
  45. package/src/components/__stories__/graphie.stories.jsx +28 -0
  46. package/src/components/__stories__/hud.stories.jsx +36 -0
  47. package/src/components/__stories__/icon.stories.jsx +56 -0
  48. package/src/components/__stories__/image-loader.stories.jsx +60 -0
  49. package/src/components/__stories__/info-tip.stories.jsx +33 -0
  50. package/src/components/__stories__/inline-icon.stories.jsx +39 -0
  51. package/src/components/__stories__/input-with-examples.stories.jsx +51 -0
  52. package/src/components/__stories__/lint.stories.jsx +40 -0
  53. package/src/components/__stories__/math-input.stories.jsx +29 -0
  54. package/src/components/__stories__/math-output.stories.jsx +24 -0
  55. package/src/components/__stories__/multi-button-group.stories.jsx +69 -0
  56. package/src/components/__stories__/number-input.stories.jsx +42 -0
  57. package/src/components/__stories__/possible-answers.stories.jsx +22 -0
  58. package/src/components/__stories__/prop-check-box.stories.jsx +62 -0
  59. package/src/components/__stories__/range-input.stories.jsx +28 -0
  60. package/src/components/__stories__/simple-keypad-input.stories.jsx +28 -0
  61. package/src/components/__stories__/sortable.stories.jsx +73 -0
  62. package/src/components/__stories__/stub-tag-editor.stories.jsx +44 -0
  63. package/src/components/__stories__/svg-image.stories.jsx +60 -0
  64. package/src/components/__stories__/tex.stories.jsx +18 -0
  65. package/src/components/__stories__/text-buttons.stories.jsx +51 -0
  66. package/src/components/__stories__/text-input.stories.jsx +34 -0
  67. package/src/components/__stories__/text-list-editor.stories.jsx +33 -0
  68. package/src/components/__stories__/zoomable-tex.stories.jsx +39 -0
  69. package/src/components/__stories__/zoomable.stories.jsx +40 -0
  70. package/src/components/__testdata__/sorter_testdata.js +20 -0
  71. package/src/components/__tests__/__snapshots__/sortable_test.jsx.snap +79 -0
  72. package/src/components/__tests__/__snapshots__/sorter_test.jsx.snap +297 -0
  73. package/src/components/__tests__/number-input_test.jsx +112 -0
  74. package/src/components/__tests__/sortable_test.jsx +234 -0
  75. package/src/components/__tests__/sorter_test.jsx +111 -0
  76. package/src/components/__tests__/zoomable_test.jsx +388 -0
  77. package/src/components/button-group.jsx +131 -0
  78. package/src/components/constants.js +15 -0
  79. package/src/components/fixed-to-responsive.jsx +164 -0
  80. package/src/components/graph.jsx +415 -0
  81. package/src/components/graphie-classes.jsx +148 -0
  82. package/src/components/graphie-movables.jsx +342 -0
  83. package/src/components/graphie.jsx +353 -0
  84. package/src/components/highlighting/highlightable-content.jsx +245 -0
  85. package/src/components/highlighting/highlights.js +208 -0
  86. package/src/components/highlighting/ranges.js +299 -0
  87. package/src/components/highlighting/types.js +73 -0
  88. package/src/components/highlighting/ui/highlight-renderer.jsx +179 -0
  89. package/src/components/highlighting/ui/highlight-set-renderer.jsx +190 -0
  90. package/src/components/highlighting/ui/highlight-tooltip.jsx +153 -0
  91. package/src/components/highlighting/ui/highlighting-ui.jsx +163 -0
  92. package/src/components/highlighting/ui/selection-tracker.jsx +195 -0
  93. package/src/components/highlighting/ui/types.js +21 -0
  94. package/src/components/highlighting/ui/util.js +166 -0
  95. package/src/components/highlighting/word-indexer.jsx +155 -0
  96. package/src/components/hud.jsx +179 -0
  97. package/src/components/icon.jsx +149 -0
  98. package/src/components/image-loader.jsx +175 -0
  99. package/src/components/info-tip/info-tip.jsx +146 -0
  100. package/src/components/info-tip.jsx +38 -0
  101. package/src/components/inline-icon.jsx +81 -0
  102. package/src/components/input-with-examples.jsx +231 -0
  103. package/src/components/lint.jsx +454 -0
  104. package/src/components/math-input.jsx +282 -0
  105. package/src/components/math-output.jsx +128 -0
  106. package/src/components/multi-button-group.jsx +137 -0
  107. package/src/components/new-tooltip/README.md +110 -0
  108. package/src/components/new-tooltip/__stories__/flexible-position.stories.jsx +437 -0
  109. package/src/components/new-tooltip/__stories__/new-tooltip.stories.jsx +665 -0
  110. package/src/components/new-tooltip/__stories__/tooltip-arrow.stories.jsx +70 -0
  111. package/src/components/new-tooltip/__stories__/tooltip-bubble.stories.jsx +98 -0
  112. package/src/components/new-tooltip/__tests__/style-constants_test.js +8 -0
  113. package/src/components/new-tooltip/__tests__/util_test.js +47 -0
  114. package/src/components/new-tooltip/flexible-position.jsx +182 -0
  115. package/src/components/new-tooltip/new-tooltip.jsx +399 -0
  116. package/src/components/new-tooltip/style-constants.js +13 -0
  117. package/src/components/new-tooltip/tooltip-arrow.jsx +184 -0
  118. package/src/components/new-tooltip/tooltip-bubble.jsx +223 -0
  119. package/src/components/new-tooltip/tooltip-portal.jsx +101 -0
  120. package/src/components/new-tooltip/tooltip-positioner.jsx +529 -0
  121. package/src/components/new-tooltip/types.js +183 -0
  122. package/src/components/new-tooltip/util.js +27 -0
  123. package/src/components/number-input.jsx +253 -0
  124. package/src/components/possible-answers.jsx +36 -0
  125. package/src/components/prop-check-box.jsx +80 -0
  126. package/src/components/range-input.jsx +61 -0
  127. package/src/components/simple-keypad-input.jsx +91 -0
  128. package/src/components/sortable.jsx +873 -0
  129. package/src/components/stub-tag-editor.jsx +54 -0
  130. package/src/components/svg-image.jsx +762 -0
  131. package/src/components/tex-buttons.jsx +322 -0
  132. package/src/components/tex.jsx +70 -0
  133. package/src/components/text-input.jsx +82 -0
  134. package/src/components/text-list-editor.jsx +157 -0
  135. package/src/components/tooltip.jsx +395 -0
  136. package/src/components/visibility-observer/__stories__/visibility-observer.stories.jsx +140 -0
  137. package/src/components/visibility-observer/get-scroll-parent.js +45 -0
  138. package/src/components/visibility-observer/visibility-observer.js +109 -0
  139. package/src/components/visibility-observer/visibility-observer.jsx +123 -0
  140. package/src/components/zoomable-tex.jsx +70 -0
  141. package/src/components/zoomable.jsx +304 -0
  142. package/src/components.js +17 -0
  143. package/src/dependencies.js +22 -0
  144. package/src/error-boundary.jsx +48 -0
  145. package/src/extra-widgets.js +75 -0
  146. package/src/gorgon/README +40 -0
  147. package/src/gorgon/__tests__/matcher_test.js +497 -0
  148. package/src/gorgon/__tests__/rule_test.js +101 -0
  149. package/src/gorgon/__tests__/rules_test.js +487 -0
  150. package/src/gorgon/__tests__/selector-parser_test.js +52 -0
  151. package/src/gorgon/__tests__/tree-transformer_test.js +446 -0
  152. package/src/gorgon/gorgon.js +290 -0
  153. package/src/gorgon/proptypes.js +29 -0
  154. package/src/gorgon/rule.js +413 -0
  155. package/src/gorgon/rules/absolute-url.js +24 -0
  156. package/src/gorgon/rules/all-rules.js +72 -0
  157. package/src/gorgon/rules/blockquoted-math.js +10 -0
  158. package/src/gorgon/rules/blockquoted-widget.js +10 -0
  159. package/src/gorgon/rules/double-spacing-after-terminal.js +12 -0
  160. package/src/gorgon/rules/extra-content-spacing.js +12 -0
  161. package/src/gorgon/rules/heading-level-1.js +14 -0
  162. package/src/gorgon/rules/heading-level-skip.js +20 -0
  163. package/src/gorgon/rules/heading-sentence-case.js +11 -0
  164. package/src/gorgon/rules/heading-title-case.js +63 -0
  165. package/src/gorgon/rules/image-alt-text.js +21 -0
  166. package/src/gorgon/rules/image-in-table.js +10 -0
  167. package/src/gorgon/rules/image-spaces-around-urls.js +35 -0
  168. package/src/gorgon/rules/image-widget.js +50 -0
  169. package/src/gorgon/rules/link-click-here.js +11 -0
  170. package/src/gorgon/rules/lint-utils.js +48 -0
  171. package/src/gorgon/rules/long-paragraph.js +14 -0
  172. package/src/gorgon/rules/math-adjacent.js +10 -0
  173. package/src/gorgon/rules/math-align-extra-break.js +11 -0
  174. package/src/gorgon/rules/math-align-linebreaks.js +43 -0
  175. package/src/gorgon/rules/math-empty.js +10 -0
  176. package/src/gorgon/rules/math-font-size.js +12 -0
  177. package/src/gorgon/rules/math-frac.js +10 -0
  178. package/src/gorgon/rules/math-nested.js +11 -0
  179. package/src/gorgon/rules/math-starts-with-space.js +12 -0
  180. package/src/gorgon/rules/math-text-empty.js +10 -0
  181. package/src/gorgon/rules/math-without-dollars.js +14 -0
  182. package/src/gorgon/rules/nested-lists.js +11 -0
  183. package/src/gorgon/rules/profanity.js +10 -0
  184. package/src/gorgon/rules/table-missing-cells.js +20 -0
  185. package/src/gorgon/rules/unbalanced-code-delimiters.js +14 -0
  186. package/src/gorgon/rules/unescaped-dollar.js +10 -0
  187. package/src/gorgon/rules/widget-in-table.js +10 -0
  188. package/src/gorgon/selector.js +506 -0
  189. package/src/gorgon/tree-transformer.js +588 -0
  190. package/src/hint-renderer.jsx +159 -0
  191. package/src/hints-renderer.jsx +359 -0
  192. package/src/icon-paths.js +120 -0
  193. package/src/index.js +149 -2
  194. package/src/init.js +49 -0
  195. package/src/interaction-tracker.js +60 -0
  196. package/src/interactive2/__tests__/movable-mock.js +48 -0
  197. package/src/interactive2/__tests__/movable-point_test.js +146 -0
  198. package/src/interactive2/interactive-util.js +152 -0
  199. package/src/interactive2/movable-helper-methods.js +160 -0
  200. package/src/interactive2/movable-line-options.js +392 -0
  201. package/src/interactive2/movable-line.js +322 -0
  202. package/src/interactive2/movable-point-options.js +190 -0
  203. package/src/interactive2/movable-point.jsx +603 -0
  204. package/src/interactive2/movable-polygon-options.js +351 -0
  205. package/src/interactive2/movable-polygon.js +368 -0
  206. package/src/interactive2/movable.js +273 -0
  207. package/src/interactive2/objective_.js +79 -0
  208. package/src/interactive2/types.js +3 -0
  209. package/src/interactive2/wrapped-defaults.js +86 -0
  210. package/src/interactive2/wrapped-ellipse.js +87 -0
  211. package/src/interactive2/wrapped-line.js +109 -0
  212. package/src/interactive2/wrapped-path.js +47 -0
  213. package/src/interactive2.js +91 -0
  214. package/src/item-renderer.jsx +518 -0
  215. package/src/item-version.js +12 -0
  216. package/src/jipt-paragraphs.js +44 -0
  217. package/src/jquery.mobile.vmouse.js +545 -0
  218. package/src/keypad-context.js +33 -0
  219. package/src/loading-context.js +20 -0
  220. package/src/logging/log.js +107 -0
  221. package/src/logging/log_test.js +41 -0
  222. package/src/mixins/changeable.jsx +115 -0
  223. package/src/mixins/editor-jsonify.jsx +13 -0
  224. package/src/mixins/provide-keypad.jsx +129 -0
  225. package/src/mixins/widget-jsonify-deprecated.jsx +23 -0
  226. package/src/mixins/widget-prop-blacklist.js +36 -0
  227. package/src/multi-items/__stories__/multi-renderer.stories.js +88 -0
  228. package/src/multi-items/__testdata__/multi-renderer_testdata.js +174 -0
  229. package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +994 -0
  230. package/src/multi-items/__tests__/items_test.js +245 -0
  231. package/src/multi-items/__tests__/multi-renderer_test.js +903 -0
  232. package/src/multi-items/__tests__/prop-type-builders_test.js +134 -0
  233. package/src/multi-items/__tests__/shapes_test.js +44 -0
  234. package/src/multi-items/__tests__/trees_test.js +316 -0
  235. package/src/multi-items/item-types.js +55 -0
  236. package/src/multi-items/items.js +176 -0
  237. package/src/multi-items/multi-renderer.jsx +543 -0
  238. package/src/multi-items/prop-type-builders.js +105 -0
  239. package/src/multi-items/shape-types.js +47 -0
  240. package/src/multi-items/shapes.js +53 -0
  241. package/src/multi-items/tree-types.js +42 -0
  242. package/src/multi-items/trees.js +345 -0
  243. package/src/multi-items.js +76 -0
  244. package/src/not-gorgon.js +129 -0
  245. package/src/perseus-api.jsx +270 -0
  246. package/src/perseus-env.js +26 -0
  247. package/src/perseus-error.js +19 -0
  248. package/src/perseus-markdown.jsx +433 -0
  249. package/src/perseus-types.js +1597 -0
  250. package/src/pure-markdown.js +347 -0
  251. package/src/question-paragraph.jsx +30 -0
  252. package/src/renderability.jsx +108 -0
  253. package/src/renderer.jsx +1932 -0
  254. package/src/server-item-renderer.jsx +467 -0
  255. package/src/sigfigs.jsx +492 -0
  256. package/src/styles/articles.less +748 -0
  257. package/src/styles/constants.js +119 -0
  258. package/src/styles/global-constants.js +350 -0
  259. package/src/styles/global-styles.js +307 -0
  260. package/src/styles/khan-exercise.css +1304 -0
  261. package/src/styles/media-queries.js +48 -0
  262. package/src/styles/perseus-renderer.less +1007 -0
  263. package/src/styles/shared.js +132 -0
  264. package/src/styles/util.less +47 -0
  265. package/src/styles/variables.boostrap.less +301 -0
  266. package/src/styles/variables.less +68 -0
  267. package/src/styles/variables.shared.less +356 -0
  268. package/src/styles/widgets/categorizer.less +39 -0
  269. package/src/styles/widgets/definition.less +86 -0
  270. package/src/styles/widgets/dropdown.less +3 -0
  271. package/src/styles/widgets/expression.less +147 -0
  272. package/src/styles/widgets/graded-group.less +36 -0
  273. package/src/styles/widgets/grapher.less +11 -0
  274. package/src/styles/widgets/group.less +19 -0
  275. package/src/styles/widgets/image.less +29 -0
  276. package/src/styles/widgets/interactive-graph.less +61 -0
  277. package/src/styles/widgets/label-image.less +41 -0
  278. package/src/styles/widgets/matcher.less +8 -0
  279. package/src/styles/widgets/matrix.less +120 -0
  280. package/src/styles/widgets/measurer.less +20 -0
  281. package/src/styles/widgets/orderer.less +97 -0
  282. package/src/styles/widgets/passage.less +151 -0
  283. package/src/styles/widgets/plotter.less +33 -0
  284. package/src/styles/widgets/radio.less +52 -0
  285. package/src/styles/widgets/reaction-diagram.less +35 -0
  286. package/src/styles/widgets/sequence.less +5 -0
  287. package/src/styles/widgets/sortable.less +127 -0
  288. package/src/styles/widgets/table.less +56 -0
  289. package/src/styles/widgets/transformer.less +28 -0
  290. package/src/styles/widgets/unit.less +14 -0
  291. package/src/tex-wrangler.js +176 -0
  292. package/src/traversal.jsx +141 -0
  293. package/src/types.js +538 -0
  294. package/src/util/a11y.js +24 -0
  295. package/src/util/answer-types.js +862 -0
  296. package/src/util/answer-types_test.js +115 -0
  297. package/src/util/colors.js +94 -0
  298. package/src/util/fix-passage-refs.jsx +122 -0
  299. package/src/util/graph-utils.js +16 -0
  300. package/src/util/graphie.js +1586 -0
  301. package/src/util/interactive.js +4078 -0
  302. package/src/util/katex-preprocess.js +16 -0
  303. package/src/util/math.js +296 -0
  304. package/src/util/mobile-native-utils.js +14 -0
  305. package/src/util/mobile-native-utils_test.js +24 -0
  306. package/src/util/register-all-widgets-for-testing.js +12 -0
  307. package/src/util/scroll-utils.js +162 -0
  308. package/src/util/sizing-utils.js +46 -0
  309. package/src/util/tex.js +203 -0
  310. package/src/util/url-utils.js +36 -0
  311. package/src/util.js +990 -0
  312. package/src/version.js +11 -0
  313. package/src/widget-container.jsx +174 -0
  314. package/src/widgets/__stories__/categorizer.stories.jsx +15 -0
  315. package/src/widgets/__stories__/cs-program.stories.jsx +15 -0
  316. package/src/widgets/__stories__/definition.stories.jsx +38 -0
  317. package/src/widgets/__stories__/dropdown.stories.jsx +15 -0
  318. package/src/widgets/__stories__/explanation.stories.jsx +19 -0
  319. package/src/widgets/__stories__/expression.stories.jsx +26 -0
  320. package/src/widgets/__stories__/graded-group-set.stories.jsx +32 -0
  321. package/src/widgets/__stories__/graded-group.stories.jsx +32 -0
  322. package/src/widgets/__stories__/grapher.stories.jsx +47 -0
  323. package/src/widgets/__stories__/group.stories.jsx +15 -0
  324. package/src/widgets/__stories__/iframe.stories.jsx +15 -0
  325. package/src/widgets/__stories__/image.stories.jsx +62 -0
  326. package/src/widgets/__stories__/input-number.stories.jsx +90 -0
  327. package/src/widgets/__stories__/interaction.stories.jsx +15 -0
  328. package/src/widgets/__stories__/interactive-graph.stories.jsx +61 -0
  329. package/src/widgets/__stories__/matcher.stories.jsx +15 -0
  330. package/src/widgets/__stories__/matrix.stories.jsx +15 -0
  331. package/src/widgets/__stories__/number-line.stories.jsx +15 -0
  332. package/src/widgets/__stories__/numeric-input.stories.jsx +19 -0
  333. package/src/widgets/__stories__/orderer.stories.jsx +15 -0
  334. package/src/widgets/__stories__/passage-ref.stories.jsx +19 -0
  335. package/src/widgets/__stories__/passage.stories.jsx +19 -0
  336. package/src/widgets/__stories__/radio.stories.jsx +82 -0
  337. package/src/widgets/__stories__/sorter.stories.jsx +15 -0
  338. package/src/widgets/__stories__/transformer.stories.jsx +15 -0
  339. package/src/widgets/__stories__/unit.stories.jsx +45 -0
  340. package/src/widgets/__stories__/video-transcript-link.stories.jsx +24 -0
  341. package/src/widgets/__stories__/video.stories.jsx +15 -0
  342. package/src/widgets/__testdata__/categorizer_testdata.js +50 -0
  343. package/src/widgets/__testdata__/cs-program_testdata.js +28 -0
  344. package/src/widgets/__testdata__/dropdown_testdata.js +34 -0
  345. package/src/widgets/__testdata__/explanation_testdata.js +56 -0
  346. package/src/widgets/__testdata__/expression_testdata.js +95 -0
  347. package/src/widgets/__testdata__/graded-group-set_testdata.js +358 -0
  348. package/src/widgets/__testdata__/graded-group_testdata.js +79 -0
  349. package/src/widgets/__testdata__/grapher_testdata.js +376 -0
  350. package/src/widgets/__testdata__/group_testdata.js +156 -0
  351. package/src/widgets/__testdata__/iframe_testdata.js +36 -0
  352. package/src/widgets/__testdata__/image_testdata.js +38 -0
  353. package/src/widgets/__testdata__/input-number_testdata.js +73 -0
  354. package/src/widgets/__testdata__/interaction_testdata.js +264 -0
  355. package/src/widgets/__testdata__/interactive-graph_testdata.js +646 -0
  356. package/src/widgets/__testdata__/matcher_testdata.js +34 -0
  357. package/src/widgets/__testdata__/matrix_testdata.js +29 -0
  358. package/src/widgets/__testdata__/number-line_testdata.js +31 -0
  359. package/src/widgets/__testdata__/numeric-input_testdata.js +266 -0
  360. package/src/widgets/__testdata__/orderer_testdata.js +58 -0
  361. package/src/widgets/__testdata__/passage-ref_testdata.js +41 -0
  362. package/src/widgets/__testdata__/passage_testdata.js +71 -0
  363. package/src/widgets/__testdata__/radio_testdata.js +210 -0
  364. package/src/widgets/__testdata__/sorter_testdata.js +20 -0
  365. package/src/widgets/__testdata__/transformer_testdata.js +109 -0
  366. package/src/widgets/__testdata__/video_testdata.js +22 -0
  367. package/src/widgets/__tests__/__snapshots__/categorizer_test.jsx.snap +928 -0
  368. package/src/widgets/__tests__/__snapshots__/cs-program_test.jsx.snap +75 -0
  369. package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +99 -0
  370. package/src/widgets/__tests__/__snapshots__/dropdown_test.jsx.snap +143 -0
  371. package/src/widgets/__tests__/__snapshots__/explanation_test.js.snap +473 -0
  372. package/src/widgets/__tests__/__snapshots__/expression_test.jsx.snap +38 -0
  373. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt_test.jsx.snap +754 -0
  374. package/src/widgets/__tests__/__snapshots__/graded-group-set_test.jsx.snap +310 -0
  375. package/src/widgets/__tests__/__snapshots__/graded-group_test.jsx.snap +863 -0
  376. package/src/widgets/__tests__/__snapshots__/grapher_test.jsx.snap +2880 -0
  377. package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +1154 -0
  378. package/src/widgets/__tests__/__snapshots__/iframe_test.jsx.snap +69 -0
  379. package/src/widgets/__tests__/__snapshots__/image_test.jsx.snap +388 -0
  380. package/src/widgets/__tests__/__snapshots__/input-number_test.jsx.snap +978 -0
  381. package/src/widgets/__tests__/__snapshots__/interaction_test.jsx.snap +311 -0
  382. package/src/widgets/__tests__/__snapshots__/interactive-graph_test.jsx.snap +2915 -0
  383. package/src/widgets/__tests__/__snapshots__/matcher_test.jsx.snap +1039 -0
  384. package/src/widgets/__tests__/__snapshots__/matrix_test.jsx.snap +450 -0
  385. package/src/widgets/__tests__/__snapshots__/number-line_test.jsx.snap +888 -0
  386. package/src/widgets/__tests__/__snapshots__/numeric-input_test.jsx.snap +930 -0
  387. package/src/widgets/__tests__/__snapshots__/orderer_test.jsx.snap +275 -0
  388. package/src/widgets/__tests__/__snapshots__/passage-ref_test.jsx.snap +446 -0
  389. package/src/widgets/__tests__/__snapshots__/passage_test.jsx.snap +1988 -0
  390. package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +7107 -0
  391. package/src/widgets/__tests__/__snapshots__/video_test.jsx.snap +163 -0
  392. package/src/widgets/__tests__/categorizer_test.jsx +205 -0
  393. package/src/widgets/__tests__/cs-program_test.jsx +45 -0
  394. package/src/widgets/__tests__/definition_test.js +152 -0
  395. package/src/widgets/__tests__/dropdown_test.jsx +106 -0
  396. package/src/widgets/__tests__/explanation_test.js +199 -0
  397. package/src/widgets/__tests__/expression_test.jsx +439 -0
  398. package/src/widgets/__tests__/graded-group-set-jipt_test.jsx +33 -0
  399. package/src/widgets/__tests__/graded-group-set_test.jsx +270 -0
  400. package/src/widgets/__tests__/graded-group_test.jsx +233 -0
  401. package/src/widgets/__tests__/grapher.cypress.jsx +486 -0
  402. package/src/widgets/__tests__/grapher_test.jsx +35 -0
  403. package/src/widgets/__tests__/group_test.jsx +512 -0
  404. package/src/widgets/__tests__/iframe_test.jsx +47 -0
  405. package/src/widgets/__tests__/image_test.jsx +65 -0
  406. package/src/widgets/__tests__/input-number_test.jsx +360 -0
  407. package/src/widgets/__tests__/interaction_test.jsx +33 -0
  408. package/src/widgets/__tests__/interactive-graph.cypress.jsx +697 -0
  409. package/src/widgets/__tests__/interactive-graph_test.jsx +105 -0
  410. package/src/widgets/__tests__/matcher_test.jsx +157 -0
  411. package/src/widgets/__tests__/matrix_test.jsx +84 -0
  412. package/src/widgets/__tests__/number-line_test.jsx +81 -0
  413. package/src/widgets/__tests__/numeric-input_test.jsx +574 -0
  414. package/src/widgets/__tests__/orderer_test.jsx +75 -0
  415. package/src/widgets/__tests__/passage-ref_test.jsx +166 -0
  416. package/src/widgets/__tests__/passage_test.jsx +133 -0
  417. package/src/widgets/__tests__/radio/base-radio_test.jsx +82 -0
  418. package/src/widgets/__tests__/radio_test.jsx +651 -0
  419. package/src/widgets/__tests__/renderQuestion.jsx +66 -0
  420. package/src/widgets/__tests__/unit_test.jsx +144 -0
  421. package/src/widgets/__tests__/video_test.jsx +55 -0
  422. package/src/widgets/categorizer.jsx +338 -0
  423. package/src/widgets/cs-program.jsx +227 -0
  424. package/src/widgets/definition.jsx +141 -0
  425. package/src/widgets/dropdown.jsx +143 -0
  426. package/src/widgets/explanation.jsx +315 -0
  427. package/src/widgets/expression.jsx +652 -0
  428. package/src/widgets/graded-group-answer-bar.jsx +152 -0
  429. package/src/widgets/graded-group-set.jsx +285 -0
  430. package/src/widgets/graded-group.jsx +448 -0
  431. package/src/widgets/grapher/util.jsx +806 -0
  432. package/src/widgets/grapher.jsx +663 -0
  433. package/src/widgets/group.jsx +213 -0
  434. package/src/widgets/iframe.jsx +198 -0
  435. package/src/widgets/image.jsx +310 -0
  436. package/src/widgets/input-number.jsx +411 -0
  437. package/src/widgets/interaction/arrow-picker.jsx +39 -0
  438. package/src/widgets/interaction/color-picker.jsx +69 -0
  439. package/src/widgets/interaction/dash-picker.jsx +46 -0
  440. package/src/widgets/interaction/element-container.jsx +97 -0
  441. package/src/widgets/interaction.jsx +742 -0
  442. package/src/widgets/interactive-graph.jsx +2820 -0
  443. package/src/widgets/label-image/__stories__/answer-choices.stories.jsx +93 -0
  444. package/src/widgets/label-image/__stories__/marker.stories.jsx +172 -0
  445. package/src/widgets/label-image/answer-choices.jsx +311 -0
  446. package/src/widgets/label-image/marker.jsx +365 -0
  447. package/src/widgets/label-image/types.js +33 -0
  448. package/src/widgets/label-image.jsx +841 -0
  449. package/src/widgets/label-image_test.js +840 -0
  450. package/src/widgets/lights-puzzle.jsx +356 -0
  451. package/src/widgets/matcher.jsx +271 -0
  452. package/src/widgets/matrix.jsx +616 -0
  453. package/src/widgets/measurer.jsx +215 -0
  454. package/src/widgets/molecule/__tests__/layout_test.jsx +159 -0
  455. package/src/widgets/molecule/__tests__/parser_test.jsx +142 -0
  456. package/src/widgets/molecule/molecule-drawing.jsx +175 -0
  457. package/src/widgets/molecule/molecule-layout.jsx +367 -0
  458. package/src/widgets/molecule/smiles-parser.jsx +300 -0
  459. package/src/widgets/molecule.jsx +172 -0
  460. package/src/widgets/number-line.jsx +858 -0
  461. package/src/widgets/numeric-input.jsx +622 -0
  462. package/src/widgets/orderer.jsx +753 -0
  463. package/src/widgets/passage/__tests__/passage-markdown_test.jsx +382 -0
  464. package/src/widgets/passage/get-line-height-for-node.js +10 -0
  465. package/src/widgets/passage/passage-markdown.jsx +416 -0
  466. package/src/widgets/passage-ref-target.jsx +70 -0
  467. package/src/widgets/passage-ref.jsx +198 -0
  468. package/src/widgets/passage.jsx +601 -0
  469. package/src/widgets/plotter.jsx +1198 -0
  470. package/src/widgets/radio/__stories__/base-radio.stories.jsx +40 -0
  471. package/src/widgets/radio/__stories__/choice-icon.stories.jsx +157 -0
  472. package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +26 -0
  473. package/src/widgets/radio/__stories__/cross-out-button.stories.jsx +64 -0
  474. package/src/widgets/radio/__stories__/cross-out-menu.stories.jsx +59 -0
  475. package/src/widgets/radio/__stories__/cross-out-tooltip.stories.jsx +59 -0
  476. package/src/widgets/radio/__stories__/focus-ring.stories.jsx +38 -0
  477. package/src/widgets/radio/__stories__/option-status.stories.jsx +118 -0
  478. package/src/widgets/radio/__stories__/toggleable-radio-button.stories.jsx +28 -0
  479. package/src/widgets/radio/base-radio.jsx +642 -0
  480. package/src/widgets/radio/choice-icon.jsx +468 -0
  481. package/src/widgets/radio/choice-none-above.jsx +54 -0
  482. package/src/widgets/radio/choice.jsx +692 -0
  483. package/src/widgets/radio/choice.jsx.fixture.js +64 -0
  484. package/src/widgets/radio/cross-out-button.jsx +136 -0
  485. package/src/widgets/radio/cross-out-menu-wrapper.jsx +492 -0
  486. package/src/widgets/radio/cross-out-tooltip.jsx +129 -0
  487. package/src/widgets/radio/focus-ring.jsx +51 -0
  488. package/src/widgets/radio/option-status.jsx +89 -0
  489. package/src/widgets/radio/toggleable-radio-button.jsx +133 -0
  490. package/src/widgets/radio/util.js +32 -0
  491. package/src/widgets/radio/util_test.js +19 -0
  492. package/src/widgets/radio/widget.jsx +470 -0
  493. package/src/widgets/radio.jsx +156 -0
  494. package/src/widgets/reaction-diagram.jsx +137 -0
  495. package/src/widgets/sequence.jsx +140 -0
  496. package/src/widgets/simulator.jsx +808 -0
  497. package/src/widgets/sorter.jsx +146 -0
  498. package/src/widgets/table.jsx +394 -0
  499. package/src/widgets/transformer.jsx +2876 -0
  500. package/src/widgets/unit.jsx +372 -0
  501. package/src/widgets/video-transcript-link.jsx +84 -0
  502. package/src/widgets/video-transcript-link_test.js +211 -0
  503. package/src/widgets/video.jsx +126 -0
  504. package/src/widgets.js +431 -0
  505. package/src/zoom.js +539 -0
  506. package/README.md +0 -3
  507. package/src/__tests__/index.test.js +0 -14
@@ -0,0 +1,41 @@
1
+ // @flow
2
+
3
+ import {testDependencies} from "../../../../testing/test-dependencies.js";
4
+ import {setDependencies} from "../dependencies.js";
5
+
6
+ import {Errors, Log} from "./log.js";
7
+
8
+ describe("Perseus logging", () => {
9
+ it("should proxy log() calls to the logger provided through setDependencies", () => {
10
+ // Arrange
11
+ const logSpy = jest.spyOn(testDependencies.Log, "log");
12
+ setDependencies(testDependencies);
13
+
14
+ // Act
15
+ Log.log("test message", {a: 1, b: "two"});
16
+
17
+ // Assert
18
+ expect(logSpy).toHaveBeenCalledWith("test message", {a: 1, b: "two"});
19
+ });
20
+
21
+ it("should proxy error() calls to the logger provided through setDependencies", () => {
22
+ // Arrange
23
+ const errorSpy = jest.spyOn(testDependencies.Log, "error");
24
+ setDependencies(testDependencies);
25
+
26
+ // Act
27
+ Log.error("test error", Errors.NotAllowed, {
28
+ cause: new Error("Something baaad"),
29
+ loggedMetadata: {a: 1, b: "two"},
30
+ });
31
+
32
+ // Assert
33
+ expect(errorSpy).toHaveBeenCalledWith("test error", "NotAllowed", {
34
+ cause: expect.any(Error),
35
+ loggedMetadata: {
36
+ a: 1,
37
+ b: "two",
38
+ },
39
+ });
40
+ });
41
+ });
@@ -0,0 +1,115 @@
1
+ /* eslint-disable @babel/no-invalid-this */
2
+ // @flow
3
+ /**
4
+ * Changeable
5
+ *
6
+ * Adds a this.change() function to a component
7
+ *
8
+ * This.change takes prop changes as parameters, and calls
9
+ * this.props.onChange with the modified props.
10
+ */
11
+
12
+ import PropTypes from "prop-types";
13
+ import _ from "underscore";
14
+
15
+ import {Errors} from "../logging/log.js";
16
+ import {PerseusError} from "../perseus-error.js";
17
+
18
+ import WIDGET_PROP_BLACKLIST from "./widget-prop-blacklist.js";
19
+
20
+ import type {ChangeFn} from "../types.js";
21
+
22
+ const USAGE =
23
+ "Usage:\n" +
24
+ " this.change({propName: 5}, callback);\n" +
25
+ ' this.change("propName", 5, callback);\n' +
26
+ ' this.change("propName")';
27
+
28
+ /**
29
+ * Primary helper function for this.change()
30
+ *
31
+ * Takes the parameters in a consistent style, once this.change() has
32
+ * figured out which way it was called.
33
+ */
34
+ const _changeMultiple = function (component, newProps, callback) {
35
+ // Omit "default" props:
36
+ // ref and key come from react, and don't actually represent
37
+ // the conceptual state of our component
38
+ // onChange comes from our parent to allow this modification,
39
+ // and doesn't conceptually represent the state of our component
40
+ const currProps = _.omit(component.props, WIDGET_PROP_BLACKLIST);
41
+ const nextProps = _.extend(currProps, newProps);
42
+ component.props.onChange(nextProps, callback);
43
+ };
44
+
45
+ /**
46
+ * Helper function for changing a single prop
47
+ */
48
+ const _changeSingle = function (component, propName: string, value, callback) {
49
+ if (value === undefined) {
50
+ // If called with a single prop name, return a lambda to change
51
+ // a single prop on the current object
52
+ return _.partial(_changeSingle, component, propName);
53
+ }
54
+ // If called with two values, change a single prop of the
55
+ // current object
56
+ const newProps = {};
57
+ newProps[propName] = value;
58
+ _changeMultiple(component, newProps, callback);
59
+ };
60
+
61
+ /**
62
+ * this.change()
63
+ *
64
+ * Can be called as follows:
65
+ * this.change(newProps, callback);
66
+ *
67
+ * this.change(propName, propValue, callback);
68
+ *
69
+ * this.change(propName) -> returns a lambda that takes a prop value to
70
+ * set and a callback to call after having set that value.
71
+ */
72
+ // TODO(WEB-1727): use proper flow syntax for overloaded functions
73
+ export const change: ChangeFn = function (
74
+ newPropsOrSinglePropName,
75
+ propValue,
76
+ callback,
77
+ ) {
78
+ if (_.isObject(newPropsOrSinglePropName) && callback === undefined) {
79
+ // Called with an object of multiple props to change
80
+ callback = propValue;
81
+ return _changeMultiple(
82
+ this,
83
+ newPropsOrSinglePropName, // object newProps
84
+ callback,
85
+ );
86
+ }
87
+ if (typeof newPropsOrSinglePropName === "string") {
88
+ // Called with a string propName of a single prop to change
89
+ return _changeSingle(
90
+ this,
91
+ newPropsOrSinglePropName, // string propName
92
+ propValue,
93
+ callback,
94
+ );
95
+ }
96
+ throw new PerseusError(
97
+ "Invalid types sent to this.change(): " +
98
+ _.toArray(arguments).join() +
99
+ "\n" +
100
+ USAGE,
101
+ Errors.Internal,
102
+ );
103
+ };
104
+
105
+ export const propTypes = {
106
+ onChange: PropTypes.func.isRequired,
107
+ };
108
+
109
+ export type ChangeableProps = {|
110
+ onChange: (
111
+ values: {[string]: any, ...},
112
+ callback?: ?() => mixed,
113
+ silent?: boolean,
114
+ ) => mixed,
115
+ |};
@@ -0,0 +1,13 @@
1
+ // @flow
2
+ import _ from "underscore";
3
+
4
+ import WIDGET_PROP_BLACKLIST from "./widget-prop-blacklist.js";
5
+
6
+ const EditorJsonify = {
7
+ serialize: function (): $FlowFixMe {
8
+ // Omit props that get passed to all widgets
9
+ return _.omit(this.props, WIDGET_PROP_BLACKLIST);
10
+ },
11
+ };
12
+
13
+ export default EditorJsonify;
@@ -0,0 +1,129 @@
1
+ // @flow
2
+ /**
3
+ * A mixin that renders a custom software keypad in additional to the base
4
+ * component. The base component will receive blur events when the keypad is
5
+ * dismissed and can access the keypad element itself so as to manage its
6
+ * activation and dismissal.
7
+ *
8
+ * TODO(charlie): This would make a nicer higher-order component, except that
9
+ * we need to expose methods on the base component (i.e., `ItemRenderer`). When
10
+ * `ItemRenderer` and friends are written as ES6 Classes, we can have them
11
+ * extend a `ProvideKeypad` component instead of using this mixin.
12
+ */
13
+
14
+ import {Keypad} from "@khanacademy/math-input";
15
+ import PropTypes from "prop-types";
16
+ import * as React from "react";
17
+ import ReactDOM from "react-dom";
18
+
19
+ export type KeypadProps = {|
20
+ // An Aphrodite style object, to be applied to the keypad container.
21
+ // Note that, given our awkward structure of injecting the keypad, this
22
+ // style won't be applied or updated dynamically. Rather, it will only
23
+ // be applied in `componentDidMount`.
24
+ keypadStyle?: any,
25
+ |};
26
+
27
+ export type KeypadApiOptions = {|
28
+ customKeypad: boolean,
29
+ // eslint-disable-next-line flowtype/no-weak-types
30
+ nativeKeypadProxy: Function,
31
+ |};
32
+
33
+ // NOTE: This is not a real component. It's a collection of methods used to
34
+ // create and manage a Keypad instances.
35
+ // TODO(LP-10789): replace this with a React Context object to pass information
36
+ // between Perseus and the Keypad.
37
+ const ProvideKeypad = {
38
+ propTypes: {
39
+ apiOptions: (PropTypes.shape({
40
+ customKeypad: PropTypes.bool,
41
+ nativeKeypadProxy: PropTypes.func,
42
+ }): React$PropType$Primitive<{
43
+ customKeypad?: boolean,
44
+ nativeKeypadProxy?: (...a: $ReadOnlyArray<any>) => mixed,
45
+ ...
46
+ }>),
47
+ // An Aphrodite style object, to be applied to the keypad container.
48
+ // Note that, given our awkward structure of injecting the keypad, this
49
+ // style won't be applied or updated dynamically. Rather, it will only
50
+ // be applied in `componentDidMount`.
51
+ keypadStyle: PropTypes.any,
52
+ },
53
+
54
+ getInitialState(): {|keypadElement: any | null|} {
55
+ // $FlowFixMe[object-this-reference]
56
+ const _this = this;
57
+ let keypadElement = null;
58
+ if (
59
+ _this.props.apiOptions &&
60
+ _this.props.apiOptions.customKeypad &&
61
+ _this.props.apiOptions.nativeKeypadProxy
62
+ ) {
63
+ keypadElement = _this.props.apiOptions.nativeKeypadProxy(
64
+ () => _this.blur && _this.blur(),
65
+ );
66
+ }
67
+ return {keypadElement};
68
+ },
69
+
70
+ componentDidMount() {
71
+ // $FlowFixMe[object-this-reference]
72
+ const _this = this;
73
+ if (
74
+ _this.props.apiOptions &&
75
+ _this.props.apiOptions.customKeypad &&
76
+ !_this.props.apiOptions.nativeKeypadProxy
77
+ ) {
78
+ // TODO(charlie): Render this and the wrapped component in the same
79
+ // React tree. We may also want to add this keypad asynchronously
80
+ // or on-demand in the future.
81
+ _this._keypadContainer = document.createElement("div");
82
+ document.body?.appendChild(_this._keypadContainer);
83
+
84
+ // TODO(LP-11406): Replace with React Portal
85
+ // eslint-disable-next-line no-restricted-syntax
86
+ ReactDOM.render(
87
+ <Keypad
88
+ onElementMounted={(element) => {
89
+ // NOTE(kevinb): The reason why this setState works is
90
+ // b/c we're calling it manually from item-renderer.jsx
91
+ // and we're manually setting the 'this' by using 'call'
92
+ _this.setState({
93
+ keypadElement: element,
94
+ });
95
+ }}
96
+ onDismiss={() => {
97
+ _this.blur && _this.blur();
98
+ }}
99
+ style={_this.props.keypadStyle}
100
+ />,
101
+ _this._keypadContainer,
102
+ );
103
+ }
104
+ },
105
+
106
+ componentWillUnmount() {
107
+ // $FlowFixMe[object-this-reference]
108
+ const _this = this;
109
+ if (_this._keypadContainer) {
110
+ ReactDOM.unmountComponentAtNode(_this._keypadContainer);
111
+ if (_this._keypadContainer.parentNode) {
112
+ // Note ChildNode.remove() isn't available in older Android
113
+ // webviews.
114
+ _this._keypadContainer.parentNode.removeChild(
115
+ _this._keypadContainer,
116
+ );
117
+ }
118
+ _this._keypadContainer = null;
119
+ }
120
+ },
121
+
122
+ keypadElement(): any {
123
+ // $FlowFixMe[object-this-reference]
124
+ const _this = this;
125
+ return _this.state.keypadElement;
126
+ },
127
+ };
128
+
129
+ export default ProvideKeypad;
@@ -0,0 +1,23 @@
1
+ // @flow
2
+ /* Free implementation of getUserInput. This should be used sparingly, since it
3
+ * just returns all the widget's props rather than picking out those which were
4
+ * input by the user.
5
+ */
6
+ import _ from "underscore";
7
+
8
+ import WIDGET_PROP_BLACKLIST from "./widget-prop-blacklist.js";
9
+
10
+ const WidgetJsonifyDeprecated = {
11
+ getUserInput: function (): $FlowFixMe {
12
+ // Omit props that get passed to all widgets
13
+ return _.omit(this.props, WIDGET_PROP_BLACKLIST);
14
+ },
15
+
16
+ // Static version of `WidgetJsonifyDeprecated.getUserInput`
17
+ getUserInputFromProps: function (props: $FlowFixMe): $FlowFixMe {
18
+ // Omit props that get passed to all widgets
19
+ return _.omit(props, WIDGET_PROP_BLACKLIST);
20
+ },
21
+ };
22
+
23
+ export default WidgetJsonifyDeprecated;
@@ -0,0 +1,36 @@
1
+ // @flow
2
+ /**
3
+ * These are things that widgets should exclude when serializing themselves.
4
+ *
5
+ * The use of this list needs to die. Basically, there are codepaths that
6
+ * blindly serialize the "props" of a widget so that it can pass around its
7
+ * info. Unfortunately, props aren't guaranteed to be serializable, and
8
+ * automatically serializing schemaless list of attributes causes issues (e.g.
9
+ * circular JSON structures sometimes).
10
+ *
11
+ * This blacklists things that we know don't need to be serialized.
12
+ */
13
+ export default [
14
+ // standard props "added" by react
15
+ // (technically the renderer still adds them)
16
+ "key",
17
+ "ref",
18
+ // added by src/renderer.jsx
19
+ "containerSizeClass",
20
+ "widgetId",
21
+ "onChange",
22
+ "problemNum",
23
+ "apiOptions",
24
+ "questionCompleted",
25
+ "findWidgets",
26
+ // added by src/editor.jsx, for widgets removing themselves
27
+ // this is soooo not the right place for this, but alas.
28
+ "onRemove",
29
+ // also added by src/editor.jsx
30
+ "id",
31
+ // Callbacks and items for interaction handling
32
+ "onBlur",
33
+ "onFocus",
34
+ "trackInteraction",
35
+ "keypadElement",
36
+ ];
@@ -0,0 +1,88 @@
1
+ // @flow
2
+
3
+ import {View} from "@khanacademy/wonder-blocks-core";
4
+ import * as i18n from "@khanacademy/wonder-blocks-i18n";
5
+ import {HeadingSmall} from "@khanacademy/wonder-blocks-typography";
6
+ import {StyleSheet} from "aphrodite";
7
+ import * as React from "react";
8
+
9
+ import {MultiItemRendererWithDebugUI} from "../../../../../testing/multi-item-renderer-with-debug-ui.jsx";
10
+ import {question1} from "../__testdata__/multi-renderer_testdata.js";
11
+
12
+ type StoryArgs = {||};
13
+
14
+ type Story = {|
15
+ title: string,
16
+ |};
17
+
18
+ export const SingleItem = (args: StoryArgs): React.Node => {
19
+ const item = {
20
+ _multi: {
21
+ // $FlowFixMe[not-an-object]
22
+ ...question1._multi,
23
+ blurb: {
24
+ // $FlowFixMe[not-an-object]
25
+ // $FlowFixMe[prop-missing]
26
+ ...question1._multi.blurb,
27
+ content:
28
+ "This is a short snippet to help you understand the context of the question. We call it the 'blurb'.",
29
+ },
30
+ },
31
+ };
32
+ return (
33
+ <MultiItemRendererWithDebugUI simpleItem={item}>
34
+ {({renderers}) => {
35
+ const {blurb, question, hints} = renderers;
36
+ return (
37
+ <View>
38
+ <View style={styles.section}>
39
+ <HeadingSmall style={styles.heading}>
40
+ {i18n.doNotTranslate("Blurb")}
41
+ </HeadingSmall>
42
+ {blurb}
43
+ </View>
44
+ <View style={styles.section}>
45
+ <HeadingSmall style={styles.heading}>
46
+ {i18n.doNotTranslate("Question")}
47
+ </HeadingSmall>
48
+ {question}
49
+ </View>
50
+ <View style={styles.section}>
51
+ <HeadingSmall style={styles.heading}>
52
+ {i18n.doNotTranslate("Hints")}
53
+ </HeadingSmall>
54
+ <View style={styles.hints}>
55
+ {
56
+ // $FlowFixMe[prop-missing]
57
+ hints?.firstN(2)
58
+ }
59
+ </View>
60
+ </View>
61
+ </View>
62
+ );
63
+ }}
64
+ </MultiItemRendererWithDebugUI>
65
+ );
66
+ };
67
+
68
+ const styles = StyleSheet.create({
69
+ section: {
70
+ backgroundColor: "#F5F5F5",
71
+ padding: "5px",
72
+ borderWidth: "1px",
73
+ marginTop: "5px",
74
+ marginBottom: "5px",
75
+ },
76
+ heading: {
77
+ backgroundColor: "#A9A9A9",
78
+ margin: "-5px",
79
+ padding: "5px",
80
+ },
81
+ hints: {
82
+ marginLeft: "50px",
83
+ },
84
+ });
85
+
86
+ export default ({
87
+ title: "Perseus/Renderers/Multi Renderer",
88
+ }: Story);
@@ -0,0 +1,174 @@
1
+ // @flow
2
+
3
+ import shapes from "../shapes.js";
4
+
5
+ import type {Item} from "../item-types.js";
6
+ import type {Shape} from "../shape-types.js";
7
+
8
+ export const simpleQuestionShape: Shape = shapes.shape({
9
+ blurb: shapes.content,
10
+ question: shapes.content,
11
+ hints: shapes.hints,
12
+ });
13
+
14
+ // Shape: simpleQuestionShape
15
+ export const question1: Item = {
16
+ _multi: {
17
+ blurb: {
18
+ __type: "content",
19
+ content: "",
20
+ images: {},
21
+ widgets: {},
22
+ },
23
+ hints: [
24
+ {
25
+ __type: "hint",
26
+ content:
27
+ "If two triangles are congruent, then they have the same side lengths and angle measures.",
28
+ images: {},
29
+ replace: false,
30
+ widgets: {},
31
+ },
32
+ {
33
+ __type: "hint",
34
+ content:
35
+ "A triangle congruent to triangle $ABC$ must also have side lengths of $12$, $14$ and $20$.",
36
+ images: {},
37
+ replace: false,
38
+ widgets: {},
39
+ },
40
+ {
41
+ __type: "hint",
42
+ content:
43
+ "The following triangle is congruent to triangle $ABC$:\n\n* A triangle with side lengths of $12$, $14$, and $20$",
44
+ images: {},
45
+ replace: false,
46
+ widgets: {},
47
+ },
48
+ ],
49
+ question: {
50
+ __type: "content",
51
+ content:
52
+ "Triangle $ABC$ has side lengths of $12$, $14$, and $20$. Which of the following triangles is congruent to triangle $ABC$ ?\n\n[[☃ radio 1]]\n\nEnter the number 3 into this field: [[☃ input-number 1]]",
53
+ widgets: {
54
+ "radio 1": {
55
+ alignment: "default",
56
+ graded: true,
57
+ options: {
58
+ choices: [
59
+ {
60
+ clue: "Congruent triangles have the same side lengths.",
61
+ content:
62
+ "A triangle with side lengths of $3$, $4$, and $5$",
63
+ correct: false,
64
+ },
65
+ {
66
+ clue: "Congruent triangles have the same side lengths.\n\nThis choice is similar to triangle $ABC$.",
67
+ content:
68
+ "A triangle with side lengths of $6$, $7$, and $10$",
69
+ correct: false,
70
+ },
71
+ {
72
+ clue: "Congruent triangles have the same side lengths.",
73
+ content:
74
+ "A triangle with side lengths of $10$, $12$, and $18$",
75
+ correct: false,
76
+ isNoneOfTheAbove: false,
77
+ },
78
+ {
79
+ clue: "Congruent triangles have the same side lengths.",
80
+ content:
81
+ "A triangle with side lengths of $12$, $14$, and $20$",
82
+ correct: true,
83
+ isNoneOfTheAbove: false,
84
+ },
85
+ {
86
+ clue: "Congruent triangles have the same side lengths.\n\nThis choice is similar to triangle $ABC$.",
87
+ content:
88
+ "A triangle with side lengths of $24$, $28$, and $40$",
89
+ correct: false,
90
+ isNoneOfTheAbove: false,
91
+ },
92
+ ],
93
+ countChoices: false,
94
+ deselectEnabled: false,
95
+ displayCount: null,
96
+ hasNoneOfTheAbove: false,
97
+ multipleSelect: false,
98
+ randomize: false,
99
+ },
100
+ static: false,
101
+ type: "radio",
102
+ version: {
103
+ major: 1,
104
+ minor: 0,
105
+ },
106
+ },
107
+ "input-number 1": {
108
+ type: "input-number",
109
+ graded: true,
110
+ options: {
111
+ answerType: "number",
112
+ value: "-42",
113
+ simplify: "required",
114
+ size: "normal",
115
+ inexact: false,
116
+ maxError: 0.1,
117
+ },
118
+ },
119
+ },
120
+ },
121
+ },
122
+ };
123
+
124
+ const mockWidgetConfig = {
125
+ graded: true,
126
+ version: {major: 0, minor: 0},
127
+ static: false,
128
+ type: "mock-widget",
129
+ options: {static: false, smiling: true},
130
+ alignment: "default",
131
+ };
132
+
133
+ // Shape: simpleQuestionShape
134
+ export const mockedQuestion1: Item = {
135
+ _multi: {
136
+ blurb: {
137
+ __type: "content",
138
+ content: "Here's a blurb [[☃ mock-widget 1]]",
139
+ images: {},
140
+ widgets: {
141
+ "mock-widget 1": mockWidgetConfig,
142
+ },
143
+ },
144
+ hints: [
145
+ {
146
+ __type: "hint",
147
+ content: "Hint #1 [[☃ mock-widget 2]]",
148
+ images: {},
149
+ replace: false,
150
+ widgets: {
151
+ "mock-widget 2": mockWidgetConfig,
152
+ },
153
+ },
154
+ {
155
+ __type: "hint",
156
+ content: "Hint #1 [[☃ mock-widget 3]]",
157
+ images: {},
158
+ replace: false,
159
+ widgets: {
160
+ "mock-widget 3": mockWidgetConfig,
161
+ },
162
+ },
163
+ ],
164
+ question: {
165
+ __type: "content",
166
+ content:
167
+ "What is the answer to this?\n\n[[☃ mock-widget 4]]\n\n[[☃ mock-widget 5]]",
168
+ widgets: {
169
+ "mock-widget 4": mockWidgetConfig,
170
+ "mock-widget 5": mockWidgetConfig,
171
+ },
172
+ },
173
+ },
174
+ };