@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,83 @@
1
+ // @flow
2
+ import TexWrangler from "../tex-wrangler.js";
3
+
4
+ const {parseTex, modifyTex} = TexWrangler;
5
+
6
+ const whitespaceRegex = /\s/g;
7
+
8
+ const assertWrangled = (toWrangle, check) => {
9
+ // We ignore whitespace when comparing
10
+ const wrangled = modifyTex(toWrangle).replace(whitespaceRegex, "");
11
+ const checkNoSpace = check.replace(whitespaceRegex, "");
12
+ expect(wrangled).toBe(checkNoSpace);
13
+ };
14
+
15
+ const assertParsed = (toParse, check) => {
16
+ // We ignore whitespace when comparing
17
+ // $FlowFixMe[incompatible-call]
18
+ const parsed = parseTex(toParse).replace(whitespaceRegex, "");
19
+ const checkNoSpace = check.replace(whitespaceRegex, "");
20
+ expect(parsed).toBe(checkNoSpace);
21
+ };
22
+
23
+ describe("modifyTex", () => {
24
+ it("should not touch single fractions", () => {
25
+ assertWrangled("\\frac{3}{4}", "\\frac{3}{4}");
26
+ });
27
+
28
+ it("should make big single fractions small", () => {
29
+ assertWrangled("\\dfrac{3}{4}", "\\frac{3}{4}");
30
+ });
31
+
32
+ it("should make outer fractions big", () => {
33
+ assertWrangled("\\frac{1}{\\frac{2}{3}}", "\\dfrac{1}{\\frac{2}{3}}");
34
+ assertWrangled("\\frac{\\frac{1}{2}}{3}", "\\dfrac{\\frac{1}{2}}{3}");
35
+ });
36
+
37
+ it("should make inner fractions small", () => {
38
+ assertWrangled("\\dfrac{1}{\\dfrac{2}{3}}", "\\dfrac{1}{\\frac{2}{3}}");
39
+ assertWrangled("\\dfrac{\\dfrac{1}{2}}{3}", "\\dfrac{\\frac{1}{2}}{3}");
40
+ });
41
+
42
+ it("should parse mutliple fractions", () => {
43
+ assertWrangled(
44
+ "\\dfrac{1}{2} + \\dfrac{3}{4}",
45
+ "\\frac{1}{2} + \\frac{3}{4}",
46
+ );
47
+ });
48
+
49
+ it("shouldn't touch things before fractions", () => {
50
+ assertWrangled("1 + \\dfrac{2}{3}", "1 + \\frac{2}{3}");
51
+ });
52
+
53
+ it("shouldn't touch things after fractions", () => {
54
+ assertWrangled("\\dfrac{1}{2} + 3", "\\frac{1}{2} + 3");
55
+ });
56
+
57
+ it("shouldn't touch things that wrap fractions", () => {
58
+ assertWrangled("\\sqrt{\\dfrac{1}{2}}", "\\sqrt{\\frac{1}{2}}");
59
+ });
60
+
61
+ it("should have sane failure modes", () => {
62
+ assertWrangled("\\dfrac{3}{4", "\\frac{3}{4}");
63
+ // This could maybe be better, but if someone gives us this and it
64
+ // doesn't work then that's their fault. :)
65
+ assertWrangled("\\dfrac{3}{4}}", "\\frac{3}{4}}");
66
+ });
67
+ });
68
+
69
+ describe("parseTex", () => {
70
+ it("should replace single fractions", () => {
71
+ assertParsed("\\dfrac{3}{4}", "3 / 4");
72
+ });
73
+
74
+ it("should remove blackslash-escapes for percent signs", () => {
75
+ assertParsed("3\\%", "3%");
76
+ assertParsed("3.5\\%", "3.5%");
77
+ assertParsed("\\dfrac{3\\%}{4}", "3% / 4");
78
+ });
79
+
80
+ it("should not throw error when input is undefined", () => {
81
+ assertParsed(undefined, "");
82
+ });
83
+ });
@@ -0,0 +1,41 @@
1
+ // @flow
2
+ import Util from "../util.js";
3
+
4
+ describe("#constrainedTickStepsFromTickSteps", () => {
5
+ it("should not changes the tick steps if there are fewer than (or exactly) 10 steps", () => {
6
+ const result = Util.constrainedTickStepsFromTickSteps(
7
+ [1, 1],
8
+ [
9
+ [0, 10],
10
+ [0, 10],
11
+ ],
12
+ );
13
+
14
+ expect(result).toEqual([1, 1]);
15
+ });
16
+
17
+ it("should should double the tick step size if there are more than 10 but fewer than (or exactly) 20 steps", () => {
18
+ const result = Util.constrainedTickStepsFromTickSteps(
19
+ [1, 1],
20
+ [
21
+ [0, 20],
22
+ [0, 20],
23
+ ],
24
+ );
25
+
26
+ expect(result).toEqual([2, 2]);
27
+ });
28
+
29
+ it("should use the value returned by tickStepFromNumTicks", () => {
30
+ jest.spyOn(Util, "tickStepFromNumTicks").mockReturnValue(5);
31
+ const result = Util.constrainedTickStepsFromTickSteps(
32
+ [1, 1],
33
+ [
34
+ [0, 50],
35
+ [0, 50],
36
+ ],
37
+ );
38
+
39
+ expect(result).toEqual([5, 5]);
40
+ });
41
+ });
package/src/a11y.js ADDED
@@ -0,0 +1,46 @@
1
+ // @flow
2
+ /**
3
+ * Identifies whether or not a given perseus item requires the use of a mouse
4
+ * or screen, based on the widgets it contains.
5
+ */
6
+
7
+ import _ from "underscore";
8
+
9
+ import MultiItems from "./multi-items.js";
10
+ import {traverse} from "./traversal.jsx";
11
+ import * as Widgets from "./widgets.js";
12
+
13
+ const {findContentNodesInItem, inferItemShape} = MultiItems;
14
+
15
+ // Iterate over a single Perseus renderer, mutating `widgets` by appending
16
+ // violating widget types discovered in this item.
17
+ function traverseRenderer(itemData, widgets) {
18
+ traverse(itemData, null, function (info) {
19
+ if (info.type && !Widgets.isAccessible(info)) {
20
+ widgets.push(info.type);
21
+ }
22
+ });
23
+ }
24
+
25
+ // Returns a list of widgets that cause a given perseus item to require
26
+ // the use of a screen or mouse.
27
+ //
28
+ // For now we'll just check the `accessible` field on each of the widgets
29
+ // in the item data, but in the future we may specify accessibility on
30
+ // each widget with higher granularity.
31
+ export function violatingWidgets(itemData: $FlowFixMe): $FlowFixMe {
32
+ // TODO(jordan): Hints as well
33
+ const widgets = [];
34
+
35
+ if (itemData._multi) {
36
+ const shape = inferItemShape(itemData);
37
+ findContentNodesInItem(itemData, shape, (content) =>
38
+ traverseRenderer(content, widgets),
39
+ );
40
+ } else {
41
+ traverseRenderer(itemData.question, widgets);
42
+ }
43
+
44
+ // Uniquify the list of widgets (by type)
45
+ return _.uniq(widgets);
46
+ }
@@ -0,0 +1,9 @@
1
+ // @flow
2
+ import basicWidgets from "./basic-widgets.js";
3
+ import extraWidgets from "./extra-widgets.js";
4
+
5
+ import type {WidgetExports} from "./types.js";
6
+
7
+ export default ([...basicWidgets, ...extraWidgets]: $ReadOnlyArray<
8
+ WidgetExports<>,
9
+ >);
@@ -0,0 +1,215 @@
1
+ // @flow
2
+
3
+ /**
4
+ * An article renderer. Articles are long-form pieces of content,
5
+ * composed of multiple (Renderer) sections concatenated together.
6
+ */
7
+
8
+ import classNames from "classnames";
9
+ import PropTypes from "prop-types";
10
+ import * as React from "react";
11
+
12
+ import Gorgon from "./gorgon/gorgon.js";
13
+ import {linterContextProps, linterContextDefault} from "./gorgon/proptypes.js";
14
+ import ProvideKeypad from "./mixins/provide-keypad.jsx";
15
+ import {ClassNames as ApiClassNames, ApiOptions} from "./perseus-api.jsx";
16
+ import Renderer from "./renderer.jsx";
17
+ import Util from "./util.js";
18
+
19
+ const rendererProps = PropTypes.shape({
20
+ content: PropTypes.string,
21
+ widgets: PropTypes.objectOf(PropTypes.any),
22
+ images: PropTypes.objectOf(PropTypes.any),
23
+ });
24
+
25
+ class ArticleRenderer extends React.Component<$FlowFixMe, $FlowFixMe> {
26
+ _currentFocus: $FlowFixMe;
27
+
28
+ static propTypes = {
29
+ ...ProvideKeypad.propTypes,
30
+ apiOptions: PropTypes.shape({
31
+ onFocusChange: PropTypes.func,
32
+ isMobile: PropTypes.bool,
33
+ }),
34
+ json: PropTypes.oneOfType([
35
+ rendererProps,
36
+ PropTypes.arrayOf(rendererProps),
37
+ ]).isRequired,
38
+
39
+ // Whether to use the new Bibliotron styles for articles
40
+ useNewStyles: PropTypes.bool,
41
+ linterContext: linterContextProps,
42
+ legacyPerseusLint: PropTypes.arrayOf(PropTypes.string),
43
+ };
44
+
45
+ static defaultProps: $FlowFixMe = {
46
+ apiOptions: {},
47
+ useNewStyles: false,
48
+ linterContext: linterContextDefault,
49
+ };
50
+
51
+ constructor(props: $FlowFixMe) {
52
+ super(props);
53
+ this.state = ProvideKeypad.getInitialState.call(this);
54
+ }
55
+
56
+ componentDidMount() {
57
+ ProvideKeypad.componentDidMount.call(this);
58
+ this._currentFocus = null;
59
+ }
60
+
61
+ shouldComponentUpdate(
62
+ nextProps: $FlowFixMe,
63
+ nextState: $FlowFixMe,
64
+ ): $FlowFixMe {
65
+ return nextProps !== this.props || nextState !== this.state;
66
+ }
67
+
68
+ componentWillUnmount() {
69
+ ProvideKeypad.componentWillUnmount.call(this);
70
+ }
71
+
72
+ keypadElement: () => void = () => {
73
+ return ProvideKeypad.keypadElement.call(this);
74
+ };
75
+
76
+ _handleFocusChange: ($FlowFixMe, $FlowFixMe) => void = (
77
+ newFocusPath,
78
+ oldFocusPath,
79
+ ) => {
80
+ // TODO(charlie): DRY this up--some of this logic is repeated in
81
+ // ItemRenderer.
82
+ if (newFocusPath) {
83
+ this._setCurrentFocus(newFocusPath);
84
+ } else {
85
+ this._onRendererBlur(oldFocusPath);
86
+ }
87
+ };
88
+
89
+ _setCurrentFocus: ($FlowFixMe) => void = (newFocusPath) => {
90
+ const keypadElement = this.keypadElement();
91
+
92
+ const prevFocusPath = this._currentFocus;
93
+ this._currentFocus = newFocusPath;
94
+
95
+ // Use the section prefix to extract the relevant Renderer's input
96
+ // paths, so as to check whether the focused path represents an
97
+ // input.
98
+ let didFocusInput = false;
99
+ if (this._currentFocus) {
100
+ const [sectionRef, ...focusPath] = this._currentFocus;
101
+ // eslint-disable-next-line react/no-string-refs
102
+ const inputPaths = this.refs[sectionRef].getInputPaths();
103
+ didFocusInput = inputPaths.some((inputPath) => {
104
+ return Util.inputPathsEqual(inputPath, focusPath);
105
+ });
106
+ }
107
+
108
+ if (this.props.apiOptions.onFocusChange != null) {
109
+ this.props.apiOptions.onFocusChange(
110
+ this._currentFocus,
111
+ prevFocusPath,
112
+ didFocusInput && keypadElement && keypadElement.getDOMNode(),
113
+ );
114
+ }
115
+
116
+ if (keypadElement) {
117
+ if (didFocusInput) {
118
+ keypadElement.activate();
119
+ } else {
120
+ keypadElement.dismiss();
121
+ }
122
+ }
123
+ };
124
+
125
+ _onRendererBlur: ($FlowFixMe) => void = (blurPath) => {
126
+ const blurringFocusPath = this._currentFocus;
127
+
128
+ // Failsafe: abort if ID is different, because focus probably happened
129
+ // before blur.
130
+ if (!Util.inputPathsEqual(blurPath, blurringFocusPath)) {
131
+ return;
132
+ }
133
+
134
+ // Wait until after any new focus events fire this tick before declaring
135
+ // that nothing is focused, since if there were a focus change across
136
+ // sections, we could receive the blur before the focus.
137
+ // TODO(jeff, CP-3128): Use Wonder Blocks Timing API
138
+ // eslint-disable-next-line no-restricted-syntax
139
+ setTimeout(() => {
140
+ if (Util.inputPathsEqual(this._currentFocus, blurringFocusPath)) {
141
+ this._setCurrentFocus(null);
142
+ }
143
+ });
144
+ };
145
+
146
+ blur: () => void = () => {
147
+ if (this._currentFocus) {
148
+ const [sectionRef, ...inputPath] = this._currentFocus;
149
+ // eslint-disable-next-line react/no-string-refs
150
+ this.refs[sectionRef].blurPath(inputPath);
151
+ }
152
+ };
153
+
154
+ _sections: () => $FlowFixMe = () => {
155
+ return Array.isArray(this.props.json)
156
+ ? this.props.json
157
+ : [this.props.json];
158
+ };
159
+
160
+ render(): React.Node {
161
+ const apiOptions = {
162
+ ...ApiOptions.defaults,
163
+ ...this.props.apiOptions,
164
+ isArticle: true,
165
+ };
166
+
167
+ const classes = classNames({
168
+ "framework-perseus": true,
169
+ "perseus-article": true,
170
+ "bibliotron-article": this.props.useNewStyles,
171
+ // NOTE(charlie): For exercises, this is applied outside of Perseus
172
+ // (in webapp).
173
+ [ApiClassNames.MOBILE]: apiOptions.isMobile,
174
+ });
175
+
176
+ // TODO(alex): Add mobile api functions and pass them down here
177
+ const sections = this._sections().map((section, i) => {
178
+ const refForSection = `section-${i}`;
179
+ return (
180
+ <div key={i} className="clearfix">
181
+ <Renderer
182
+ {...section}
183
+ ref={refForSection}
184
+ key={i}
185
+ key_={i}
186
+ keypadElement={this.keypadElement()}
187
+ apiOptions={{
188
+ ...apiOptions,
189
+ onFocusChange: (newFocusPath, oldFocusPath) => {
190
+ // Prefix the paths with the relevant section,
191
+ // so as to allow us to distinguish between
192
+ // equivalently-named inputs across Renderers.
193
+ this._handleFocusChange(
194
+ newFocusPath &&
195
+ [refForSection].concat(newFocusPath),
196
+ oldFocusPath &&
197
+ [refForSection].concat(oldFocusPath),
198
+ );
199
+ },
200
+ }}
201
+ linterContext={Gorgon.pushContextStack(
202
+ this.props.linterContext,
203
+ "article",
204
+ )}
205
+ legacyPerseusLint={this.props.legacyPerseusLint}
206
+ />
207
+ </div>
208
+ );
209
+ });
210
+
211
+ return <div className={classes}>{sections}</div>;
212
+ }
213
+ }
214
+
215
+ export default ArticleRenderer;
@@ -0,0 +1,30 @@
1
+ // @flow
2
+ /**
3
+ * A React context for keeping track of whether an component is fully
4
+ * loaded. This is used to know when SvgImage and (Zoomable)TeX are finished
5
+ * renderering.
6
+ */
7
+
8
+ import * as React from "react";
9
+
10
+ type Context = {
11
+ // A dictionary of asset statues. See server-item-renderer.jsx for
12
+ // an example of its definition.
13
+ assetStatuses: {[assetKey: string]: boolean, ...},
14
+ // setAssetStatus(key, false) must be called in the constructor of
15
+ // any component which isn't fully rendered on initial render. This
16
+ // adds the asset key to asssetStatuses, see server-item-renderer.jsx.
17
+ // setAssetStatus(key, true) must be called when the component has
18
+ // fully rendered itself. See svg-image.jsx and tex.jsx.
19
+ setAssetStatus: (assetKey: string, loaded: boolean) => void,
20
+ ...
21
+ };
22
+
23
+ const defaultContext: Context = {
24
+ assetStatuses: {},
25
+ setAssetStatus: (assetKey: string, loaded: boolean) => {},
26
+ };
27
+
28
+ const context: React.Context<Context> = React.createContext(defaultContext);
29
+
30
+ export default context;
@@ -0,0 +1,13 @@
1
+ // @flow
2
+ // As new widgets get added here, please also make sure they get added in
3
+ // content_internal/perseus_traversal.py so they can be properly translated.
4
+ import Expression from "./widgets/expression.jsx";
5
+ import InputNumber from "./widgets/input-number.jsx";
6
+ import NumericInput from "./widgets/numeric-input.jsx";
7
+ import Radio from "./widgets/radio.jsx";
8
+
9
+ import type {WidgetExports} from "./types.js";
10
+
11
+ export default ([Radio, InputNumber, NumericInput, Expression]: $ReadOnlyArray<
12
+ WidgetExports<>,
13
+ >);
@@ -0,0 +1,61 @@
1
+ // @flow
2
+
3
+ import * as React from "react";
4
+
5
+ import ButtonGroup from "../button-group.jsx";
6
+
7
+ type StoryArgs = {||};
8
+
9
+ type Story = {|
10
+ title: string,
11
+ |};
12
+
13
+ export default ({
14
+ title: "Perseus/Components/Button Group",
15
+ }: Story);
16
+
17
+ const HarnassedButtonGroup = (
18
+ props: $Rest<
19
+ React.ElementConfig<typeof ButtonGroup>,
20
+ {|
21
+ value: React.ElementConfig<typeof ButtonGroup>["value"],
22
+ onChange: React.ElementConfig<typeof ButtonGroup>["onChange"],
23
+ |},
24
+ >,
25
+ ) => {
26
+ const [value, updateValue] = React.useState((null: ?string));
27
+
28
+ return (
29
+ <ButtonGroup
30
+ {...props}
31
+ value={value}
32
+ onChange={(newValue) => {
33
+ updateValue(newValue);
34
+ }}
35
+ />
36
+ );
37
+ };
38
+
39
+ export const ButtonsWithNoTitles = (args: StoryArgs): React.Node => {
40
+ return (
41
+ <HarnassedButtonGroup
42
+ buttons={[
43
+ {value: "One", content: "Item #1"},
44
+ {value: "Two", content: "Item #2"},
45
+ {value: "Three", content: "Item #3"},
46
+ ]}
47
+ />
48
+ );
49
+ };
50
+
51
+ export const ButtonsWithTitles = (args: StoryArgs): React.Node => {
52
+ return (
53
+ <HarnassedButtonGroup
54
+ buttons={[
55
+ {value: "One", content: "Item #1", title: "The first item"},
56
+ {value: "Two", content: "Item #2", title: "The second item"},
57
+ {value: "Three", content: "Item #3", title: "The third item"},
58
+ ]}
59
+ />
60
+ );
61
+ };
@@ -0,0 +1,132 @@
1
+ // @flow
2
+ import * as React from "react";
3
+
4
+ import {getDependencies} from "../../dependencies.js";
5
+ import FixedToResponsive from "../fixed-to-responsive.jsx";
6
+
7
+ type StoryArgs = {||};
8
+
9
+ type Story = {|
10
+ title: string,
11
+ |};
12
+
13
+ const svgUrl = "https://www.khanacademy.org/images/ohnoes-concerned.svg";
14
+ const imgUrl = "https://www.khanacademy.org/images/hand-tree.new.png";
15
+
16
+ const sizeSmall = 200;
17
+ const sizeMedium = 600;
18
+ const sizeLarge = 1024;
19
+ const width = 1024;
20
+
21
+ export default ({
22
+ title: "Perseus/Components/Fixed to Responsive",
23
+ }: Story);
24
+
25
+ export const SmallImageWithSmallContainer = (args: StoryArgs): React.Node => {
26
+ return (
27
+ <FixedToResponsive width={width} height={sizeSmall}>
28
+ <img
29
+ alt=""
30
+ width={sizeSmall}
31
+ height={sizeSmall}
32
+ src={getDependencies().staticUrl(svgUrl)}
33
+ />
34
+ </FixedToResponsive>
35
+ );
36
+ };
37
+
38
+ export const SmallImageWithMediumContainer = (args: StoryArgs): React.Node => {
39
+ return (
40
+ <FixedToResponsive width={width} height={sizeMedium}>
41
+ <img
42
+ alt=""
43
+ width={sizeMedium}
44
+ height={sizeMedium}
45
+ src={getDependencies().staticUrl(svgUrl)}
46
+ />
47
+ </FixedToResponsive>
48
+ );
49
+ };
50
+
51
+ export const LargeImageWithLargeContainer = (args: StoryArgs): React.Node => {
52
+ return (
53
+ <FixedToResponsive width={width} height={sizeLarge}>
54
+ <img
55
+ alt=""
56
+ width={sizeLarge}
57
+ height={sizeLarge}
58
+ src={getDependencies().staticUrl(svgUrl)}
59
+ />
60
+ </FixedToResponsive>
61
+ );
62
+ };
63
+
64
+ export const LargeImageWithSmallerContainer = (args: StoryArgs): React.Node => {
65
+ return (
66
+ <FixedToResponsive width={width} height={sizeSmall}>
67
+ <img
68
+ alt=""
69
+ width={sizeLarge}
70
+ height={sizeLarge}
71
+ src={getDependencies().staticUrl(svgUrl)}
72
+ />
73
+ </FixedToResponsive>
74
+ );
75
+ };
76
+
77
+ export const TwoOverlayedImagesInsteadOneResponsiveContainer = (
78
+ args: StoryArgs,
79
+ ): React.Node => {
80
+ return (
81
+ <FixedToResponsive width={width} height={sizeSmall}>
82
+ <img
83
+ alt=""
84
+ key={1}
85
+ width={sizeSmall}
86
+ height={sizeSmall}
87
+ src={imgUrl}
88
+ />
89
+ <img
90
+ alt=""
91
+ key={2}
92
+ width={sizeSmall}
93
+ height={sizeSmall}
94
+ src={getDependencies().staticUrl(svgUrl)}
95
+ />
96
+ </FixedToResponsive>
97
+ );
98
+ };
99
+
100
+ export const HeightConstrainingAnImage = (args: StoryArgs): React.Node => {
101
+ return (
102
+ <FixedToResponsive
103
+ width={width}
104
+ height={sizeLarge}
105
+ constrainHeight={true}
106
+ >
107
+ <img
108
+ alt=""
109
+ width={sizeLarge}
110
+ height={sizeLarge}
111
+ src={getDependencies().staticUrl(svgUrl)}
112
+ />
113
+ </FixedToResponsive>
114
+ );
115
+ };
116
+
117
+ export const AllowingFullBleed = (args: StoryArgs): React.Node => {
118
+ return (
119
+ <FixedToResponsive
120
+ width={width}
121
+ height={sizeMedium}
122
+ allowFullBleed={true}
123
+ >
124
+ <img
125
+ alt=""
126
+ width={sizeMedium}
127
+ height={sizeMedium}
128
+ src={getDependencies().staticUrl(svgUrl)}
129
+ />
130
+ </FixedToResponsive>
131
+ );
132
+ };
@@ -0,0 +1,27 @@
1
+ // @flow
2
+ import * as React from "react";
3
+
4
+ import Graph from "../graph.jsx";
5
+ // TODO(scottgrant): Katex is unavailable here. Fix!
6
+
7
+ type StoryArgs = {||};
8
+
9
+ type Story = {|
10
+ title: string,
11
+ |};
12
+
13
+ const size = 200;
14
+
15
+ export default ({
16
+ title: "Perseus/Components/Graph",
17
+ }: Story);
18
+
19
+ export const SquareBoxSizeAndOtherwiseEmpty = (args: StoryArgs): React.Node => {
20
+ return <Graph box={[size, size]} />;
21
+ };
22
+
23
+ export const LabeledSquaredBox = (args: StoryArgs): React.Node => {
24
+ return (
25
+ <Graph box={[size, size]} labels={["First label", "Second label"]} />
26
+ );
27
+ };
@@ -0,0 +1,28 @@
1
+ // @flow
2
+ import * as React from "react";
3
+
4
+ import Graphie from "../graphie.jsx";
5
+
6
+ type StoryArgs = {||};
7
+
8
+ type Story = {|
9
+ title: string,
10
+ |};
11
+
12
+ const size = 200;
13
+
14
+ export default ({
15
+ title: "Perseus/Components/Graphie",
16
+ }: Story);
17
+
18
+ export const SquareBoxSizeAndOtherwiseEmpty = (args: StoryArgs): React.Node => {
19
+ return (
20
+ <Graphie
21
+ box={[size, size]}
22
+ setDrawingAreaAvailable={() => {}}
23
+ setup={() => {}}
24
+ />
25
+ );
26
+ };
27
+
28
+ //TODO(scottgrant): Add a wider range of stories here