@khanacademy/perseus 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/.babelrc.js +1 -1
  2. package/CHANGELOG.md +7 -0
  3. package/dist/es/index.js +15 -1
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.css +11934 -0
  6. package/dist/index.js +15 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/strings.js +148 -1
  9. package/package.json +40 -4
  10. package/src/README.md +7 -0
  11. package/src/__stories__/item-renderer.stories.jsx +27 -0
  12. package/src/__stories__/server-item-renderer.stories.jsx +27 -0
  13. package/src/__testdata__/item-renderer_testdata.js +161 -0
  14. package/src/__testdata__/renderer_testdata.js +123 -0
  15. package/src/__tests__/__snapshots__/item-renderer_test.jsx.snap +233 -0
  16. package/src/__tests__/__snapshots__/perseus-markdown_test.jsx.snap +516 -0
  17. package/src/__tests__/__snapshots__/pure-markdown_test.js.snap +113 -0
  18. package/src/__tests__/__snapshots__/renderer_test.jsx.snap +576 -0
  19. package/src/__tests__/__snapshots__/server-item-renderer_test.jsx.snap +306 -0
  20. package/src/__tests__/a11y_test.jsx +304 -0
  21. package/src/__tests__/item-renderer_test.jsx +892 -0
  22. package/src/__tests__/mock-asset-loading-widget.jsx +57 -0
  23. package/src/__tests__/mock-widget.jsx +35 -0
  24. package/src/__tests__/perseus-markdown_test.jsx +747 -0
  25. package/src/__tests__/pure-markdown_test.js +552 -0
  26. package/src/__tests__/renderability_test.jsx +481 -0
  27. package/src/__tests__/renderer-api_test.jsx +333 -0
  28. package/src/__tests__/renderer_test.jsx +1792 -0
  29. package/src/__tests__/server-item-renderer_test.jsx +516 -0
  30. package/src/__tests__/test-items/image-item.js +25 -0
  31. package/src/__tests__/test-items/input-number-1-item.js +27 -0
  32. package/src/__tests__/test-items/input-number-2-item.js +39 -0
  33. package/src/__tests__/test-items/table-item.js +30 -0
  34. package/src/__tests__/tex-wrangler_test.js +83 -0
  35. package/src/__tests__/util_test.js +41 -0
  36. package/src/a11y.js +46 -0
  37. package/src/all-widgets.js +9 -0
  38. package/src/article-renderer.jsx +215 -0
  39. package/src/asset-context.js +30 -0
  40. package/src/basic-widgets.js +13 -0
  41. package/src/components/__stories__/button-group.stories.jsx +61 -0
  42. package/src/components/__stories__/fixed-to-responsive.stories.jsx +132 -0
  43. package/src/components/__stories__/graph.stories.jsx +27 -0
  44. package/src/components/__stories__/graphie.stories.jsx +28 -0
  45. package/src/components/__stories__/hud.stories.jsx +36 -0
  46. package/src/components/__stories__/icon.stories.jsx +56 -0
  47. package/src/components/__stories__/image-loader.stories.jsx +60 -0
  48. package/src/components/__stories__/info-tip.stories.jsx +33 -0
  49. package/src/components/__stories__/inline-icon.stories.jsx +39 -0
  50. package/src/components/__stories__/input-with-examples.stories.jsx +51 -0
  51. package/src/components/__stories__/lint.stories.jsx +40 -0
  52. package/src/components/__stories__/math-input.stories.jsx +29 -0
  53. package/src/components/__stories__/math-output.stories.jsx +24 -0
  54. package/src/components/__stories__/multi-button-group.stories.jsx +69 -0
  55. package/src/components/__stories__/number-input.stories.jsx +42 -0
  56. package/src/components/__stories__/possible-answers.stories.jsx +22 -0
  57. package/src/components/__stories__/prop-check-box.stories.jsx +62 -0
  58. package/src/components/__stories__/range-input.stories.jsx +28 -0
  59. package/src/components/__stories__/simple-keypad-input.stories.jsx +28 -0
  60. package/src/components/__stories__/sortable.stories.jsx +73 -0
  61. package/src/components/__stories__/stub-tag-editor.stories.jsx +44 -0
  62. package/src/components/__stories__/svg-image.stories.jsx +60 -0
  63. package/src/components/__stories__/tex.stories.jsx +18 -0
  64. package/src/components/__stories__/text-buttons.stories.jsx +51 -0
  65. package/src/components/__stories__/text-input.stories.jsx +34 -0
  66. package/src/components/__stories__/text-list-editor.stories.jsx +33 -0
  67. package/src/components/__stories__/zoomable-tex.stories.jsx +39 -0
  68. package/src/components/__stories__/zoomable.stories.jsx +40 -0
  69. package/src/components/__testdata__/sorter_testdata.js +20 -0
  70. package/src/components/__tests__/__snapshots__/sortable_test.jsx.snap +79 -0
  71. package/src/components/__tests__/__snapshots__/sorter_test.jsx.snap +297 -0
  72. package/src/components/__tests__/number-input_test.jsx +112 -0
  73. package/src/components/__tests__/sortable_test.jsx +234 -0
  74. package/src/components/__tests__/sorter_test.jsx +111 -0
  75. package/src/components/__tests__/zoomable_test.jsx +388 -0
  76. package/src/components/button-group.jsx +131 -0
  77. package/src/components/constants.js +15 -0
  78. package/src/components/fixed-to-responsive.jsx +163 -0
  79. package/src/components/graph.jsx +414 -0
  80. package/src/components/graphie-classes.jsx +148 -0
  81. package/src/components/graphie-movables.jsx +342 -0
  82. package/src/components/graphie.jsx +353 -0
  83. package/src/components/highlighting/highlightable-content.jsx +245 -0
  84. package/src/components/highlighting/highlights.js +208 -0
  85. package/src/components/highlighting/ranges.js +299 -0
  86. package/src/components/highlighting/types.js +73 -0
  87. package/src/components/highlighting/ui/highlight-renderer.jsx +179 -0
  88. package/src/components/highlighting/ui/highlight-set-renderer.jsx +190 -0
  89. package/src/components/highlighting/ui/highlight-tooltip.jsx +153 -0
  90. package/src/components/highlighting/ui/highlighting-ui.jsx +163 -0
  91. package/src/components/highlighting/ui/selection-tracker.jsx +195 -0
  92. package/src/components/highlighting/ui/types.js +21 -0
  93. package/src/components/highlighting/ui/util.js +166 -0
  94. package/src/components/highlighting/word-indexer.jsx +155 -0
  95. package/src/components/hud.jsx +179 -0
  96. package/src/components/icon.jsx +149 -0
  97. package/src/components/image-loader.jsx +175 -0
  98. package/src/components/info-tip/info-tip.jsx +149 -0
  99. package/src/components/info-tip.jsx +38 -0
  100. package/src/components/inline-icon.jsx +81 -0
  101. package/src/components/input-with-examples.jsx +231 -0
  102. package/src/components/lint.jsx +456 -0
  103. package/src/components/math-input.jsx +282 -0
  104. package/src/components/math-output.jsx +128 -0
  105. package/src/components/multi-button-group.jsx +137 -0
  106. package/src/components/new-tooltip/README.md +110 -0
  107. package/src/components/new-tooltip/__stories__/flexible-position.stories.jsx +437 -0
  108. package/src/components/new-tooltip/__stories__/new-tooltip.stories.jsx +665 -0
  109. package/src/components/new-tooltip/__stories__/tooltip-arrow.stories.jsx +70 -0
  110. package/src/components/new-tooltip/__stories__/tooltip-bubble.stories.jsx +98 -0
  111. package/src/components/new-tooltip/__tests__/style-constants_test.js +8 -0
  112. package/src/components/new-tooltip/__tests__/util_test.js +47 -0
  113. package/src/components/new-tooltip/flexible-position.jsx +182 -0
  114. package/src/components/new-tooltip/new-tooltip.jsx +399 -0
  115. package/src/components/new-tooltip/style-constants.js +13 -0
  116. package/src/components/new-tooltip/tooltip-arrow.jsx +184 -0
  117. package/src/components/new-tooltip/tooltip-bubble.jsx +223 -0
  118. package/src/components/new-tooltip/tooltip-portal.jsx +101 -0
  119. package/src/components/new-tooltip/tooltip-positioner.jsx +529 -0
  120. package/src/components/new-tooltip/types.js +183 -0
  121. package/src/components/new-tooltip/util.js +27 -0
  122. package/src/components/number-input.jsx +253 -0
  123. package/src/components/possible-answers.jsx +36 -0
  124. package/src/components/prop-check-box.jsx +78 -0
  125. package/src/components/range-input.jsx +61 -0
  126. package/src/components/simple-keypad-input.jsx +91 -0
  127. package/src/components/sortable.jsx +872 -0
  128. package/src/components/stub-tag-editor.jsx +53 -0
  129. package/src/components/svg-image.jsx +762 -0
  130. package/src/components/tex-buttons.jsx +322 -0
  131. package/src/components/tex.jsx +70 -0
  132. package/src/components/text-input.jsx +82 -0
  133. package/src/components/text-list-editor.jsx +157 -0
  134. package/src/components/tooltip.jsx +395 -0
  135. package/src/components/visibility-observer/__stories__/visibility-observer.stories.jsx +140 -0
  136. package/src/components/visibility-observer/get-scroll-parent.js +45 -0
  137. package/src/components/visibility-observer/visibility-observer.js +109 -0
  138. package/src/components/visibility-observer/visibility-observer.jsx +123 -0
  139. package/src/components/zoomable-tex.jsx +70 -0
  140. package/src/components/zoomable.jsx +304 -0
  141. package/src/components.js +17 -0
  142. package/src/dependencies.js +22 -0
  143. package/src/error-boundary.jsx +48 -0
  144. package/src/extra-widgets.js +75 -0
  145. package/src/gorgon/README +40 -0
  146. package/src/gorgon/__tests__/matcher_test.js +497 -0
  147. package/src/gorgon/__tests__/rule_test.js +101 -0
  148. package/src/gorgon/__tests__/rules_test.js +487 -0
  149. package/src/gorgon/__tests__/selector-parser_test.js +52 -0
  150. package/src/gorgon/__tests__/tree-transformer_test.js +446 -0
  151. package/src/gorgon/gorgon.js +290 -0
  152. package/src/gorgon/proptypes.js +29 -0
  153. package/src/gorgon/rule.js +413 -0
  154. package/src/gorgon/rules/absolute-url.js +24 -0
  155. package/src/gorgon/rules/all-rules.js +72 -0
  156. package/src/gorgon/rules/blockquoted-math.js +10 -0
  157. package/src/gorgon/rules/blockquoted-widget.js +10 -0
  158. package/src/gorgon/rules/double-spacing-after-terminal.js +12 -0
  159. package/src/gorgon/rules/extra-content-spacing.js +12 -0
  160. package/src/gorgon/rules/heading-level-1.js +14 -0
  161. package/src/gorgon/rules/heading-level-skip.js +20 -0
  162. package/src/gorgon/rules/heading-sentence-case.js +11 -0
  163. package/src/gorgon/rules/heading-title-case.js +63 -0
  164. package/src/gorgon/rules/image-alt-text.js +21 -0
  165. package/src/gorgon/rules/image-in-table.js +10 -0
  166. package/src/gorgon/rules/image-spaces-around-urls.js +35 -0
  167. package/src/gorgon/rules/image-widget.js +50 -0
  168. package/src/gorgon/rules/link-click-here.js +11 -0
  169. package/src/gorgon/rules/lint-utils.js +48 -0
  170. package/src/gorgon/rules/long-paragraph.js +14 -0
  171. package/src/gorgon/rules/math-adjacent.js +10 -0
  172. package/src/gorgon/rules/math-align-extra-break.js +11 -0
  173. package/src/gorgon/rules/math-align-linebreaks.js +43 -0
  174. package/src/gorgon/rules/math-empty.js +10 -0
  175. package/src/gorgon/rules/math-font-size.js +12 -0
  176. package/src/gorgon/rules/math-frac.js +10 -0
  177. package/src/gorgon/rules/math-nested.js +11 -0
  178. package/src/gorgon/rules/math-starts-with-space.js +12 -0
  179. package/src/gorgon/rules/math-text-empty.js +10 -0
  180. package/src/gorgon/rules/math-without-dollars.js +14 -0
  181. package/src/gorgon/rules/nested-lists.js +11 -0
  182. package/src/gorgon/rules/profanity.js +10 -0
  183. package/src/gorgon/rules/table-missing-cells.js +20 -0
  184. package/src/gorgon/rules/unbalanced-code-delimiters.js +14 -0
  185. package/src/gorgon/rules/unescaped-dollar.js +10 -0
  186. package/src/gorgon/rules/widget-in-table.js +10 -0
  187. package/src/gorgon/selector.js +506 -0
  188. package/src/gorgon/tree-transformer.js +588 -0
  189. package/src/hint-renderer.jsx +159 -0
  190. package/src/hints-renderer.jsx +359 -0
  191. package/src/icon-paths.js +120 -0
  192. package/src/index.js +149 -2
  193. package/src/init.js +49 -0
  194. package/src/interaction-tracker.js +60 -0
  195. package/src/interactive2/__tests__/movable-mock.js +48 -0
  196. package/src/interactive2/__tests__/movable-point_test.js +146 -0
  197. package/src/interactive2/interactive-util.js +152 -0
  198. package/src/interactive2/movable-helper-methods.js +160 -0
  199. package/src/interactive2/movable-line-options.js +392 -0
  200. package/src/interactive2/movable-line.js +322 -0
  201. package/src/interactive2/movable-point-options.js +190 -0
  202. package/src/interactive2/movable-point.jsx +604 -0
  203. package/src/interactive2/movable-polygon-options.js +351 -0
  204. package/src/interactive2/movable-polygon.js +367 -0
  205. package/src/interactive2/movable.js +273 -0
  206. package/src/interactive2/objective_.js +79 -0
  207. package/src/interactive2/types.js +3 -0
  208. package/src/interactive2/wrapped-defaults.js +86 -0
  209. package/src/interactive2/wrapped-ellipse.js +87 -0
  210. package/src/interactive2/wrapped-line.js +109 -0
  211. package/src/interactive2/wrapped-path.js +47 -0
  212. package/src/interactive2.js +91 -0
  213. package/src/item-renderer.jsx +518 -0
  214. package/src/item-version.js +12 -0
  215. package/src/jipt-paragraphs.js +44 -0
  216. package/src/jquery.mobile.vmouse.js +545 -0
  217. package/src/keypad-context.js +33 -0
  218. package/src/loading-context.js +20 -0
  219. package/src/logging/log.js +107 -0
  220. package/src/logging/log_test.js +41 -0
  221. package/src/mixins/changeable.jsx +115 -0
  222. package/src/mixins/editor-jsonify.jsx +13 -0
  223. package/src/mixins/provide-keypad.jsx +131 -0
  224. package/src/mixins/widget-jsonify-deprecated.jsx +23 -0
  225. package/src/mixins/widget-prop-blacklist.js +36 -0
  226. package/src/multi-items/__stories__/multi-renderer.stories.js +88 -0
  227. package/src/multi-items/__testdata__/multi-renderer_testdata.js +174 -0
  228. package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +994 -0
  229. package/src/multi-items/__tests__/items_test.js +245 -0
  230. package/src/multi-items/__tests__/multi-renderer_test.js +903 -0
  231. package/src/multi-items/__tests__/prop-type-builders_test.js +134 -0
  232. package/src/multi-items/__tests__/shapes_test.js +44 -0
  233. package/src/multi-items/__tests__/trees_test.js +316 -0
  234. package/src/multi-items/item-types.js +55 -0
  235. package/src/multi-items/items.js +176 -0
  236. package/src/multi-items/multi-renderer.jsx +542 -0
  237. package/src/multi-items/prop-type-builders.js +105 -0
  238. package/src/multi-items/shape-types.js +47 -0
  239. package/src/multi-items/shapes.js +53 -0
  240. package/src/multi-items/tree-types.js +42 -0
  241. package/src/multi-items/trees.js +345 -0
  242. package/src/multi-items.js +76 -0
  243. package/src/not-gorgon.js +129 -0
  244. package/src/perseus-api.jsx +270 -0
  245. package/src/perseus-env.js +26 -0
  246. package/src/perseus-error.js +19 -0
  247. package/src/perseus-markdown.jsx +434 -0
  248. package/src/perseus-types.js +1597 -0
  249. package/src/pure-markdown.js +346 -0
  250. package/src/question-paragraph.jsx +30 -0
  251. package/src/renderability.jsx +108 -0
  252. package/src/renderer.jsx +1931 -0
  253. package/src/server-item-renderer.jsx +467 -0
  254. package/src/sigfigs.jsx +492 -0
  255. package/src/styles/articles.less +748 -0
  256. package/src/styles/constants.js +119 -0
  257. package/src/styles/global-constants.js +350 -0
  258. package/src/styles/global-styles.js +307 -0
  259. package/src/styles/khan-exercise.css +1304 -0
  260. package/src/styles/media-queries.js +48 -0
  261. package/src/styles/perseus-renderer.less +1008 -0
  262. package/src/styles/shared.js +132 -0
  263. package/src/styles/util.less +47 -0
  264. package/src/styles/variables.boostrap.less +301 -0
  265. package/src/styles/variables.less +68 -0
  266. package/src/styles/variables.shared.less +356 -0
  267. package/src/styles/widgets/categorizer.less +39 -0
  268. package/src/styles/widgets/definition.less +86 -0
  269. package/src/styles/widgets/dropdown.less +3 -0
  270. package/src/styles/widgets/expression.less +147 -0
  271. package/src/styles/widgets/graded-group.less +36 -0
  272. package/src/styles/widgets/grapher.less +11 -0
  273. package/src/styles/widgets/group.less +19 -0
  274. package/src/styles/widgets/image.less +29 -0
  275. package/src/styles/widgets/interactive-graph.less +61 -0
  276. package/src/styles/widgets/label-image.less +41 -0
  277. package/src/styles/widgets/matcher.less +8 -0
  278. package/src/styles/widgets/matrix.less +120 -0
  279. package/src/styles/widgets/measurer.less +20 -0
  280. package/src/styles/widgets/orderer.less +97 -0
  281. package/src/styles/widgets/passage.less +151 -0
  282. package/src/styles/widgets/plotter.less +33 -0
  283. package/src/styles/widgets/radio.less +52 -0
  284. package/src/styles/widgets/reaction-diagram.less +35 -0
  285. package/src/styles/widgets/sequence.less +5 -0
  286. package/src/styles/widgets/sortable.less +127 -0
  287. package/src/styles/widgets/table.less +56 -0
  288. package/src/styles/widgets/transformer.less +28 -0
  289. package/src/styles/widgets/unit.less +14 -0
  290. package/src/tex-wrangler.js +176 -0
  291. package/src/traversal.jsx +141 -0
  292. package/src/types.js +538 -0
  293. package/src/util/a11y.js +24 -0
  294. package/src/util/answer-types.js +862 -0
  295. package/src/util/answer-types_test.js +115 -0
  296. package/src/util/colors.js +94 -0
  297. package/src/util/fix-passage-refs.jsx +122 -0
  298. package/src/util/graph-utils.js +16 -0
  299. package/src/util/graphie.js +1585 -0
  300. package/src/util/interactive.js +4071 -0
  301. package/src/util/katex-preprocess.js +16 -0
  302. package/src/util/math.js +296 -0
  303. package/src/util/mobile-native-utils.js +14 -0
  304. package/src/util/mobile-native-utils_test.js +24 -0
  305. package/src/util/register-all-widgets-for-testing.js +12 -0
  306. package/src/util/scroll-utils.js +162 -0
  307. package/src/util/sizing-utils.js +46 -0
  308. package/src/util/tex.js +203 -0
  309. package/src/util/url-utils.js +36 -0
  310. package/src/util.js +990 -0
  311. package/src/version.js +11 -0
  312. package/src/widget-container.jsx +174 -0
  313. package/src/widgets/__stories__/categorizer.stories.jsx +15 -0
  314. package/src/widgets/__stories__/cs-program.stories.jsx +15 -0
  315. package/src/widgets/__stories__/definition.stories.jsx +38 -0
  316. package/src/widgets/__stories__/dropdown.stories.jsx +15 -0
  317. package/src/widgets/__stories__/explanation.stories.jsx +19 -0
  318. package/src/widgets/__stories__/expression.stories.jsx +26 -0
  319. package/src/widgets/__stories__/graded-group-set.stories.jsx +32 -0
  320. package/src/widgets/__stories__/graded-group.stories.jsx +32 -0
  321. package/src/widgets/__stories__/grapher.stories.jsx +47 -0
  322. package/src/widgets/__stories__/group.stories.jsx +15 -0
  323. package/src/widgets/__stories__/iframe.stories.jsx +15 -0
  324. package/src/widgets/__stories__/image.stories.jsx +62 -0
  325. package/src/widgets/__stories__/input-number.stories.jsx +90 -0
  326. package/src/widgets/__stories__/interaction.stories.jsx +15 -0
  327. package/src/widgets/__stories__/interactive-graph.stories.jsx +61 -0
  328. package/src/widgets/__stories__/matcher.stories.jsx +15 -0
  329. package/src/widgets/__stories__/matrix.stories.jsx +15 -0
  330. package/src/widgets/__stories__/number-line.stories.jsx +15 -0
  331. package/src/widgets/__stories__/numeric-input.stories.jsx +19 -0
  332. package/src/widgets/__stories__/orderer.stories.jsx +15 -0
  333. package/src/widgets/__stories__/passage-ref.stories.jsx +19 -0
  334. package/src/widgets/__stories__/passage.stories.jsx +19 -0
  335. package/src/widgets/__stories__/radio.stories.jsx +82 -0
  336. package/src/widgets/__stories__/sorter.stories.jsx +15 -0
  337. package/src/widgets/__stories__/transformer.stories.jsx +15 -0
  338. package/src/widgets/__stories__/video.stories.jsx +15 -0
  339. package/src/widgets/__testdata__/categorizer_testdata.js +50 -0
  340. package/src/widgets/__testdata__/cs-program_testdata.js +28 -0
  341. package/src/widgets/__testdata__/dropdown_testdata.js +34 -0
  342. package/src/widgets/__testdata__/explanation_testdata.js +56 -0
  343. package/src/widgets/__testdata__/expression_testdata.js +95 -0
  344. package/src/widgets/__testdata__/graded-group-set_testdata.js +358 -0
  345. package/src/widgets/__testdata__/graded-group_testdata.js +79 -0
  346. package/src/widgets/__testdata__/grapher_testdata.js +376 -0
  347. package/src/widgets/__testdata__/group_testdata.js +156 -0
  348. package/src/widgets/__testdata__/iframe_testdata.js +36 -0
  349. package/src/widgets/__testdata__/image_testdata.js +38 -0
  350. package/src/widgets/__testdata__/input-number_testdata.js +73 -0
  351. package/src/widgets/__testdata__/interaction_testdata.js +264 -0
  352. package/src/widgets/__testdata__/interactive-graph_testdata.js +646 -0
  353. package/src/widgets/__testdata__/matcher_testdata.js +34 -0
  354. package/src/widgets/__testdata__/matrix_testdata.js +29 -0
  355. package/src/widgets/__testdata__/number-line_testdata.js +31 -0
  356. package/src/widgets/__testdata__/numeric-input_testdata.js +266 -0
  357. package/src/widgets/__testdata__/orderer_testdata.js +58 -0
  358. package/src/widgets/__testdata__/passage-ref_testdata.js +41 -0
  359. package/src/widgets/__testdata__/passage_testdata.js +71 -0
  360. package/src/widgets/__testdata__/radio_testdata.js +210 -0
  361. package/src/widgets/__testdata__/sorter_testdata.js +20 -0
  362. package/src/widgets/__testdata__/transformer_testdata.js +109 -0
  363. package/src/widgets/__testdata__/video_testdata.js +22 -0
  364. package/src/widgets/__tests__/__snapshots__/categorizer_test.jsx.snap +928 -0
  365. package/src/widgets/__tests__/__snapshots__/cs-program_test.jsx.snap +75 -0
  366. package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +99 -0
  367. package/src/widgets/__tests__/__snapshots__/dropdown_test.jsx.snap +143 -0
  368. package/src/widgets/__tests__/__snapshots__/explanation_test.js.snap +473 -0
  369. package/src/widgets/__tests__/__snapshots__/expression_test.jsx.snap +38 -0
  370. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt_test.jsx.snap +754 -0
  371. package/src/widgets/__tests__/__snapshots__/graded-group-set_test.jsx.snap +310 -0
  372. package/src/widgets/__tests__/__snapshots__/graded-group_test.jsx.snap +863 -0
  373. package/src/widgets/__tests__/__snapshots__/grapher_test.jsx.snap +2880 -0
  374. package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +1154 -0
  375. package/src/widgets/__tests__/__snapshots__/iframe_test.jsx.snap +69 -0
  376. package/src/widgets/__tests__/__snapshots__/image_test.jsx.snap +388 -0
  377. package/src/widgets/__tests__/__snapshots__/input-number_test.jsx.snap +978 -0
  378. package/src/widgets/__tests__/__snapshots__/interaction_test.jsx.snap +311 -0
  379. package/src/widgets/__tests__/__snapshots__/interactive-graph_test.jsx.snap +2915 -0
  380. package/src/widgets/__tests__/__snapshots__/matcher_test.jsx.snap +1039 -0
  381. package/src/widgets/__tests__/__snapshots__/matrix_test.jsx.snap +450 -0
  382. package/src/widgets/__tests__/__snapshots__/number-line_test.jsx.snap +888 -0
  383. package/src/widgets/__tests__/__snapshots__/numeric-input_test.jsx.snap +930 -0
  384. package/src/widgets/__tests__/__snapshots__/orderer_test.jsx.snap +275 -0
  385. package/src/widgets/__tests__/__snapshots__/passage-ref_test.jsx.snap +446 -0
  386. package/src/widgets/__tests__/__snapshots__/passage_test.jsx.snap +1988 -0
  387. package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +7107 -0
  388. package/src/widgets/__tests__/__snapshots__/video_test.jsx.snap +163 -0
  389. package/src/widgets/__tests__/categorizer_test.jsx +205 -0
  390. package/src/widgets/__tests__/cs-program_test.jsx +45 -0
  391. package/src/widgets/__tests__/definition_test.js +152 -0
  392. package/src/widgets/__tests__/dropdown_test.jsx +106 -0
  393. package/src/widgets/__tests__/explanation_test.js +199 -0
  394. package/src/widgets/__tests__/expression_test.jsx +439 -0
  395. package/src/widgets/__tests__/graded-group-set-jipt_test.jsx +33 -0
  396. package/src/widgets/__tests__/graded-group-set_test.jsx +270 -0
  397. package/src/widgets/__tests__/graded-group_test.jsx +233 -0
  398. package/src/widgets/__tests__/grapher.cypress.jsx +486 -0
  399. package/src/widgets/__tests__/grapher_test.jsx +35 -0
  400. package/src/widgets/__tests__/group_test.jsx +512 -0
  401. package/src/widgets/__tests__/iframe_test.jsx +47 -0
  402. package/src/widgets/__tests__/image_test.jsx +65 -0
  403. package/src/widgets/__tests__/input-number_test.jsx +360 -0
  404. package/src/widgets/__tests__/interaction_test.jsx +33 -0
  405. package/src/widgets/__tests__/interactive-graph.cypress.jsx +697 -0
  406. package/src/widgets/__tests__/interactive-graph_test.jsx +105 -0
  407. package/src/widgets/__tests__/matcher_test.jsx +157 -0
  408. package/src/widgets/__tests__/matrix_test.jsx +84 -0
  409. package/src/widgets/__tests__/number-line_test.jsx +81 -0
  410. package/src/widgets/__tests__/numeric-input_test.jsx +574 -0
  411. package/src/widgets/__tests__/orderer_test.jsx +75 -0
  412. package/src/widgets/__tests__/passage-ref_test.jsx +166 -0
  413. package/src/widgets/__tests__/passage_test.jsx +133 -0
  414. package/src/widgets/__tests__/radio/base-radio_test.jsx +82 -0
  415. package/src/widgets/__tests__/radio_test.jsx +651 -0
  416. package/src/widgets/__tests__/renderQuestion.jsx +65 -0
  417. package/src/widgets/__tests__/unit_test.jsx +144 -0
  418. package/src/widgets/__tests__/video_test.jsx +55 -0
  419. package/src/widgets/categorizer.jsx +338 -0
  420. package/src/widgets/cs-program.jsx +228 -0
  421. package/src/widgets/definition.jsx +141 -0
  422. package/src/widgets/dropdown.jsx +143 -0
  423. package/src/widgets/explanation.jsx +315 -0
  424. package/src/widgets/expression.jsx +654 -0
  425. package/src/widgets/graded-group-answer-bar.jsx +152 -0
  426. package/src/widgets/graded-group-set.jsx +285 -0
  427. package/src/widgets/graded-group.jsx +448 -0
  428. package/src/widgets/grapher/util.jsx +819 -0
  429. package/src/widgets/grapher.jsx +658 -0
  430. package/src/widgets/group.jsx +213 -0
  431. package/src/widgets/iframe.jsx +199 -0
  432. package/src/widgets/image.jsx +309 -0
  433. package/src/widgets/input-number.jsx +410 -0
  434. package/src/widgets/interaction/arrow-picker.jsx +39 -0
  435. package/src/widgets/interaction/color-picker.jsx +69 -0
  436. package/src/widgets/interaction/dash-picker.jsx +46 -0
  437. package/src/widgets/interaction/element-container.jsx +97 -0
  438. package/src/widgets/interaction.jsx +742 -0
  439. package/src/widgets/interactive-graph.jsx +2821 -0
  440. package/src/widgets/label-image/__stories__/answer-choices.stories.jsx +93 -0
  441. package/src/widgets/label-image/__stories__/marker.stories.jsx +172 -0
  442. package/src/widgets/label-image/answer-choices.jsx +311 -0
  443. package/src/widgets/label-image/marker.jsx +365 -0
  444. package/src/widgets/label-image/types.js +33 -0
  445. package/src/widgets/label-image.jsx +841 -0
  446. package/src/widgets/label-image_test.js +840 -0
  447. package/src/widgets/lights-puzzle.jsx +356 -0
  448. package/src/widgets/matcher.jsx +271 -0
  449. package/src/widgets/matrix.jsx +615 -0
  450. package/src/widgets/measurer.jsx +215 -0
  451. package/src/widgets/molecule/__tests__/layout_test.jsx +159 -0
  452. package/src/widgets/molecule/__tests__/parser_test.jsx +142 -0
  453. package/src/widgets/molecule/molecule-drawing.jsx +175 -0
  454. package/src/widgets/molecule/molecule-layout.jsx +367 -0
  455. package/src/widgets/molecule/smiles-parser.jsx +300 -0
  456. package/src/widgets/molecule.jsx +172 -0
  457. package/src/widgets/number-line.jsx +858 -0
  458. package/src/widgets/numeric-input.jsx +622 -0
  459. package/src/widgets/orderer.jsx +753 -0
  460. package/src/widgets/passage/__tests__/passage-markdown_test.jsx +382 -0
  461. package/src/widgets/passage/get-line-height-for-node.js +10 -0
  462. package/src/widgets/passage/passage-markdown.jsx +416 -0
  463. package/src/widgets/passage-ref-target.jsx +70 -0
  464. package/src/widgets/passage-ref.jsx +198 -0
  465. package/src/widgets/passage.jsx +601 -0
  466. package/src/widgets/plotter.jsx +1198 -0
  467. package/src/widgets/radio/__stories__/base-radio.stories.jsx +40 -0
  468. package/src/widgets/radio/__stories__/choice-icon.stories.jsx +157 -0
  469. package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +26 -0
  470. package/src/widgets/radio/__stories__/cross-out-button.stories.jsx +64 -0
  471. package/src/widgets/radio/__stories__/cross-out-menu.stories.jsx +59 -0
  472. package/src/widgets/radio/__stories__/cross-out-tooltip.stories.jsx +59 -0
  473. package/src/widgets/radio/__stories__/focus-ring.stories.jsx +38 -0
  474. package/src/widgets/radio/__stories__/option-status.stories.jsx +118 -0
  475. package/src/widgets/radio/__stories__/toggleable-radio-button.stories.jsx +28 -0
  476. package/src/widgets/radio/base-radio.jsx +642 -0
  477. package/src/widgets/radio/choice-icon.jsx +468 -0
  478. package/src/widgets/radio/choice-none-above.jsx +54 -0
  479. package/src/widgets/radio/choice.jsx +692 -0
  480. package/src/widgets/radio/choice.jsx.fixture.js +64 -0
  481. package/src/widgets/radio/cross-out-button.jsx +136 -0
  482. package/src/widgets/radio/cross-out-menu-wrapper.jsx +492 -0
  483. package/src/widgets/radio/cross-out-tooltip.jsx +129 -0
  484. package/src/widgets/radio/focus-ring.jsx +51 -0
  485. package/src/widgets/radio/option-status.jsx +89 -0
  486. package/src/widgets/radio/toggleable-radio-button.jsx +133 -0
  487. package/src/widgets/radio/util.js +32 -0
  488. package/src/widgets/radio/util_test.js +19 -0
  489. package/src/widgets/radio/widget.jsx +470 -0
  490. package/src/widgets/radio.jsx +156 -0
  491. package/src/widgets/reaction-diagram.jsx +136 -0
  492. package/src/widgets/sequence.jsx +140 -0
  493. package/src/widgets/simulator.jsx +808 -0
  494. package/src/widgets/sorter.jsx +146 -0
  495. package/src/widgets/table.jsx +395 -0
  496. package/src/widgets/transformer.jsx +2870 -0
  497. package/src/widgets/unit.jsx +371 -0
  498. package/src/widgets/video-transcript-link.jsx +84 -0
  499. package/src/widgets/video-transcript-link_test.js +211 -0
  500. package/src/widgets/video.jsx +131 -0
  501. package/src/widgets.js +431 -0
  502. package/src/zoom.js +539 -0
  503. package/src/__tests__/index.test.js +0 -14
