@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,127 @@
1
+ .draggy-boxy-thing-hover (@color: #ffa500) {
2
+ border-color: @color;
3
+ @darker: darken(@color, 11%);
4
+ box-shadow: 0 0 4px @darker;
5
+ -moz-box-shadow: 0 0 4px @darker;
6
+ -ms-box-shadow: 0 0 4px @darker;
7
+ -o-box-shadow: 0 0 4px @darker;
8
+ -webkit-box-shadow: 0 0 4px @darker;
9
+ }
10
+
11
+ .draggy-boxy-thing {
12
+ .draggable-box,
13
+ .cards-area {
14
+ background: #eee;
15
+ border: 1px solid #ccc;
16
+ border-bottom: 1px solid #aaa;
17
+
18
+ box-shadow: 0 1px 2px #ccc;
19
+ -moz-box-shadow: 0 1px 2px #ccc;
20
+ -webkit-box-shadow: 0 1px 2px #ccc;
21
+ }
22
+
23
+ // TODO(jack): Make this work for the orderer too.
24
+ // Right now don't do this for the orderer because it uses
25
+ // more complicated positioning that this would break
26
+ .cards-area {
27
+ .above-scratchpad;
28
+ }
29
+
30
+ .card {
31
+ .perseus-interactive;
32
+
33
+ background-color: #fff;
34
+ border: 1px solid #b9b9b9;
35
+ border-bottom-color: #939393;
36
+ border-radius: 4px;
37
+ -moz-border-radius: 4px;
38
+ -webkit-border-radius: 4px;
39
+ -webkit-user-select: none;
40
+ -khtml-user-select: none;
41
+ -moz-user-select: none;
42
+ -o-user-select: none;
43
+ cursor: pointer;
44
+ touch-action: none;
45
+
46
+ &.placeholder {
47
+ background:#ddd;
48
+ border: 1px solid #ccc;
49
+ }
50
+
51
+ &.drag-hint {
52
+ background: none;
53
+ border: 1px dashed #aaa;
54
+ cursor: auto;
55
+
56
+ &:hover {
57
+ border-color: #aaa;
58
+ box-shadow: none;
59
+ }
60
+ }
61
+
62
+ &.dragging {
63
+ background-color: #ffedcd;
64
+ opacity: 0.8;
65
+ filter: opacity(0.8);
66
+ }
67
+
68
+ &.stack {
69
+ z-index: auto;
70
+ &:after {
71
+ content: " ";
72
+ background-color: #fff;
73
+ border: 1px solid #b9b9b9;
74
+ border-bottom-color: #939393;
75
+ border-radius: 4px;
76
+ -moz-border-radius: 4px;
77
+ -webkit-border-radius: 4px;
78
+ height: 100%;
79
+ width: 100%;
80
+ z-index: -1;
81
+ top: 1px;
82
+ left: 1px;
83
+ position: absolute;
84
+ }
85
+ }
86
+
87
+ &:hover {
88
+ .draggy-boxy-thing-hover();
89
+ }
90
+ }
91
+ }
92
+
93
+ // TODO(benkomalo): ideally all of these would be removed as all of the other
94
+ // sortable styles have been moved to inline styles using Aphrodite. However,
95
+ // these are all hacky styles that reach down into descendents in ways that
96
+ // they probably shouldn't, so Aphrodite doesn't support it. This will require
97
+ // a larger refactoring to wire down options to nested `Renderer`s so they can
98
+ // have their styling modified.
99
+ .perseus-sortable {
100
+ div.paragraph {
101
+ margin: 0;
102
+ }
103
+
104
+ .perseus-sortable-draggable {
105
+ &:before {
106
+ // Vertical-align, part 1
107
+ content: "";
108
+ display: inline-block;
109
+ height: 100%;
110
+ vertical-align: middle;
111
+ }
112
+
113
+ & > div {
114
+ // Vertical-align, part 2
115
+ display: inline-block;
116
+ font-size: 14px;
117
+ max-width: 100%;
118
+ vertical-align: middle;
119
+ }
120
+ }
121
+
122
+ .perseus-sortable-draggable-unpadded {
123
+ img {
124
+ vertical-align: bottom;
125
+ }
126
+ }
127
+ }
@@ -0,0 +1,56 @@
1
+ // Extra specifity is needed to counteract generic tables
2
+ .framework-perseus table.perseus-widget-table-of-values.non-markdown {
3
+ text-align: left;
4
+ margin: 20px auto;
5
+ border-collapse: collapse;
6
+
7
+ tr {
8
+ height: 23px;
9
+ }
10
+
11
+ th, td {
12
+ border: 2px solid black;
13
+ border-width: 0 2px;
14
+
15
+ &:first-child {
16
+ border-left: 0;
17
+ }
18
+
19
+ &:last-child {
20
+ border-right: 0;
21
+ }
22
+ }
23
+
24
+ th {
25
+ font-weight: normal;
26
+ padding: 5px;
27
+ width: 80px;
28
+ text-align: left;
29
+ border-bottom: 2px solid black;
30
+ .paragraph {
31
+ margin: 0;
32
+ }
33
+ }
34
+
35
+ td {
36
+ padding: 0px 5px;
37
+ }
38
+
39
+ tbody tr:first-child td {
40
+ padding-top: 5px;
41
+ }
42
+ }
43
+ .framework-perseus table.perseus-widget-table-of-values input,
44
+ #answer_area table.perseus-widget-table-of-values input {
45
+ // NOTE(charlie): This should be kept in-sync with the "width: 80" in
46
+ // table.jsx.
47
+ width: 80px;
48
+ }
49
+
50
+ body.mobile {
51
+ .framework-perseus table.perseus-widget-table-of-values.non-markdown {
52
+ td {
53
+ padding: 5px;
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,28 @@
1
+ .perseus-widget-transformer {
2
+ .highlighted-tool-button {
3
+ text-shadow: 1px 1px rgba(0, 0, 0, 0.25);
4
+ }
5
+ > .graphie-container {
6
+ margin-bottom: 10px;
7
+ position: relative;
8
+ overflow: hidden;
9
+
10
+ > img, > .unresponsive-svg-image {
11
+ position: absolute;
12
+ // Preserves background image alignment (if image is a graph,
13
+ // it can extend up and to the right to allow for axis labels)
14
+ bottom: 0;
15
+ left: 0;
16
+ }
17
+ }
18
+ .transformer-undo-button {
19
+ float: right;
20
+ }
21
+ .perseus-transformation-list {
22
+ input {
23
+ width: 40px;
24
+ }
25
+ margin-top: 10px;
26
+ margin-bottom: 10px;
27
+ }
28
+ }
@@ -0,0 +1,14 @@
1
+ .old-unit-input input, .unit-editor-canonical {
2
+ border: 1px solid #a4a4a4;
3
+ border-radius: 5px;
4
+ // box-sizing: border-box;
5
+ font-size: 14px;
6
+ // margin-bottom: 5px;
7
+ // max-width: 240px;
8
+ padding: 6px;
9
+ // width: 100%;
10
+ }
11
+
12
+ .unit-editor > div {
13
+ margin: 5px 0;
14
+ }
@@ -0,0 +1,176 @@
1
+ // @flow
2
+ /*
3
+ * In this file, an `expression` is some portion of valid TeX enclosed in
4
+ * curly brackets.
5
+ */
6
+
7
+ /*
8
+ * Find the index at which an expression ends, i.e., has an unmatched
9
+ * closing curly bracket. This method assumes that we start with a non-open
10
+ * bracket character and end when we've seen more left than right brackets
11
+ * (rather than assuming that we start with a bracket character and wait for
12
+ * bracket equality).
13
+ */
14
+ function findEndpoint(tex, currentIndex) {
15
+ let bracketDepth = 0;
16
+
17
+ for (let i = currentIndex, len = tex.length; i < len; i++) {
18
+ const c = tex[i];
19
+
20
+ if (c === "{") {
21
+ bracketDepth++;
22
+ } else if (c === "}") {
23
+ bracketDepth--;
24
+ }
25
+
26
+ if (bracketDepth < 0) {
27
+ return i;
28
+ }
29
+ }
30
+ // If we never see unbalanced curly brackets, default to the
31
+ // entire string
32
+ return tex.length;
33
+ }
34
+
35
+ /*
36
+ * Parses an individual set of curly brackets into TeX.
37
+ */
38
+ function parseNextExpression(tex, currentIndex, handler) {
39
+ // Find the first '{' and grab subsequent TeX
40
+ // Ex) tex: '{3}{7}', and we want the '3'
41
+ const openBracketIndex = tex.indexOf("{", currentIndex);
42
+ const nextExpIndex = openBracketIndex + 1;
43
+
44
+ // Truncate to only contain remaining TeX
45
+ const endpoint = findEndpoint(tex, nextExpIndex);
46
+ const expressionTeX = tex.substring(nextExpIndex, endpoint);
47
+ const parsedExp = walkTex(expressionTeX, handler);
48
+
49
+ return {
50
+ endpoint: endpoint,
51
+ expression: parsedExp,
52
+ };
53
+ }
54
+
55
+ function getNextFracIndex(tex, currentIndex) {
56
+ const dfrac = "\\dfrac";
57
+ const frac = "\\frac";
58
+
59
+ const nextFrac = tex.indexOf(frac, currentIndex);
60
+ const nextDFrac = tex.indexOf(dfrac, currentIndex);
61
+
62
+ if (nextFrac > -1 && nextDFrac > -1) {
63
+ return Math.min(nextFrac, nextDFrac);
64
+ }
65
+ if (nextFrac > -1) {
66
+ return nextFrac;
67
+ }
68
+ if (nextDFrac > -1) {
69
+ return nextDFrac;
70
+ }
71
+ return -1;
72
+ }
73
+
74
+ function walkTex(tex: string, handler): string {
75
+ if (!tex) {
76
+ return "";
77
+ }
78
+
79
+ // Ex) tex: '2 \dfrac {3}{7}'
80
+ let parsedString = "";
81
+ let currentIndex = 0;
82
+ let nextFrac = getNextFracIndex(tex, currentIndex);
83
+
84
+ // For each \dfrac, find the two expressions (wrapped in {}) and recur
85
+ while (nextFrac > -1) {
86
+ // Gather first fragment, preceding \dfrac
87
+ // Ex) parsedString: '2 '
88
+ parsedString += tex.substring(currentIndex, nextFrac);
89
+
90
+ // Remove everything preceding \dfrac, which has been parsed
91
+ currentIndex = nextFrac;
92
+
93
+ // Parse first expression and move index past it
94
+ // Ex) firstParsedExpression.expression: '3'
95
+ const firstParsedExpression = parseNextExpression(
96
+ tex,
97
+ currentIndex,
98
+ handler,
99
+ );
100
+ currentIndex = firstParsedExpression.endpoint + 1;
101
+
102
+ // Parse second expression
103
+ // Ex) secondParsedExpression.expression: '7'
104
+ const secondParsedExpression = parseNextExpression(
105
+ tex,
106
+ currentIndex,
107
+ handler,
108
+ );
109
+ currentIndex = secondParsedExpression.endpoint + 1;
110
+
111
+ // Add expressions to running total of parsed expressions
112
+ if (parsedString.length) {
113
+ parsedString += " ";
114
+ }
115
+
116
+ // Apply a custom handler based on the parsed subexpressions
117
+ parsedString += handler(
118
+ firstParsedExpression.expression,
119
+ secondParsedExpression.expression,
120
+ );
121
+
122
+ // Find next DFrac, relative to currentIndex
123
+ nextFrac = getNextFracIndex(tex, currentIndex);
124
+ }
125
+
126
+ // Add remaining TeX, which is \dfrac-free
127
+ parsedString += tex.slice(currentIndex);
128
+
129
+ return parsedString;
130
+ }
131
+
132
+ /*
133
+ * Modify a TeX expression, returning another TeX expression. The resulting
134
+ * expression will have its innermost fractions stubbed out with \fracs
135
+ * (as opposed to \dfracs). All other content will remain untouched.
136
+ */
137
+ function modifyTex(tex: string): string {
138
+ function isNestedFraction(tex) {
139
+ return tex.indexOf("\\frac") > -1 || tex.indexOf("\\dfrac") > -1;
140
+ }
141
+ const handler = function (exp1, exp2) {
142
+ let prefix;
143
+ if (isNestedFraction(exp1) || isNestedFraction(exp2)) {
144
+ prefix = "\\dfrac";
145
+ } else {
146
+ prefix = "\\frac";
147
+ }
148
+ return prefix + " {" + exp1 + "}{" + exp2 + "}";
149
+ };
150
+ return walkTex(tex, handler);
151
+ }
152
+
153
+ /*
154
+ * Parse a TeX expression into something interpretable by input-number.
155
+ * The process is concerned with: (1) parsing fractions, i.e., \dfracs; and
156
+ * (2) removing backslash-escaping from certain characters (right now, only
157
+ * percent signs).
158
+ *
159
+ * The basic algorithm for handling \dfracs splits on \dfracs and then recurs
160
+ * on the subsequent "expressions", i.e., the {} pairs that follow \dfrac. The
161
+ * recursion is to allow for nested \dfrac elements.
162
+ *
163
+ * Backslash-escapes are removed with a simple search-and-replace.
164
+ */
165
+ function parseTex(tex: string): string {
166
+ const handler = function (exp1, exp2) {
167
+ return exp1 + "/" + exp2;
168
+ };
169
+ const texWithoutFracs = walkTex(tex, handler);
170
+ return texWithoutFracs.replace("\\%", "%");
171
+ }
172
+
173
+ export default {
174
+ parseTex,
175
+ modifyTex,
176
+ };
@@ -0,0 +1,141 @@
1
+ // @flow
2
+ /**
3
+ * Traverses a {content, widgets, images} renderer props object,
4
+ * such as `itemData.question`
5
+ *
6
+ * This traversal is deep and handles some widget prop upgrades
7
+ * (TODO(aria): Handle minor prop upgrades :) )
8
+ *
9
+ * This is the right way to traverse itemData.
10
+ *
11
+ * NOTE: We should not expose this on the perseus API yet. Instead,
12
+ * build the traversal method you want inside perseus, and use this
13
+ * from that. We might eventually expose this, but I'd like to be
14
+ * more confident in the interface provided first.
15
+ */
16
+
17
+ import _ from "underscore";
18
+
19
+ // TODO(aria): Pull this out of interactive2 / replace with new _.mapObject
20
+ import objective_ from "./interactive2/objective_.js";
21
+ import * as Widgets from "./widgets.js";
22
+
23
+ const noop = function () {};
24
+
25
+ const deepCallbackFor = function (
26
+ contentCallback: ($FlowFixMe) => void,
27
+ widgetCallback: (widgetInfo: $FlowFixMe, widgetId: string) => $FlowFixMe,
28
+ optionsCallback: ($FlowFixMe) => void,
29
+ ) {
30
+ const deepCallback = function (widgetInfo, widgetId) {
31
+ // This doesn't modify the widget info if the widget info
32
+ // is at a later version than is supported, which is important
33
+ // for our latestVersion test below.
34
+ const upgradedWidgetInfo =
35
+ Widgets.upgradeWidgetInfoToLatestVersion(widgetInfo);
36
+ const latestVersion = Widgets.getVersion(upgradedWidgetInfo.type);
37
+
38
+ // Only traverse our children if we can understand this version
39
+ // of the widget props.
40
+ // TODO(aria): This will break if the traversal code assumes that
41
+ // any props that usually get defaulted in are present. That is,
42
+ // it can fail on minor version upgrades.
43
+ // For this reason, and because the upgrade code doesn't handle
44
+ // minor versions correctly (it doesn't report anything useful
45
+ // about what minor version a widget is actually at, since it
46
+ // doesn't have meaning in the context of upgrades), we
47
+ // just check the major version here.
48
+ // TODO(aria): This is seriously quirky and would be unpleasant
49
+ // to think about while writing traverseChildWidgets code. Please
50
+ // make all of this a little tighter.
51
+ // I think once we use react class defaultProps instead of relying
52
+ // on getDefaultProps, this will become easier.
53
+ let newWidgetInfo;
54
+ if (
55
+ latestVersion &&
56
+ upgradedWidgetInfo.version?.major === latestVersion.major
57
+ ) {
58
+ newWidgetInfo = Widgets.traverseChildWidgets(
59
+ upgradedWidgetInfo,
60
+ (rendererOptions) => {
61
+ return traverseRenderer(
62
+ rendererOptions,
63
+ contentCallback,
64
+ // so that we traverse grandchildren, too:
65
+ deepCallback,
66
+ optionsCallback,
67
+ );
68
+ },
69
+ );
70
+ } else {
71
+ newWidgetInfo = upgradedWidgetInfo;
72
+ }
73
+
74
+ const userWidgetInfo = widgetCallback(newWidgetInfo, widgetId);
75
+ if (userWidgetInfo !== undefined) {
76
+ return userWidgetInfo;
77
+ }
78
+ return newWidgetInfo;
79
+ };
80
+ return deepCallback;
81
+ };
82
+
83
+ const traverseRenderer = function (
84
+ rendererOptions,
85
+ contentCallback: ($FlowFixMe) => void,
86
+ deepWidgetCallback: (
87
+ widgetInfo: $FlowFixMe,
88
+ widgetId: string,
89
+ ) => $FlowFixMe,
90
+ optionsCallback: ($FlowFixMe) => void,
91
+ ) {
92
+ let newContent = rendererOptions.content;
93
+ if (rendererOptions.content != null) {
94
+ const modifiedContent = contentCallback(rendererOptions.content);
95
+ if (modifiedContent !== undefined) {
96
+ newContent = modifiedContent;
97
+ }
98
+ }
99
+
100
+ const newWidgets = objective_.mapObject(
101
+ rendererOptions.widgets || {},
102
+ function (widgetInfo, widgetId) {
103
+ // Widgets without info or a type are empty widgets, and
104
+ // should always be renderable. It's also annoying to write
105
+ // checks for this everywhere, so we just filter them out once and
106
+ // for all!
107
+ if (widgetInfo == null || widgetInfo.type == null) {
108
+ return widgetInfo;
109
+ }
110
+ return deepWidgetCallback(widgetInfo, widgetId);
111
+ },
112
+ );
113
+
114
+ const newOptions = _.extend({}, rendererOptions, {
115
+ content: newContent,
116
+ widgets: newWidgets,
117
+ });
118
+ const userOptions = optionsCallback(newOptions);
119
+ if (userOptions !== undefined) {
120
+ return userOptions;
121
+ }
122
+ return newOptions;
123
+ };
124
+
125
+ export const traverse = function (
126
+ rendererOptions: $FlowFixMe,
127
+ contentCallback?: ?($FlowFixMe) => $FlowFixMe,
128
+ widgetCallback?: ?(widgetInfo: $FlowFixMe, widgetId: string) => $FlowFixMe,
129
+ optionsCallback?: ($FlowFixMe) => void,
130
+ ): $FlowFixMe {
131
+ contentCallback = contentCallback || noop;
132
+ widgetCallback = widgetCallback || noop;
133
+ optionsCallback = optionsCallback || noop;
134
+
135
+ return traverseRenderer(
136
+ rendererOptions,
137
+ contentCallback,
138
+ deepCallbackFor(contentCallback, widgetCallback, optionsCallback),
139
+ optionsCallback,
140
+ );
141
+ };