@@ -0,0 +1,604 @@
1
+ // @flow
2
+ /**
3
+ * Creates and adds a point to the graph that can be dragged around.
4
+ * It allows constraints on its movement and draws when moves happen.
5
+ *
6
+ * Options can be passed to the constructor to control how the point behaves:
7
+ * coord: [x, y]
8
+ * The initial position of the point
9
+ * pointSize:
10
+ * changes the size of the point. defaults to 4
11
+ * static: boolean
12
+ * draw the point, but don't let it be interactable
13
+ * cursor: "move", "pointer"
14
+ * css cursor for this point
15
+ * add: [function(state)]
16
+ * called immediately when this movablePoint is added
17
+ * default: apply any constraints and draw
18
+ * draw: [function(prevState, currentState)]
19
+ * drawing functions. default to [basic, highlight]
20
+ * remove: [function(state)]
21
+ * called when this movablePoint is removed
22
+ * onMoveStart: [function(coord)]
23
+ * called when this point is clicked on
24
+ * constraints: [function(coord)]
25
+ * called when this point is dragged
26
+ * return true or nothing to accept the move
27
+ * return false to cancel the move
28
+ * return an [x, y] coordinate to override the move
29
+ * onMove: [function(coord)]
30
+ * called after all constraints functions pass and the point
31
+ * is moved to a new location
32
+ * onMoveEnd: [function(coord)]
33
+ * called when the mouse is released from a click or move
34
+ * onClick: [function(coord)]
35
+ * called when someone mouses down, doesn't move the point,
36
+ * and mouses up.
37
+ * normalStyle:
38
+ * the raphael/graphie style of the point when not hovering
39
+ * highlightStyle:
40
+ * the raphael/graphie style of the point when hovering, if
41
+ * MovablePoint.draw.highlight is used
42
+ *
43
+ * This creates a MovablePoint object with the following methods:
44
+ * setCoord: [x, y]
45
+ * changes the point's coordinate
46
+ * draw:
47
+ * redraws the coord
48
+ * modify: {options}
49
+ * modifies the original options passed to the point
50
+ * remove:
51
+ * removes the point from graphie
52
+ */
53
+ import {point as kpoint} from "kmath";
54
+ import {vector as kvector} from "kmath";
55
+ import * as React from "react";
56
+ import * as ReactDOM from "react-dom";
57
+ import _ from "underscore";
58
+
59
+ import InlineIcon from "../components/inline-icon.jsx";
60
+ import {iconTrash} from "../icon-paths.js";
61
+ import KhanColors from "../util/colors.js";
62
+ import Tex from "../util/tex.js";
63
+
64
+ import InteractiveUtil from "./interactive-util.js";
65
+ import MovablePointOptions from "./movable-point-options.js";
66
+ import objective_ from "./objective_.js";
67
+ import WrappedEllipse from "./wrapped-ellipse.js";
68
+
69
+ const assert = InteractiveUtil.assert;
70
+ const normalizeOptions = InteractiveUtil.normalizeOptions;
71
+
72
+ const {processMath} = Tex;
73
+
74
+ // State parameters that should be converted into an array of
75
+ // functions
76
+ const FUNCTION_ARRAY_OPTIONS = _.keys(MovablePointOptions);
77
+
78
+ // Default "props" and "state". Both are added to this.state and
79
+ // receive magic getter methods (this.coord() etc).
80
+ // However, properties in DEFAULT_PROPS are updated on `modify()`,
81
+ // while those in DEFAULT_STATE persist and are not updated.
82
+ // Things that the user might want to change should be on "props",
83
+ // while things used to render the point should be on "state".
84
+ const DEFAULT_PROPS = {
85
+ coord: [0, 0],
86
+ pointSize: 4,
87
+ static: false,
88
+ cursor: "move",
89
+ normalStyle: null, // turned into an object in this.modify
90
+ highlightStyle: null, // likewise
91
+ shadow: false,
92
+ tooltip: false,
93
+ };
94
+ const DEFAULT_STATE = {
95
+ added: false,
96
+ hasMoved: false,
97
+ visibleShape: null,
98
+ outOfBounds: false,
99
+ mouseTarget: null,
100
+ touchOffset: null,
101
+ };
102
+
103
+ const tooltipResetFunctions = [];
104
+
105
+ const MovablePoint = function (
106
+ graphie: $FlowFixMe,
107
+ movable: $FlowFixMe,
108
+ options: $FlowFixMe,
109
+ ) {
110
+ _.extend(this, {
111
+ graphie,
112
+ movable,
113
+ state: {
114
+ // Set here because this must be unique for each instance
115
+ id: _.uniqueId("movablePoint"),
116
+ },
117
+ });
118
+
119
+ // We only set DEFAULT_STATE once, here
120
+ this.modify(_.extend({}, DEFAULT_STATE, options));
121
+ };
122
+
123
+ _.extend(MovablePoint, MovablePointOptions);
124
+ InteractiveUtil.createGettersFor(
125
+ MovablePoint,
126
+ _.extend({}, DEFAULT_PROPS, DEFAULT_STATE),
127
+ );
128
+ InteractiveUtil.addMovableHelperMethodsTo(MovablePoint);
129
+
130
+ _.extend(MovablePoint.prototype, {
131
+ cloneState: function () {
132
+ return _.extend(this.movable.cloneState(), this.state);
133
+ },
134
+
135
+ _createDefaultState: function () {
136
+ return _.extend(
137
+ {
138
+ id: this.state.id,
139
+ },
140
+ normalizeOptions(
141
+ FUNCTION_ARRAY_OPTIONS,
142
+ // Defaults are copied from MovablePointOptions.*.standard
143
+ // These defaults are set here instead of DEFAULT_PROPS/STATE
144
+ // because they:
145
+ // - are objects, not primitives (and need a deeper copy)
146
+ // - they don't need getters created for them
147
+ // TODO(jack): Consider "default" once we es3ify perseus
148
+ objective_.pluck(MovablePointOptions, "standard"),
149
+
150
+ // We only update props here, because we want things on state to
151
+ // be persistent, and updated appropriately in modify()
152
+ ),
153
+ DEFAULT_PROPS,
154
+ );
155
+ },
156
+
157
+ /**
158
+ * Resets the object to its state as if it were constructed with
159
+ * `options` originally. state not on DEFAULT_PROPS is maintained.
160
+ *
161
+ * Analogous to React.js's replaceProps
162
+ */
163
+ modify: function (options) {
164
+ this.update(_.extend(this._createDefaultState(), options));
165
+ },
166
+
167
+ /**
168
+ * Displays a tooltip above the point, replacing any previous contents. If
169
+ * there is no tooltip initialized, adds the tooltip.
170
+ *
171
+ * If the type of contents is string, the contents will be rendered with
172
+ * KaTeX. Otherwise, the content will be assumed to be a DOM node and will
173
+ * be appended inside the tooltip.
174
+ */
175
+ _showTooltip: function (contents) {
176
+ if (!this._tooltip) {
177
+ this._tooltip = document.createElement("div");
178
+ this._tooltip.className = "tooltip-content";
179
+ this.state.visibleShape.wrapper.className = "tooltip";
180
+ this.state.visibleShape.wrapper.appendChild(this._tooltip);
181
+
182
+ // Only one tooltip should be displayed at a time, so store a list
183
+ // of all the tooltips initialized.
184
+ tooltipResetFunctions.push(() => {
185
+ if (this.state.added) {
186
+ this._hideTooltip();
187
+ }
188
+ });
189
+ }
190
+
191
+ if (this._tooltip.firstChild) {
192
+ this._tooltip.removeChild(this._tooltip.firstChild);
193
+ }
194
+
195
+ this.state.visibleShape.wrapper.className = "tooltip visible";
196
+ this._tooltip.appendChild(document.createElement("span"));
197
+
198
+ if (typeof contents === "string") {
199
+ processMath(this._tooltip.firstChild, contents, false);
200
+ } else if (typeof contents === "function") {
201
+ contents(this._tooltip.firstChild);
202
+ } else {
203
+ this._tooltip.firstChild.appendChild(contents);
204
+ }
205
+ },
206
+
207
+ _hideTooltip: function () {
208
+ if (this._tooltip) {
209
+ // Without the visible class, tooltips have display: none set
210
+ this.state.visibleShape.wrapper.className = "tooltip";
211
+ }
212
+ },
213
+
214
+ /**
215
+ * Adjusts constructor parameters without changing previous settings
216
+ * for any option not specified
217
+ *
218
+ * Analogous to React.js's setProps
219
+ */
220
+ update: function (options) {
221
+ const self = this;
222
+ const graphie = self.graphie;
223
+ const state = _.extend(
224
+ self.state,
225
+ normalizeOptions(FUNCTION_ARRAY_OPTIONS, options),
226
+ );
227
+
228
+ assert(kpoint.is(state.coord));
229
+
230
+ // Default things inside the state.normalStyle object, because
231
+ // _.extend is not deep.
232
+ // We use _.extend instead of _.defaults because we don't want
233
+ // to modify the passed-in copy (especially if it's from
234
+ // DEFAULT_PROPS/STATE!)
235
+ const normalColor = state.static
236
+ ? KhanColors.DYNAMIC
237
+ : KhanColors.INTERACTIVE;
238
+ state.normalStyle = _.extend(
239
+ {
240
+ fill: normalColor,
241
+ stroke: normalColor,
242
+ scale: 1,
243
+ },
244
+ state.normalStyle,
245
+ );
246
+
247
+ state.highlightStyle = _.extend(
248
+ {
249
+ fill: KhanColors.INTERACTING,
250
+ stroke: KhanColors.INTERACTING,
251
+ scale: 2,
252
+ },
253
+ state.highlightStyle,
254
+ );
255
+
256
+ if (!state.static) {
257
+ // the invisible shape in front of the point that gets mouse events
258
+ if (!state.mouseTarget) {
259
+ const center = self.state.coord;
260
+ const radii = graphie.unscaleVector(24);
261
+ const options = {
262
+ mouselayer: true,
263
+ padding: 0,
264
+ interactiveKindForTesting: "movable-point",
265
+ };
266
+ // $FlowFixMe[invalid-constructor]
267
+ state.mouseTarget = new WrappedEllipse(
268
+ graphie,
269
+ center,
270
+ radii,
271
+ options,
272
+ );
273
+ state.mouseTarget.attr({fill: "#000", opacity: 0.0});
274
+ }
275
+ }
276
+
277
+ const showTrashTooltip = () => {
278
+ this._showTooltip((container) => {
279
+ // TODO(LP-11406): Replace with React Portal
280
+ // eslint-disable-next-line no-restricted-syntax
281
+ ReactDOM.render(
282
+ <span style={{fontSize: "2em"}}>
283
+ <InlineIcon
284
+ {...iconTrash}
285
+ style={{
286
+ position: "static",
287
+ color: KhanColors.INTERACTIVE,
288
+ marginLeft: 9,
289
+ marginRight: 9,
290
+ }}
291
+ />
292
+ </span>,
293
+ container,
294
+ );
295
+ });
296
+ };
297
+
298
+ // The starting coord of any move, sent to onMoveEnd as the previous
299
+ // value
300
+ let startCoord = state.coord;
301
+
302
+ // The Movable representing this movablePoint's representation
303
+ // This handles mouse events for us, which we propagate in
304
+ // onMove
305
+ self.movable.modify(
306
+ _.extend({}, state, {
307
+ add: null,
308
+ modify: null,
309
+ draw: self.draw.bind(self),
310
+ remove: null,
311
+ onMoveStart: (startMouseCoord) => {
312
+ state.hasMoved = false;
313
+ startCoord = state.coord;
314
+
315
+ // Save the offset between the cursor and the initial coordinate
316
+ // of the point. This is tracked so as to avoid locking the
317
+ // moving point to the user's finger on touch devices, which
318
+ // would obscure it, no matter how large we made the touch
319
+ // target. Instead, we respect the offset at which the point was
320
+ // grabbed for the entirety of the gesture, if it's a
321
+ // touch-based interaction.
322
+ if (state.touchOffset == null) {
323
+ const isMouse = !("ontouchstart" in window);
324
+ state.touchOffset = isMouse
325
+ ? [0, 0]
326
+ : kvector.subtract(startCoord, startMouseCoord);
327
+ }
328
+
329
+ const svgElem = state.visibleShape.wrapper;
330
+ if (state.shadow) {
331
+ const filter = "none";
332
+ svgElem.style.webkitFilter = filter;
333
+ svgElem.style.filter = filter;
334
+ }
335
+
336
+ if (state.showHairlines) {
337
+ state.showHairlines(state.coord);
338
+ }
339
+
340
+ tooltipResetFunctions.forEach((f) => f());
341
+ if (state.tooltip) {
342
+ if (state.xOnlyTooltip) {
343
+ this._showTooltip(`${state.coord[0]}`);
344
+ } else {
345
+ this._showTooltip(
346
+ `(${state.coord[0]}, ${state.coord[1]})`,
347
+ );
348
+ }
349
+
350
+ if (state.shadow) {
351
+ const content =
352
+ svgElem.getElementsByClassName(
353
+ "tooltip-content",
354
+ )[0];
355
+ const filter =
356
+ "drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
357
+
358
+ content.style.webkitFilter = filter;
359
+ content.style.filter = filter;
360
+ }
361
+ }
362
+
363
+ self._fireEvent(state.onMoveStart, startCoord, startCoord);
364
+ self.draw();
365
+ },
366
+ onMove: (mouseCoord, prevMouseCoord) => {
367
+ const transformedCoord = kvector.add(
368
+ mouseCoord,
369
+ state.touchOffset,
370
+ );
371
+
372
+ self.moveTo(transformedCoord);
373
+
374
+ if (state.showHairlines) {
375
+ if (!this.state.outOfBounds) {
376
+ state.showHairlines(state.coord);
377
+ } else {
378
+ state.hideHairlines();
379
+ }
380
+ }
381
+
382
+ if (state.tooltip) {
383
+ if (!this.state.outOfBounds) {
384
+ if (state.xOnlyTooltip) {
385
+ this._showTooltip(`${state.coord[0]}`);
386
+ } else {
387
+ this._showTooltip(
388
+ `(${state.coord[0]}, ${state.coord[1]})`,
389
+ );
390
+ }
391
+ }
392
+ }
393
+
394
+ if (state.onRemove && this.state.outOfBounds) {
395
+ showTrashTooltip();
396
+ }
397
+ },
398
+ onMoveEnd: () => {
399
+ if (self.isHovering() && !state.hasMoved) {
400
+ self._fireEvent(state.onClick, state.coord, startCoord);
401
+ }
402
+
403
+ const svgElem = state.visibleShape.wrapper;
404
+
405
+ if (state.shadow) {
406
+ const filter =
407
+ "drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
408
+ svgElem.style.webkitFilter = filter;
409
+ svgElem.style.filter = filter;
410
+ }
411
+
412
+ if (state.hideHairlines) {
413
+ state.hideHairlines();
414
+ }
415
+
416
+ if (state.hasMoved) {
417
+ this._hideTooltip();
418
+ } else if (state.onRemove) {
419
+ // If we haven't moved and we should be displaying trash
420
+ // tooltips.
421
+ showTrashTooltip();
422
+
423
+ const content =
424
+ svgElem.getElementsByClassName(
425
+ "tooltip-content",
426
+ )[0];
427
+
428
+ content.style.webkitFilter = "none";
429
+ content.style.filter = "none";
430
+
431
+ this._tooltip.firstChild.addEventListener(
432
+ "touchstart",
433
+ (e) => {
434
+ // Prevent creation of a new point when the event is
435
+ // propagated up the DOM.
436
+ e.stopPropagation();
437
+ },
438
+ true,
439
+ );
440
+
441
+ this._tooltip.firstChild.addEventListener(
442
+ "touchend",
443
+ (e) => {
444
+ // Remove the point and prevent creation of a
445
+ // new point.
446
+ state.onRemove();
447
+ e.stopPropagation();
448
+ },
449
+ true,
450
+ );
451
+ } else if (state.tooltip) {
452
+ this._hideTooltip();
453
+ }
454
+
455
+ if (state.outOfBounds) {
456
+ state.onRemove();
457
+ }
458
+
459
+ self._fireEvent(state.onMoveEnd, state.coord, startCoord);
460
+ state.hasMoved = false;
461
+ state.touchOffset = null;
462
+ self.draw();
463
+ },
464
+ }),
465
+ );
466
+
467
+ // Trigger an add event if this hasn't been added before
468
+ if (!state.added) {
469
+ self.prevState = {};
470
+ self._fireEvent(state.add, self.cloneState(), self.prevState);
471
+ state.added = true;
472
+
473
+ // Update the state for `added` and in case the add event
474
+ // changed it
475
+ self.prevState = self.cloneState();
476
+ }
477
+
478
+ // Trigger a modify event
479
+ self._fireEvent(state.modify, self.cloneState(), self.prevState);
480
+ },
481
+
482
+ remove: function () {
483
+ this.state.added = false;
484
+ this._fireEvent(this.state.remove);
485
+ if (this.movable) {
486
+ this.movable.remove();
487
+ }
488
+ // TODO(jack): This should really be moved off of
489
+ // movablePoint.state and only kept on movable.state
490
+ this.state.mouseTarget = null;
491
+ },
492
+
493
+ constrain: function () {
494
+ const result = this._applyConstraints(this.coord(), this.coord());
495
+ if (kpoint.is(result)) {
496
+ this.setCoord(result);
497
+ }
498
+ return result !== false;
499
+ },
500
+
501
+ setCoord: function (coord) {
502
+ assert(kpoint.is(coord, 2));
503
+ this.state.coord = _.clone(coord);
504
+ this.draw();
505
+ },
506
+
507
+ setCoordConstrained: function (coord) {
508
+ assert(kpoint.is(coord, 2));
509
+ const result = this._applyConstraints(coord, this.coord());
510
+ if (result !== false) {
511
+ this.state.coord = _.clone(result);
512
+ this.draw();
513
+ }
514
+ },
515
+
516
+ moveTo: function (coord) {
517
+ // The caller has the option of adding an onMove() method to the
518
+ // movablePoint object we return as a sort of event handler
519
+ // By returning false from onMove(), the move can be vetoed,
520
+ // providing custom constraints on where the point can be moved.
521
+ // By returning array [x, y], the move can be overridden
522
+
523
+ const state = this.state;
524
+
525
+ this.state.outOfBounds = false;
526
+ const result = this._applyConstraints(
527
+ coord,
528
+ state.coord,
529
+ state.onRemove
530
+ ? {
531
+ onOutOfBounds: () => {
532
+ this.state.outOfBounds = true;
533
+ },
534
+ }
535
+ : {},
536
+ );
537
+
538
+ if (result === false) {
539
+ return;
540
+ }
541
+ if (kpoint.is(result)) {
542
+ coord = result;
543
+ }
544
+ if (!kpoint.equal(coord, state.coord)) {
545
+ const prevCoord = state.coord;
546
+ state.coord = coord;
547
+ state.hasMoved = true;
548
+ this._fireEvent(state.onMove, state.coord, prevCoord);
549
+ this.draw();
550
+ }
551
+ },
552
+
553
+ // Clone these for use with raphael, which modifies the input
554
+ // style parameters
555
+ normalStyle: function () {
556
+ return _.clone(this.state.normalStyle);
557
+ },
558
+
559
+ highlightStyle: function () {
560
+ return _.clone(this.state.highlightStyle);
561
+ },
562
+
563
+ // Change z-order to back
564
+ toBack: function () {
565
+ this.movable.toBack();
566
+ if (this.state.visibleShape) {
567
+ this.state.visibleShape.toBack();
568
+ }
569
+ },
570
+
571
+ // Change z-order to front
572
+ toFront: function () {
573
+ if (this.state.visibleShape) {
574
+ this.state.visibleShape.toFront();
575
+ }
576
+ this.movable.toFront();
577
+ },
578
+
579
+ /**
580
+ * Forwarding methods to this.movable:
581
+ */
582
+ isHovering: function () {
583
+ return this.movable.isHovering();
584
+ },
585
+
586
+ isDragging: function () {
587
+ return this.movable.isDragging();
588
+ },
589
+
590
+ mouseTarget: function () {
591
+ return this.movable.mouseTarget();
592
+ },
593
+
594
+ grab: function (coord) {
595
+ // Provide an explicit touchOffset override, so that we track the user's
596
+ // finger when a point has been grabbed.
597
+ this.state.touchOffset = [0, 0];
598
+
599
+ this.movable.grab(coord);
600
+ this.moveTo(coord);
601
+ },
602
+ });
603
+
604
+ export default MovablePoint;