@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.
- package/.babelrc.js +1 -1
- package/CHANGELOG.md +29 -0
- package/dist/es/index.css +4361 -0
- package/dist/es/index.js +7 -1
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +4361 -0
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/strings.js +148 -46
- package/package.json +50 -4
- package/src/README.md +35 -0
- package/src/__stories__/item-renderer.stories.jsx +27 -0
- package/src/__stories__/server-item-renderer.stories.jsx +27 -0
- package/src/__testdata__/item-renderer_testdata.js +161 -0
- package/src/__testdata__/renderer_testdata.js +123 -0
- package/src/__tests__/__snapshots__/item-renderer_test.jsx.snap +233 -0
- package/src/__tests__/__snapshots__/perseus-markdown_test.jsx.snap +516 -0
- package/src/__tests__/__snapshots__/pure-markdown_test.js.snap +113 -0
- package/src/__tests__/__snapshots__/renderer_test.jsx.snap +576 -0
- package/src/__tests__/__snapshots__/server-item-renderer_test.jsx.snap +306 -0
- package/src/__tests__/a11y_test.jsx +304 -0
- package/src/__tests__/item-renderer_test.jsx +892 -0
- package/src/__tests__/mock-asset-loading-widget.jsx +57 -0
- package/src/__tests__/mock-widget.jsx +35 -0
- package/src/__tests__/perseus-markdown_test.jsx +747 -0
- package/src/__tests__/pure-markdown_test.js +552 -0
- package/src/__tests__/renderability_test.jsx +481 -0
- package/src/__tests__/renderer-api_test.jsx +333 -0
- package/src/__tests__/renderer_test.jsx +1792 -0
- package/src/__tests__/server-item-renderer_test.jsx +516 -0
- package/src/__tests__/test-items/image-item.js +25 -0
- package/src/__tests__/test-items/input-number-1-item.js +27 -0
- package/src/__tests__/test-items/input-number-2-item.js +39 -0
- package/src/__tests__/test-items/table-item.js +30 -0
- package/src/__tests__/tex-wrangler_test.js +83 -0
- package/src/__tests__/util_test.js +41 -0
- package/src/a11y.js +46 -0
- package/src/all-widgets.js +9 -0
- package/src/article-renderer.jsx +215 -0
- package/src/asset-context.js +30 -0
- package/src/basic-widgets.js +13 -0
- package/src/components/__stories__/button-group.stories.jsx +61 -0
- package/src/components/__stories__/fixed-to-responsive.stories.jsx +132 -0
- package/src/components/__stories__/graph.stories.jsx +27 -0
- package/src/components/__stories__/graphie.stories.jsx +28 -0
- package/src/components/__stories__/hud.stories.jsx +36 -0
- package/src/components/__stories__/icon.stories.jsx +56 -0
- package/src/components/__stories__/image-loader.stories.jsx +60 -0
- package/src/components/__stories__/info-tip.stories.jsx +33 -0
- package/src/components/__stories__/inline-icon.stories.jsx +39 -0
- package/src/components/__stories__/input-with-examples.stories.jsx +51 -0
- package/src/components/__stories__/lint.stories.jsx +40 -0
- package/src/components/__stories__/math-input.stories.jsx +29 -0
- package/src/components/__stories__/math-output.stories.jsx +24 -0
- package/src/components/__stories__/multi-button-group.stories.jsx +69 -0
- package/src/components/__stories__/number-input.stories.jsx +42 -0
- package/src/components/__stories__/possible-answers.stories.jsx +22 -0
- package/src/components/__stories__/prop-check-box.stories.jsx +62 -0
- package/src/components/__stories__/range-input.stories.jsx +28 -0
- package/src/components/__stories__/simple-keypad-input.stories.jsx +28 -0
- package/src/components/__stories__/sortable.stories.jsx +73 -0
- package/src/components/__stories__/stub-tag-editor.stories.jsx +44 -0
- package/src/components/__stories__/svg-image.stories.jsx +60 -0
- package/src/components/__stories__/tex.stories.jsx +18 -0
- package/src/components/__stories__/text-buttons.stories.jsx +51 -0
- package/src/components/__stories__/text-input.stories.jsx +34 -0
- package/src/components/__stories__/text-list-editor.stories.jsx +33 -0
- package/src/components/__stories__/zoomable-tex.stories.jsx +39 -0
- package/src/components/__stories__/zoomable.stories.jsx +40 -0
- package/src/components/__testdata__/sorter_testdata.js +20 -0
- package/src/components/__tests__/__snapshots__/sortable_test.jsx.snap +79 -0
- package/src/components/__tests__/__snapshots__/sorter_test.jsx.snap +297 -0
- package/src/components/__tests__/number-input_test.jsx +112 -0
- package/src/components/__tests__/sortable_test.jsx +234 -0
- package/src/components/__tests__/sorter_test.jsx +111 -0
- package/src/components/__tests__/zoomable_test.jsx +388 -0
- package/src/components/button-group.jsx +131 -0
- package/src/components/constants.js +15 -0
- package/src/components/fixed-to-responsive.jsx +164 -0
- package/src/components/graph.jsx +415 -0
- package/src/components/graphie-classes.jsx +148 -0
- package/src/components/graphie-movables.jsx +342 -0
- package/src/components/graphie.jsx +353 -0
- package/src/components/highlighting/highlightable-content.jsx +245 -0
- package/src/components/highlighting/highlights.js +208 -0
- package/src/components/highlighting/ranges.js +299 -0
- package/src/components/highlighting/types.js +73 -0
- package/src/components/highlighting/ui/highlight-renderer.jsx +179 -0
- package/src/components/highlighting/ui/highlight-set-renderer.jsx +190 -0
- package/src/components/highlighting/ui/highlight-tooltip.jsx +153 -0
- package/src/components/highlighting/ui/highlighting-ui.jsx +163 -0
- package/src/components/highlighting/ui/selection-tracker.jsx +195 -0
- package/src/components/highlighting/ui/types.js +21 -0
- package/src/components/highlighting/ui/util.js +166 -0
- package/src/components/highlighting/word-indexer.jsx +155 -0
- package/src/components/hud.jsx +179 -0
- package/src/components/icon.jsx +149 -0
- package/src/components/image-loader.jsx +175 -0
- package/src/components/info-tip/info-tip.jsx +146 -0
- package/src/components/info-tip.jsx +38 -0
- package/src/components/inline-icon.jsx +81 -0
- package/src/components/input-with-examples.jsx +231 -0
- package/src/components/lint.jsx +454 -0
- package/src/components/math-input.jsx +282 -0
- package/src/components/math-output.jsx +128 -0
- package/src/components/multi-button-group.jsx +137 -0
- package/src/components/new-tooltip/README.md +110 -0
- package/src/components/new-tooltip/__stories__/flexible-position.stories.jsx +437 -0
- package/src/components/new-tooltip/__stories__/new-tooltip.stories.jsx +665 -0
- package/src/components/new-tooltip/__stories__/tooltip-arrow.stories.jsx +70 -0
- package/src/components/new-tooltip/__stories__/tooltip-bubble.stories.jsx +98 -0
- package/src/components/new-tooltip/__tests__/style-constants_test.js +8 -0
- package/src/components/new-tooltip/__tests__/util_test.js +47 -0
- package/src/components/new-tooltip/flexible-position.jsx +182 -0
- package/src/components/new-tooltip/new-tooltip.jsx +399 -0
- package/src/components/new-tooltip/style-constants.js +13 -0
- package/src/components/new-tooltip/tooltip-arrow.jsx +184 -0
- package/src/components/new-tooltip/tooltip-bubble.jsx +223 -0
- package/src/components/new-tooltip/tooltip-portal.jsx +101 -0
- package/src/components/new-tooltip/tooltip-positioner.jsx +529 -0
- package/src/components/new-tooltip/types.js +183 -0
- package/src/components/new-tooltip/util.js +27 -0
- package/src/components/number-input.jsx +253 -0
- package/src/components/possible-answers.jsx +36 -0
- package/src/components/prop-check-box.jsx +80 -0
- package/src/components/range-input.jsx +61 -0
- package/src/components/simple-keypad-input.jsx +91 -0
- package/src/components/sortable.jsx +873 -0
- package/src/components/stub-tag-editor.jsx +54 -0
- package/src/components/svg-image.jsx +762 -0
- package/src/components/tex-buttons.jsx +322 -0
- package/src/components/tex.jsx +70 -0
- package/src/components/text-input.jsx +82 -0
- package/src/components/text-list-editor.jsx +157 -0
- package/src/components/tooltip.jsx +395 -0
- package/src/components/visibility-observer/__stories__/visibility-observer.stories.jsx +140 -0
- package/src/components/visibility-observer/get-scroll-parent.js +45 -0
- package/src/components/visibility-observer/visibility-observer.js +109 -0
- package/src/components/visibility-observer/visibility-observer.jsx +123 -0
- package/src/components/zoomable-tex.jsx +70 -0
- package/src/components/zoomable.jsx +304 -0
- package/src/components.js +17 -0
- package/src/dependencies.js +22 -0
- package/src/error-boundary.jsx +48 -0
- package/src/extra-widgets.js +75 -0
- package/src/gorgon/README +40 -0
- package/src/gorgon/__tests__/matcher_test.js +497 -0
- package/src/gorgon/__tests__/rule_test.js +101 -0
- package/src/gorgon/__tests__/rules_test.js +487 -0
- package/src/gorgon/__tests__/selector-parser_test.js +52 -0
- package/src/gorgon/__tests__/tree-transformer_test.js +446 -0
- package/src/gorgon/gorgon.js +290 -0
- package/src/gorgon/proptypes.js +29 -0
- package/src/gorgon/rule.js +413 -0
- package/src/gorgon/rules/absolute-url.js +24 -0
- package/src/gorgon/rules/all-rules.js +72 -0
- package/src/gorgon/rules/blockquoted-math.js +10 -0
- package/src/gorgon/rules/blockquoted-widget.js +10 -0
- package/src/gorgon/rules/double-spacing-after-terminal.js +12 -0
- package/src/gorgon/rules/extra-content-spacing.js +12 -0
- package/src/gorgon/rules/heading-level-1.js +14 -0
- package/src/gorgon/rules/heading-level-skip.js +20 -0
- package/src/gorgon/rules/heading-sentence-case.js +11 -0
- package/src/gorgon/rules/heading-title-case.js +63 -0
- package/src/gorgon/rules/image-alt-text.js +21 -0
- package/src/gorgon/rules/image-in-table.js +10 -0
- package/src/gorgon/rules/image-spaces-around-urls.js +35 -0
- package/src/gorgon/rules/image-widget.js +50 -0
- package/src/gorgon/rules/link-click-here.js +11 -0
- package/src/gorgon/rules/lint-utils.js +48 -0
- package/src/gorgon/rules/long-paragraph.js +14 -0
- package/src/gorgon/rules/math-adjacent.js +10 -0
- package/src/gorgon/rules/math-align-extra-break.js +11 -0
- package/src/gorgon/rules/math-align-linebreaks.js +43 -0
- package/src/gorgon/rules/math-empty.js +10 -0
- package/src/gorgon/rules/math-font-size.js +12 -0
- package/src/gorgon/rules/math-frac.js +10 -0
- package/src/gorgon/rules/math-nested.js +11 -0
- package/src/gorgon/rules/math-starts-with-space.js +12 -0
- package/src/gorgon/rules/math-text-empty.js +10 -0
- package/src/gorgon/rules/math-without-dollars.js +14 -0
- package/src/gorgon/rules/nested-lists.js +11 -0
- package/src/gorgon/rules/profanity.js +10 -0
- package/src/gorgon/rules/table-missing-cells.js +20 -0
- package/src/gorgon/rules/unbalanced-code-delimiters.js +14 -0
- package/src/gorgon/rules/unescaped-dollar.js +10 -0
- package/src/gorgon/rules/widget-in-table.js +10 -0
- package/src/gorgon/selector.js +506 -0
- package/src/gorgon/tree-transformer.js +588 -0
- package/src/hint-renderer.jsx +159 -0
- package/src/hints-renderer.jsx +359 -0
- package/src/icon-paths.js +120 -0
- package/src/index.js +149 -2
- package/src/init.js +49 -0
- package/src/interaction-tracker.js +60 -0
- package/src/interactive2/__tests__/movable-mock.js +48 -0
- package/src/interactive2/__tests__/movable-point_test.js +146 -0
- package/src/interactive2/interactive-util.js +152 -0
- package/src/interactive2/movable-helper-methods.js +160 -0
- package/src/interactive2/movable-line-options.js +392 -0
- package/src/interactive2/movable-line.js +322 -0
- package/src/interactive2/movable-point-options.js +190 -0
- package/src/interactive2/movable-point.jsx +603 -0
- package/src/interactive2/movable-polygon-options.js +351 -0
- package/src/interactive2/movable-polygon.js +368 -0
- package/src/interactive2/movable.js +273 -0
- package/src/interactive2/objective_.js +79 -0
- package/src/interactive2/types.js +3 -0
- package/src/interactive2/wrapped-defaults.js +86 -0
- package/src/interactive2/wrapped-ellipse.js +87 -0
- package/src/interactive2/wrapped-line.js +109 -0
- package/src/interactive2/wrapped-path.js +47 -0
- package/src/interactive2.js +91 -0
- package/src/item-renderer.jsx +518 -0
- package/src/item-version.js +12 -0
- package/src/jipt-paragraphs.js +44 -0
- package/src/jquery.mobile.vmouse.js +545 -0
- package/src/keypad-context.js +33 -0
- package/src/loading-context.js +20 -0
- package/src/logging/log.js +107 -0
- package/src/logging/log_test.js +41 -0
- package/src/mixins/changeable.jsx +115 -0
- package/src/mixins/editor-jsonify.jsx +13 -0
- package/src/mixins/provide-keypad.jsx +129 -0
- package/src/mixins/widget-jsonify-deprecated.jsx +23 -0
- package/src/mixins/widget-prop-blacklist.js +36 -0
- package/src/multi-items/__stories__/multi-renderer.stories.js +88 -0
- package/src/multi-items/__testdata__/multi-renderer_testdata.js +174 -0
- package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +994 -0
- package/src/multi-items/__tests__/items_test.js +245 -0
- package/src/multi-items/__tests__/multi-renderer_test.js +903 -0
- package/src/multi-items/__tests__/prop-type-builders_test.js +134 -0
- package/src/multi-items/__tests__/shapes_test.js +44 -0
- package/src/multi-items/__tests__/trees_test.js +316 -0
- package/src/multi-items/item-types.js +55 -0
- package/src/multi-items/items.js +176 -0
- package/src/multi-items/multi-renderer.jsx +543 -0
- package/src/multi-items/prop-type-builders.js +105 -0
- package/src/multi-items/shape-types.js +47 -0
- package/src/multi-items/shapes.js +53 -0
- package/src/multi-items/tree-types.js +42 -0
- package/src/multi-items/trees.js +345 -0
- package/src/multi-items.js +76 -0
- package/src/not-gorgon.js +129 -0
- package/src/perseus-api.jsx +270 -0
- package/src/perseus-env.js +26 -0
- package/src/perseus-error.js +19 -0
- package/src/perseus-markdown.jsx +433 -0
- package/src/perseus-types.js +1597 -0
- package/src/pure-markdown.js +347 -0
- package/src/question-paragraph.jsx +30 -0
- package/src/renderability.jsx +108 -0
- package/src/renderer.jsx +1932 -0
- package/src/server-item-renderer.jsx +467 -0
- package/src/sigfigs.jsx +492 -0
- package/src/styles/articles.less +748 -0
- package/src/styles/constants.js +119 -0
- package/src/styles/global-constants.js +350 -0
- package/src/styles/global-styles.js +307 -0
- package/src/styles/khan-exercise.css +1304 -0
- package/src/styles/media-queries.js +48 -0
- package/src/styles/perseus-renderer.less +1007 -0
- package/src/styles/shared.js +132 -0
- package/src/styles/util.less +47 -0
- package/src/styles/variables.boostrap.less +301 -0
- package/src/styles/variables.less +68 -0
- package/src/styles/variables.shared.less +356 -0
- package/src/styles/widgets/categorizer.less +39 -0
- package/src/styles/widgets/definition.less +86 -0
- package/src/styles/widgets/dropdown.less +3 -0
- package/src/styles/widgets/expression.less +147 -0
- package/src/styles/widgets/graded-group.less +36 -0
- package/src/styles/widgets/grapher.less +11 -0
- package/src/styles/widgets/group.less +19 -0
- package/src/styles/widgets/image.less +29 -0
- package/src/styles/widgets/interactive-graph.less +61 -0
- package/src/styles/widgets/label-image.less +41 -0
- package/src/styles/widgets/matcher.less +8 -0
- package/src/styles/widgets/matrix.less +120 -0
- package/src/styles/widgets/measurer.less +20 -0
- package/src/styles/widgets/orderer.less +97 -0
- package/src/styles/widgets/passage.less +151 -0
- package/src/styles/widgets/plotter.less +33 -0
- package/src/styles/widgets/radio.less +52 -0
- package/src/styles/widgets/reaction-diagram.less +35 -0
- package/src/styles/widgets/sequence.less +5 -0
- package/src/styles/widgets/sortable.less +127 -0
- package/src/styles/widgets/table.less +56 -0
- package/src/styles/widgets/transformer.less +28 -0
- package/src/styles/widgets/unit.less +14 -0
- package/src/tex-wrangler.js +176 -0
- package/src/traversal.jsx +141 -0
- package/src/types.js +538 -0
- package/src/util/a11y.js +24 -0
- package/src/util/answer-types.js +862 -0
- package/src/util/answer-types_test.js +115 -0
- package/src/util/colors.js +94 -0
- package/src/util/fix-passage-refs.jsx +122 -0
- package/src/util/graph-utils.js +16 -0
- package/src/util/graphie.js +1586 -0
- package/src/util/interactive.js +4078 -0
- package/src/util/katex-preprocess.js +16 -0
- package/src/util/math.js +296 -0
- package/src/util/mobile-native-utils.js +14 -0
- package/src/util/mobile-native-utils_test.js +24 -0
- package/src/util/register-all-widgets-for-testing.js +12 -0
- package/src/util/scroll-utils.js +162 -0
- package/src/util/sizing-utils.js +46 -0
- package/src/util/tex.js +203 -0
- package/src/util/url-utils.js +36 -0
- package/src/util.js +990 -0
- package/src/version.js +11 -0
- package/src/widget-container.jsx +174 -0
- package/src/widgets/__stories__/categorizer.stories.jsx +15 -0
- package/src/widgets/__stories__/cs-program.stories.jsx +15 -0
- package/src/widgets/__stories__/definition.stories.jsx +38 -0
- package/src/widgets/__stories__/dropdown.stories.jsx +15 -0
- package/src/widgets/__stories__/explanation.stories.jsx +19 -0
- package/src/widgets/__stories__/expression.stories.jsx +26 -0
- package/src/widgets/__stories__/graded-group-set.stories.jsx +32 -0
- package/src/widgets/__stories__/graded-group.stories.jsx +32 -0
- package/src/widgets/__stories__/grapher.stories.jsx +47 -0
- package/src/widgets/__stories__/group.stories.jsx +15 -0
- package/src/widgets/__stories__/iframe.stories.jsx +15 -0
- package/src/widgets/__stories__/image.stories.jsx +62 -0
- package/src/widgets/__stories__/input-number.stories.jsx +90 -0
- package/src/widgets/__stories__/interaction.stories.jsx +15 -0
- package/src/widgets/__stories__/interactive-graph.stories.jsx +61 -0
- package/src/widgets/__stories__/matcher.stories.jsx +15 -0
- package/src/widgets/__stories__/matrix.stories.jsx +15 -0
- package/src/widgets/__stories__/number-line.stories.jsx +15 -0
- package/src/widgets/__stories__/numeric-input.stories.jsx +19 -0
- package/src/widgets/__stories__/orderer.stories.jsx +15 -0
- package/src/widgets/__stories__/passage-ref.stories.jsx +19 -0
- package/src/widgets/__stories__/passage.stories.jsx +19 -0
- package/src/widgets/__stories__/radio.stories.jsx +82 -0
- package/src/widgets/__stories__/sorter.stories.jsx +15 -0
- package/src/widgets/__stories__/transformer.stories.jsx +15 -0
- package/src/widgets/__stories__/unit.stories.jsx +45 -0
- package/src/widgets/__stories__/video-transcript-link.stories.jsx +24 -0
- package/src/widgets/__stories__/video.stories.jsx +15 -0
- package/src/widgets/__testdata__/categorizer_testdata.js +50 -0
- package/src/widgets/__testdata__/cs-program_testdata.js +28 -0
- package/src/widgets/__testdata__/dropdown_testdata.js +34 -0
- package/src/widgets/__testdata__/explanation_testdata.js +56 -0
- package/src/widgets/__testdata__/expression_testdata.js +95 -0
- package/src/widgets/__testdata__/graded-group-set_testdata.js +358 -0
- package/src/widgets/__testdata__/graded-group_testdata.js +79 -0
- package/src/widgets/__testdata__/grapher_testdata.js +376 -0
- package/src/widgets/__testdata__/group_testdata.js +156 -0
- package/src/widgets/__testdata__/iframe_testdata.js +36 -0
- package/src/widgets/__testdata__/image_testdata.js +38 -0
- package/src/widgets/__testdata__/input-number_testdata.js +73 -0
- package/src/widgets/__testdata__/interaction_testdata.js +264 -0
- package/src/widgets/__testdata__/interactive-graph_testdata.js +646 -0
- package/src/widgets/__testdata__/matcher_testdata.js +34 -0
- package/src/widgets/__testdata__/matrix_testdata.js +29 -0
- package/src/widgets/__testdata__/number-line_testdata.js +31 -0
- package/src/widgets/__testdata__/numeric-input_testdata.js +266 -0
- package/src/widgets/__testdata__/orderer_testdata.js +58 -0
- package/src/widgets/__testdata__/passage-ref_testdata.js +41 -0
- package/src/widgets/__testdata__/passage_testdata.js +71 -0
- package/src/widgets/__testdata__/radio_testdata.js +210 -0
- package/src/widgets/__testdata__/sorter_testdata.js +20 -0
- package/src/widgets/__testdata__/transformer_testdata.js +109 -0
- package/src/widgets/__testdata__/video_testdata.js +22 -0
- package/src/widgets/__tests__/__snapshots__/categorizer_test.jsx.snap +928 -0
- package/src/widgets/__tests__/__snapshots__/cs-program_test.jsx.snap +75 -0
- package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +99 -0
- package/src/widgets/__tests__/__snapshots__/dropdown_test.jsx.snap +143 -0
- package/src/widgets/__tests__/__snapshots__/explanation_test.js.snap +473 -0
- package/src/widgets/__tests__/__snapshots__/expression_test.jsx.snap +38 -0
- package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt_test.jsx.snap +754 -0
- package/src/widgets/__tests__/__snapshots__/graded-group-set_test.jsx.snap +310 -0
- package/src/widgets/__tests__/__snapshots__/graded-group_test.jsx.snap +863 -0
- package/src/widgets/__tests__/__snapshots__/grapher_test.jsx.snap +2880 -0
- package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +1154 -0
- package/src/widgets/__tests__/__snapshots__/iframe_test.jsx.snap +69 -0
- package/src/widgets/__tests__/__snapshots__/image_test.jsx.snap +388 -0
- package/src/widgets/__tests__/__snapshots__/input-number_test.jsx.snap +978 -0
- package/src/widgets/__tests__/__snapshots__/interaction_test.jsx.snap +311 -0
- package/src/widgets/__tests__/__snapshots__/interactive-graph_test.jsx.snap +2915 -0
- package/src/widgets/__tests__/__snapshots__/matcher_test.jsx.snap +1039 -0
- package/src/widgets/__tests__/__snapshots__/matrix_test.jsx.snap +450 -0
- package/src/widgets/__tests__/__snapshots__/number-line_test.jsx.snap +888 -0
- package/src/widgets/__tests__/__snapshots__/numeric-input_test.jsx.snap +930 -0
- package/src/widgets/__tests__/__snapshots__/orderer_test.jsx.snap +275 -0
- package/src/widgets/__tests__/__snapshots__/passage-ref_test.jsx.snap +446 -0
- package/src/widgets/__tests__/__snapshots__/passage_test.jsx.snap +1988 -0
- package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +7107 -0
- package/src/widgets/__tests__/__snapshots__/video_test.jsx.snap +163 -0
- package/src/widgets/__tests__/categorizer_test.jsx +205 -0
- package/src/widgets/__tests__/cs-program_test.jsx +45 -0
- package/src/widgets/__tests__/definition_test.js +152 -0
- package/src/widgets/__tests__/dropdown_test.jsx +106 -0
- package/src/widgets/__tests__/explanation_test.js +199 -0
- package/src/widgets/__tests__/expression_test.jsx +439 -0
- package/src/widgets/__tests__/graded-group-set-jipt_test.jsx +33 -0
- package/src/widgets/__tests__/graded-group-set_test.jsx +270 -0
- package/src/widgets/__tests__/graded-group_test.jsx +233 -0
- package/src/widgets/__tests__/grapher.cypress.jsx +486 -0
- package/src/widgets/__tests__/grapher_test.jsx +35 -0
- package/src/widgets/__tests__/group_test.jsx +512 -0
- package/src/widgets/__tests__/iframe_test.jsx +47 -0
- package/src/widgets/__tests__/image_test.jsx +65 -0
- package/src/widgets/__tests__/input-number_test.jsx +360 -0
- package/src/widgets/__tests__/interaction_test.jsx +33 -0
- package/src/widgets/__tests__/interactive-graph.cypress.jsx +697 -0
- package/src/widgets/__tests__/interactive-graph_test.jsx +105 -0
- package/src/widgets/__tests__/matcher_test.jsx +157 -0
- package/src/widgets/__tests__/matrix_test.jsx +84 -0
- package/src/widgets/__tests__/number-line_test.jsx +81 -0
- package/src/widgets/__tests__/numeric-input_test.jsx +574 -0
- package/src/widgets/__tests__/orderer_test.jsx +75 -0
- package/src/widgets/__tests__/passage-ref_test.jsx +166 -0
- package/src/widgets/__tests__/passage_test.jsx +133 -0
- package/src/widgets/__tests__/radio/base-radio_test.jsx +82 -0
- package/src/widgets/__tests__/radio_test.jsx +651 -0
- package/src/widgets/__tests__/renderQuestion.jsx +66 -0
- package/src/widgets/__tests__/unit_test.jsx +144 -0
- package/src/widgets/__tests__/video_test.jsx +55 -0
- package/src/widgets/categorizer.jsx +338 -0
- package/src/widgets/cs-program.jsx +227 -0
- package/src/widgets/definition.jsx +141 -0
- package/src/widgets/dropdown.jsx +143 -0
- package/src/widgets/explanation.jsx +315 -0
- package/src/widgets/expression.jsx +652 -0
- package/src/widgets/graded-group-answer-bar.jsx +152 -0
- package/src/widgets/graded-group-set.jsx +285 -0
- package/src/widgets/graded-group.jsx +448 -0
- package/src/widgets/grapher/util.jsx +806 -0
- package/src/widgets/grapher.jsx +663 -0
- package/src/widgets/group.jsx +213 -0
- package/src/widgets/iframe.jsx +198 -0
- package/src/widgets/image.jsx +310 -0
- package/src/widgets/input-number.jsx +411 -0
- package/src/widgets/interaction/arrow-picker.jsx +39 -0
- package/src/widgets/interaction/color-picker.jsx +69 -0
- package/src/widgets/interaction/dash-picker.jsx +46 -0
- package/src/widgets/interaction/element-container.jsx +97 -0
- package/src/widgets/interaction.jsx +742 -0
- package/src/widgets/interactive-graph.jsx +2820 -0
- package/src/widgets/label-image/__stories__/answer-choices.stories.jsx +93 -0
- package/src/widgets/label-image/__stories__/marker.stories.jsx +172 -0
- package/src/widgets/label-image/answer-choices.jsx +311 -0
- package/src/widgets/label-image/marker.jsx +365 -0
- package/src/widgets/label-image/types.js +33 -0
- package/src/widgets/label-image.jsx +841 -0
- package/src/widgets/label-image_test.js +840 -0
- package/src/widgets/lights-puzzle.jsx +356 -0
- package/src/widgets/matcher.jsx +271 -0
- package/src/widgets/matrix.jsx +616 -0
- package/src/widgets/measurer.jsx +215 -0
- package/src/widgets/molecule/__tests__/layout_test.jsx +159 -0
- package/src/widgets/molecule/__tests__/parser_test.jsx +142 -0
- package/src/widgets/molecule/molecule-drawing.jsx +175 -0
- package/src/widgets/molecule/molecule-layout.jsx +367 -0
- package/src/widgets/molecule/smiles-parser.jsx +300 -0
- package/src/widgets/molecule.jsx +172 -0
- package/src/widgets/number-line.jsx +858 -0
- package/src/widgets/numeric-input.jsx +622 -0
- package/src/widgets/orderer.jsx +753 -0
- package/src/widgets/passage/__tests__/passage-markdown_test.jsx +382 -0
- package/src/widgets/passage/get-line-height-for-node.js +10 -0
- package/src/widgets/passage/passage-markdown.jsx +416 -0
- package/src/widgets/passage-ref-target.jsx +70 -0
- package/src/widgets/passage-ref.jsx +198 -0
- package/src/widgets/passage.jsx +601 -0
- package/src/widgets/plotter.jsx +1198 -0
- package/src/widgets/radio/__stories__/base-radio.stories.jsx +40 -0
- package/src/widgets/radio/__stories__/choice-icon.stories.jsx +157 -0
- package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +26 -0
- package/src/widgets/radio/__stories__/cross-out-button.stories.jsx +64 -0
- package/src/widgets/radio/__stories__/cross-out-menu.stories.jsx +59 -0
- package/src/widgets/radio/__stories__/cross-out-tooltip.stories.jsx +59 -0
- package/src/widgets/radio/__stories__/focus-ring.stories.jsx +38 -0
- package/src/widgets/radio/__stories__/option-status.stories.jsx +118 -0
- package/src/widgets/radio/__stories__/toggleable-radio-button.stories.jsx +28 -0
- package/src/widgets/radio/base-radio.jsx +642 -0
- package/src/widgets/radio/choice-icon.jsx +468 -0
- package/src/widgets/radio/choice-none-above.jsx +54 -0
- package/src/widgets/radio/choice.jsx +692 -0
- package/src/widgets/radio/choice.jsx.fixture.js +64 -0
- package/src/widgets/radio/cross-out-button.jsx +136 -0
- package/src/widgets/radio/cross-out-menu-wrapper.jsx +492 -0
- package/src/widgets/radio/cross-out-tooltip.jsx +129 -0
- package/src/widgets/radio/focus-ring.jsx +51 -0
- package/src/widgets/radio/option-status.jsx +89 -0
- package/src/widgets/radio/toggleable-radio-button.jsx +133 -0
- package/src/widgets/radio/util.js +32 -0
- package/src/widgets/radio/util_test.js +19 -0
- package/src/widgets/radio/widget.jsx +470 -0
- package/src/widgets/radio.jsx +156 -0
- package/src/widgets/reaction-diagram.jsx +137 -0
- package/src/widgets/sequence.jsx +140 -0
- package/src/widgets/simulator.jsx +808 -0
- package/src/widgets/sorter.jsx +146 -0
- package/src/widgets/table.jsx +394 -0
- package/src/widgets/transformer.jsx +2876 -0
- package/src/widgets/unit.jsx +372 -0
- package/src/widgets/video-transcript-link.jsx +84 -0
- package/src/widgets/video-transcript-link_test.js +211 -0
- package/src/widgets/video.jsx +126 -0
- package/src/widgets.js +431 -0
- package/src/zoom.js +539 -0
- package/README.md +0 -3
- package/src/__tests__/index.test.js +0 -14
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
/**
|
|
3
|
+
* This is a wrapper component for the visibility-observer.js utility which
|
|
4
|
+
* abstracts the native or polyfilled IntersectionObserver utility. The
|
|
5
|
+
* primary purpose of this comonent is to tell you whether the children of
|
|
6
|
+
* the component are visibile within a scrollable ancestor. It will notify
|
|
7
|
+
* you via an onChange event when the visibility changes, and whether the
|
|
8
|
+
* children are below or above the scroll.
|
|
9
|
+
*/
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import ReactDOM from "react-dom";
|
|
12
|
+
|
|
13
|
+
import {getScrollParent} from "./get-scroll-parent.js";
|
|
14
|
+
import {createVisibilityObserver} from "./visibility-observer.js";
|
|
15
|
+
|
|
16
|
+
import type {VisibilityObserver as IVisibilityObserver} from "./visibility-observer.js";
|
|
17
|
+
|
|
18
|
+
export type ScrollVisibility =
|
|
19
|
+
| "hidden-above"
|
|
20
|
+
| "hidden-below"
|
|
21
|
+
| "visible"
|
|
22
|
+
| "unknown";
|
|
23
|
+
|
|
24
|
+
type Props = {|
|
|
25
|
+
children: React.Node,
|
|
26
|
+
rootMargin?: string,
|
|
27
|
+
|
|
28
|
+
// In most cases, the scroll parent we want to compare against is the body. Sometimes,
|
|
29
|
+
// there will be a scroll parent which scrolls independant of the body. In that case,
|
|
30
|
+
// the math is different and we need to be told to find the scroll parent.
|
|
31
|
+
scrollParentIsNotBody?: boolean,
|
|
32
|
+
|
|
33
|
+
onChange: (visibility: ScrollVisibility) => void,
|
|
34
|
+
|};
|
|
35
|
+
|
|
36
|
+
function findPositionInScrollContainer(
|
|
37
|
+
childNode: HTMLElement,
|
|
38
|
+
bounds: DOMRectReadOnly,
|
|
39
|
+
scrollParentIsNotBody: boolean,
|
|
40
|
+
): ScrollVisibility {
|
|
41
|
+
try {
|
|
42
|
+
const scrollParent = getScrollParent(childNode);
|
|
43
|
+
if (!scrollParent) {
|
|
44
|
+
return "unknown";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const parentRect = scrollParent.getBoundingClientRect();
|
|
48
|
+
const childRect = childNode.getBoundingClientRect();
|
|
49
|
+
|
|
50
|
+
const isAbove =
|
|
51
|
+
!scrollParentIsNotBody || scrollParent === document.body
|
|
52
|
+
? childRect.bottom < bounds.top
|
|
53
|
+
: childRect.bottom < parentRect.top;
|
|
54
|
+
|
|
55
|
+
return isAbove ? "hidden-above" : "hidden-below";
|
|
56
|
+
} catch (e) {
|
|
57
|
+
return "unknown";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class VisibilityObserver extends React.Component<Props> {
|
|
62
|
+
_observer: IVisibilityObserver;
|
|
63
|
+
_node: HTMLElement;
|
|
64
|
+
|
|
65
|
+
static defaultProps: {|onChange: () => void|} = {
|
|
66
|
+
onChange: () => {},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
componentDidMount() {
|
|
70
|
+
this._node = ((ReactDOM.findDOMNode(this): any): HTMLElement);
|
|
71
|
+
|
|
72
|
+
this.registerVisibilityObserver();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
componentWillUnmount() {
|
|
76
|
+
this.unregisterVisibilityObserver();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
handleVisibilityChange: (
|
|
80
|
+
isVisible: boolean,
|
|
81
|
+
rootBounds: DOMRectReadOnly,
|
|
82
|
+
) => void = (isVisible: boolean, rootBounds: DOMRectReadOnly) => {
|
|
83
|
+
const {scrollParentIsNotBody, onChange} = this.props;
|
|
84
|
+
|
|
85
|
+
if (isVisible) {
|
|
86
|
+
onChange("visible");
|
|
87
|
+
} else {
|
|
88
|
+
const visibility = findPositionInScrollContainer(
|
|
89
|
+
this._node,
|
|
90
|
+
rootBounds,
|
|
91
|
+
!!scrollParentIsNotBody,
|
|
92
|
+
);
|
|
93
|
+
onChange(visibility);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
registerVisibilityObserver() {
|
|
98
|
+
const {rootMargin} = this.props;
|
|
99
|
+
if (!this._node) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this._observer = createVisibilityObserver(
|
|
104
|
+
null,
|
|
105
|
+
this.handleVisibilityChange,
|
|
106
|
+
rootMargin,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
this._observer.setTargetElement(this._node);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
unregisterVisibilityObserver() {
|
|
113
|
+
if (this._observer) {
|
|
114
|
+
this._observer.disconnect();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
render(): React.Node {
|
|
119
|
+
return this.props.children;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export default VisibilityObserver;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ZoomableTeX is a wrapper around TeX to be used on mobile. Without wrapping
|
|
5
|
+
* TeX we run into issues of measuring at the incorrect time resulting in bad
|
|
6
|
+
* measurements.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as React from "react";
|
|
10
|
+
|
|
11
|
+
import AssetContext from "../asset-context.js";
|
|
12
|
+
|
|
13
|
+
import TeX from "./tex.jsx";
|
|
14
|
+
import Zoomable from "./zoomable.jsx";
|
|
15
|
+
|
|
16
|
+
type Props = {|children: string|};
|
|
17
|
+
type State = {|isRendered: boolean|};
|
|
18
|
+
|
|
19
|
+
const computeMathBounds = (parentNode, parentBounds) => {
|
|
20
|
+
const textElement =
|
|
21
|
+
parentNode.querySelector(".katex-html") ||
|
|
22
|
+
parentNode.querySelector(".MathJax");
|
|
23
|
+
const textBounds = {
|
|
24
|
+
// $FlowFixMe[incompatible-use]
|
|
25
|
+
width: textElement.offsetWidth,
|
|
26
|
+
// $FlowFixMe[incompatible-use]
|
|
27
|
+
height: textElement.offsetHeight,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// HACK(benkomalo): when measuring math content, note that
|
|
31
|
+
// sometimes it actually peeks outside of the
|
|
32
|
+
// container in some cases. Just be conservative and use
|
|
33
|
+
// the maximum value of the text and the parent. :(
|
|
34
|
+
return {
|
|
35
|
+
width: Math.max(parentBounds.width, textBounds.width),
|
|
36
|
+
height: Math.max(parentBounds.height, textBounds.height),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default class ZoomableTeX extends React.Component<Props, State> {
|
|
41
|
+
constructor() {
|
|
42
|
+
super();
|
|
43
|
+
|
|
44
|
+
this.state = {isRendered: false};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
handleRender: () => void = () => {
|
|
48
|
+
this.setState({isRendered: true});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
render(): React.Node {
|
|
52
|
+
return (
|
|
53
|
+
<Zoomable
|
|
54
|
+
readyToMeasure={this.state.isRendered}
|
|
55
|
+
computeChildBounds={computeMathBounds}
|
|
56
|
+
>
|
|
57
|
+
<AssetContext.Consumer>
|
|
58
|
+
{({setAssetStatus}) => (
|
|
59
|
+
<TeX
|
|
60
|
+
onRender={this.handleRender}
|
|
61
|
+
setAssetStatus={setAssetStatus}
|
|
62
|
+
>
|
|
63
|
+
{this.props.children}
|
|
64
|
+
</TeX>
|
|
65
|
+
)}
|
|
66
|
+
</AssetContext.Consumer>
|
|
67
|
+
</Zoomable>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
/**
|
|
3
|
+
* Zooms child to fit with tap-to-zoom behavior.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import ReactDOM from "react-dom";
|
|
8
|
+
|
|
9
|
+
type Bounds = {|
|
|
10
|
+
width: number,
|
|
11
|
+
height: number,
|
|
12
|
+
|};
|
|
13
|
+
|
|
14
|
+
type Props = {|
|
|
15
|
+
children: React.Node,
|
|
16
|
+
animateHeight: boolean,
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Optional function that allows customizations in zooming.
|
|
20
|
+
*
|
|
21
|
+
* Defaults to just using the bounding client rect of the first DOM
|
|
22
|
+
* element of this component.
|
|
23
|
+
*/
|
|
24
|
+
computeChildBounds: (
|
|
25
|
+
parentNode: HTMLElement,
|
|
26
|
+
parentBounds: Bounds,
|
|
27
|
+
) => Bounds,
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Optional boolean specifying whether the component is ready to measure
|
|
31
|
+
* or not. Defaults to true for synchronous components like tables.
|
|
32
|
+
*/
|
|
33
|
+
readyToMeasure: boolean,
|
|
34
|
+
|};
|
|
35
|
+
|
|
36
|
+
type DefaultProps = {|
|
|
37
|
+
animateHeight: Props["animateHeight"],
|
|
38
|
+
computeChildBounds: Props["computeChildBounds"],
|
|
39
|
+
readyToMeasure: Props["readyToMeasure"],
|
|
40
|
+
|};
|
|
41
|
+
|
|
42
|
+
type State = {|
|
|
43
|
+
visible: boolean,
|
|
44
|
+
marginBottomPx: number,
|
|
45
|
+
compactHeight?: ?number,
|
|
46
|
+
expandedHeight?: ?number,
|
|
47
|
+
scale?: ?number,
|
|
48
|
+
zoomed: boolean,
|
|
49
|
+
|};
|
|
50
|
+
|
|
51
|
+
class Zoomable extends React.Component<Props, State> {
|
|
52
|
+
_isMounted: boolean;
|
|
53
|
+
_observer: MutationObserver;
|
|
54
|
+
_measuringInitialized: boolean;
|
|
55
|
+
_originalWidth: ?number;
|
|
56
|
+
_node: HTMLElement;
|
|
57
|
+
|
|
58
|
+
static defaultProps: DefaultProps = {
|
|
59
|
+
animateHeight: false,
|
|
60
|
+
readyToMeasure: true,
|
|
61
|
+
computeChildBounds: (parentNode) => {
|
|
62
|
+
const firstChild = parentNode.firstElementChild;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
// $FlowFixMe[incompatible-use]
|
|
66
|
+
// $FlowFixMe[prop-missing]
|
|
67
|
+
width: firstChild.offsetWidth,
|
|
68
|
+
// $FlowFixMe[incompatible-use]
|
|
69
|
+
// $FlowFixMe[prop-missing]
|
|
70
|
+
height: firstChild.offsetHeight,
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
state: State = {
|
|
76
|
+
visible: false,
|
|
77
|
+
marginBottomPx: 0,
|
|
78
|
+
zoomed: true,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
componentDidMount() {
|
|
82
|
+
this._isMounted = true;
|
|
83
|
+
this.maybeInitializeMeasuring();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
componentDidUpdate() {
|
|
87
|
+
this.maybeInitializeMeasuring();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
componentWillUnmount() {
|
|
91
|
+
window.removeEventListener("resize", this.reset);
|
|
92
|
+
if (this._observer) {
|
|
93
|
+
this._observer.disconnect();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this._isMounted = false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
reset: () => void = (): void => {
|
|
100
|
+
if (!this._isMounted) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (!this.state.visible) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this._originalWidth = null;
|
|
107
|
+
this.setState(
|
|
108
|
+
{
|
|
109
|
+
visible: false,
|
|
110
|
+
compactHeight: null,
|
|
111
|
+
expandedHeight: null,
|
|
112
|
+
zoomed: true,
|
|
113
|
+
},
|
|
114
|
+
() => {
|
|
115
|
+
this.measureAndScaleChildToFit(false);
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Calls measureAndScaleChildToFit and sets up a MutationObserver
|
|
122
|
+
* to call measureAndScaleChildToFit if Zoomable's children change.
|
|
123
|
+
*
|
|
124
|
+
* If the readyToMeasure prop isn't true or if measuring has already
|
|
125
|
+
* been initialized this method does nothing.
|
|
126
|
+
*/
|
|
127
|
+
maybeInitializeMeasuring() {
|
|
128
|
+
const shouldInitialize =
|
|
129
|
+
this.props.readyToMeasure && !this._measuringInitialized;
|
|
130
|
+
|
|
131
|
+
if (this._isMounted && shouldInitialize) {
|
|
132
|
+
this._measuringInitialized = true;
|
|
133
|
+
// $FlowFixMe[incompatible-type] - this is our root node, it won't be text
|
|
134
|
+
this._node = ReactDOM.findDOMNode(this);
|
|
135
|
+
|
|
136
|
+
// We call measureAndScaleChildToFit asynchronously so that the browser
|
|
137
|
+
// can apply CSS styles so that we get an accurate measurement.
|
|
138
|
+
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API
|
|
139
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
140
|
+
setTimeout(() => this.measureAndScaleChildToFit(false), 0);
|
|
141
|
+
|
|
142
|
+
if (window.MutationObserver) {
|
|
143
|
+
this._observer = new MutationObserver((mutations) => {
|
|
144
|
+
if (this._isMounted) {
|
|
145
|
+
for (const mutation of mutations) {
|
|
146
|
+
if (mutation.target !== this._node) {
|
|
147
|
+
// Only act on mutations of children
|
|
148
|
+
this.measureAndScaleChildToFit(
|
|
149
|
+
this.state.zoomed,
|
|
150
|
+
);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
this._observer.observe(this._node, {
|
|
158
|
+
childList: true,
|
|
159
|
+
subtree: true,
|
|
160
|
+
attributes: true,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
window.addEventListener("resize", this.reset);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
stopPropagationIfZoomed: (e: SyntheticTouchEvent<>) => void = (
|
|
168
|
+
e: SyntheticTouchEvent<>,
|
|
169
|
+
) => {
|
|
170
|
+
if (!this.state.zoomed) {
|
|
171
|
+
// We only allow touch events (which trigger interactive elements)
|
|
172
|
+
// to be propagated to children if we are already zoomed.
|
|
173
|
+
e.stopPropagation();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// TODO(benkomalo): call this on viewport width changes?
|
|
178
|
+
// https://github.com/Khan/math-input/blob/master/src/components/math-keypad.js#L43
|
|
179
|
+
measureAndScaleChildToFit(zoomed: boolean) {
|
|
180
|
+
if (!this._isMounted) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const parentBounds = {
|
|
184
|
+
width: this._node.offsetWidth,
|
|
185
|
+
height: this._node.offsetHeight,
|
|
186
|
+
};
|
|
187
|
+
const childBounds = this.props.computeChildBounds(
|
|
188
|
+
this._node,
|
|
189
|
+
parentBounds,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
// The +1 is a fudge factor to make sure any border on the
|
|
193
|
+
// content isn't clipped by the the container it's in.
|
|
194
|
+
const childWidth = childBounds.width + 1;
|
|
195
|
+
const childHeight = childBounds.height + 1;
|
|
196
|
+
|
|
197
|
+
if (childWidth > parentBounds.width) {
|
|
198
|
+
const scale = parentBounds.width / childWidth;
|
|
199
|
+
|
|
200
|
+
this.setState({
|
|
201
|
+
scale,
|
|
202
|
+
zoomed,
|
|
203
|
+
|
|
204
|
+
compactHeight: Math.ceil(scale * childHeight),
|
|
205
|
+
expandedHeight: childHeight,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// TODO(charlie): Do this as a callback to `setState`. Something is
|
|
209
|
+
// going wrong with that approach in initial testing.
|
|
210
|
+
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API
|
|
211
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
212
|
+
setTimeout(() => {
|
|
213
|
+
// Only show it after the next paint, to allow for CSS
|
|
214
|
+
// transitions to fade it in.
|
|
215
|
+
if (this._isMounted) {
|
|
216
|
+
this.setState({
|
|
217
|
+
visible: true,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
} else {
|
|
222
|
+
this.setState({
|
|
223
|
+
visible: true,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
handleClickIfZoomed: (e: SyntheticMouseEvent<>) => void = (
|
|
229
|
+
e: SyntheticMouseEvent<>,
|
|
230
|
+
) => {
|
|
231
|
+
if (!this.state.zoomed) {
|
|
232
|
+
e.stopPropagation();
|
|
233
|
+
this.handleClick();
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
handleClick: () => void = () => {
|
|
238
|
+
this.setState({
|
|
239
|
+
zoomed: !this.state.zoomed,
|
|
240
|
+
});
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
render(): React.Node {
|
|
244
|
+
const {visible, scale, compactHeight, expandedHeight, zoomed} =
|
|
245
|
+
this.state;
|
|
246
|
+
const {animateHeight} = this.props;
|
|
247
|
+
|
|
248
|
+
const property = animateHeight
|
|
249
|
+
? "opacity transform height"
|
|
250
|
+
: "opacity transform";
|
|
251
|
+
|
|
252
|
+
// Since we're not using aphrodite, we have to prefix ourselves.
|
|
253
|
+
const transitionStyle = visible
|
|
254
|
+
? {
|
|
255
|
+
transitionProperty: property,
|
|
256
|
+
WebkitTransitionProperty: property,
|
|
257
|
+
msTransitionProperty: property,
|
|
258
|
+
transitionDuration: "0.3s",
|
|
259
|
+
WebkitTransitionDuration: "0.3s",
|
|
260
|
+
msTransitionDuration: "0.3s",
|
|
261
|
+
transitionTimingFunction: "ease-out",
|
|
262
|
+
WebkitTransitionTimingfunction: "ease-out",
|
|
263
|
+
msTransitionTmingFunction: "ease-out",
|
|
264
|
+
}
|
|
265
|
+
: {};
|
|
266
|
+
|
|
267
|
+
// Do a fancy little slide as we fade the contents in the first time.
|
|
268
|
+
const translateOffset = visible ? "" : " translate(0, 8px)";
|
|
269
|
+
const scaleString = (scale ?? 1).toString();
|
|
270
|
+
const transform = zoomed
|
|
271
|
+
? `scale(1, 1) ${translateOffset}`
|
|
272
|
+
: `scale(${scaleString}, ${scaleString}) ${translateOffset}`;
|
|
273
|
+
|
|
274
|
+
const style = {
|
|
275
|
+
display: "block",
|
|
276
|
+
width: "100%",
|
|
277
|
+
height: zoomed ? expandedHeight : compactHeight,
|
|
278
|
+
transform: transform,
|
|
279
|
+
WebkitTransform: transform,
|
|
280
|
+
msTransform: transform,
|
|
281
|
+
transformOrigin: "0 0",
|
|
282
|
+
WebkitTransformOrigin: "0 0",
|
|
283
|
+
msTransformOrigin: "0 0",
|
|
284
|
+
opacity: visible ? 1 : 0,
|
|
285
|
+
WebkitTapHighlightColor: "transparent",
|
|
286
|
+
...transitionStyle,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<span
|
|
291
|
+
onClick={this.handleClick}
|
|
292
|
+
onClickCapture={this.handleClickIfZoomed}
|
|
293
|
+
onTouchCancelCapture={this.stopPropagationIfZoomed}
|
|
294
|
+
onTouchEndCapture={this.stopPropagationIfZoomed}
|
|
295
|
+
onTouchStartCapture={this.stopPropagationIfZoomed}
|
|
296
|
+
style={style}
|
|
297
|
+
>
|
|
298
|
+
{this.props.children}
|
|
299
|
+
</span>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export default Zoomable;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
export {default as ButtonGroup} from "./components/button-group.jsx";
|
|
3
|
+
export {default as Graph} from "./components/graph.jsx";
|
|
4
|
+
export {default as Graphie} from "./components/graphie.jsx";
|
|
5
|
+
export {default as HUD} from "./components/hud.jsx";
|
|
6
|
+
export {default as Icon} from "./components/icon.jsx";
|
|
7
|
+
export {default as InfoTip} from "./components/info-tip.jsx";
|
|
8
|
+
export {default as InlineIcon} from "./components/inline-icon.jsx";
|
|
9
|
+
export {default as MathInput} from "./components/math-input.jsx";
|
|
10
|
+
export {default as MultiButtonGroup} from "./components/multi-button-group.jsx";
|
|
11
|
+
export {default as NumberInput} from "./components/number-input.jsx";
|
|
12
|
+
export {default as PropCheckBox} from "./components/prop-check-box.jsx";
|
|
13
|
+
export {default as RangeInput} from "./components/range-input.jsx";
|
|
14
|
+
export {default as SvgImage} from "./components/svg-image.jsx";
|
|
15
|
+
export {default as TextInput} from "./components/text-input.jsx";
|
|
16
|
+
export {default as TexButtons} from "./components/tex-buttons.jsx";
|
|
17
|
+
export {default as TextListEditor} from "./components/text-list-editor.jsx";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {PerseusDependencies} from "./types.js";
|
|
3
|
+
|
|
4
|
+
let _dependencies: ?PerseusDependencies = null;
|
|
5
|
+
|
|
6
|
+
export const setDependencies = (dependencies: PerseusDependencies) => {
|
|
7
|
+
_dependencies = dependencies;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getDependencies = (): PerseusDependencies => {
|
|
11
|
+
if (_dependencies) {
|
|
12
|
+
return _dependencies;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
throw new Error(
|
|
16
|
+
[
|
|
17
|
+
"Perseus has not been provided required dependencies.",
|
|
18
|
+
"setDependencies(dependencies) must be called first.",
|
|
19
|
+
"Make sure Perseus is being imported from javascript/perseus/perseus.js.",
|
|
20
|
+
].join("\n"),
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
import {Errors, Log} from "./logging/log.js";
|
|
6
|
+
|
|
7
|
+
type ErrorBoundaryProps = {|children: React.Node|};
|
|
8
|
+
type ErrorBoundaryState = {|error: string|};
|
|
9
|
+
|
|
10
|
+
class ErrorBoundary extends React.Component<
|
|
11
|
+
ErrorBoundaryProps,
|
|
12
|
+
ErrorBoundaryState,
|
|
13
|
+
> {
|
|
14
|
+
constructor(props: ErrorBoundaryProps) {
|
|
15
|
+
super(props);
|
|
16
|
+
this.state = {error: ""};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
componentDidCatch(error: Error, info: any) {
|
|
20
|
+
this.setState({error: error.toString()});
|
|
21
|
+
Log.error("Perseus error boundary caught error", Errors.Internal, {
|
|
22
|
+
cause: error,
|
|
23
|
+
loggedMetadata: {info: info.toString()},
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
render(): React.Node {
|
|
28
|
+
if (this.state.error) {
|
|
29
|
+
// TODO(djf): perhaps we should have one error boundary for
|
|
30
|
+
// inline elements and one for block elements. This one uses
|
|
31
|
+
// a <span> and effectively converts block elements with
|
|
32
|
+
// errors into inline elements.
|
|
33
|
+
// TODO(michaelpolyak): Link error icon to "Report a problem".
|
|
34
|
+
return (
|
|
35
|
+
<svg height="16" width="16" viewBox="0 0 16 16">
|
|
36
|
+
<path
|
|
37
|
+
d="m8 16c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm0-3c0.55 0 1-0.45 1-1s-0.45-1-1-1-1 0.45-1 1 0.45 1 1 1zm0-9c-0.55 0-1 0.45-1 1v4c0 0.55.45 1 1 1s1-0.45 1-1v-4c0-0.55-0.45-1-1-1z"
|
|
38
|
+
fill="#d92916"
|
|
39
|
+
fillRule="evenodd"
|
|
40
|
+
/>
|
|
41
|
+
</svg>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return this.props.children;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default ErrorBoundary;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
// As new widgets get added here, please also make sure they get added in
|
|
3
|
+
// content_internal/perseus_traversal.py so they can be properly translated.
|
|
4
|
+
|
|
5
|
+
import Categorizer from "./widgets/categorizer.jsx";
|
|
6
|
+
import CSProgram from "./widgets/cs-program.jsx";
|
|
7
|
+
import Definition from "./widgets/definition.jsx";
|
|
8
|
+
import Dropdown from "./widgets/dropdown.jsx";
|
|
9
|
+
import Explanation from "./widgets/explanation.jsx";
|
|
10
|
+
import GradedGroupSet from "./widgets/graded-group-set.jsx";
|
|
11
|
+
import GradedGroup from "./widgets/graded-group.jsx";
|
|
12
|
+
import Grapher from "./widgets/grapher.jsx";
|
|
13
|
+
import Group from "./widgets/group.jsx";
|
|
14
|
+
import Iframe from "./widgets/iframe.jsx";
|
|
15
|
+
import Image from "./widgets/image.jsx";
|
|
16
|
+
import Interactive from "./widgets/interaction.jsx";
|
|
17
|
+
import InteractiveGraph from "./widgets/interactive-graph.jsx";
|
|
18
|
+
import LabelImage from "./widgets/label-image.jsx";
|
|
19
|
+
import LightsPuzzle from "./widgets/lights-puzzle.jsx";
|
|
20
|
+
import Matcher from "./widgets/matcher.jsx";
|
|
21
|
+
import Matrix from "./widgets/matrix.jsx";
|
|
22
|
+
import Measurer from "./widgets/measurer.jsx";
|
|
23
|
+
import Molecule from "./widgets/molecule.jsx";
|
|
24
|
+
import NumberLine from "./widgets/number-line.jsx";
|
|
25
|
+
import Orderer from "./widgets/orderer.jsx";
|
|
26
|
+
import PassageRefTarget from "./widgets/passage-ref-target.jsx";
|
|
27
|
+
import PassageRef from "./widgets/passage-ref.jsx";
|
|
28
|
+
import Passage from "./widgets/passage.jsx";
|
|
29
|
+
import Plotter from "./widgets/plotter.jsx";
|
|
30
|
+
import ReactionDiagram from "./widgets/reaction-diagram.jsx";
|
|
31
|
+
import Sequence from "./widgets/sequence.jsx";
|
|
32
|
+
import Simulator from "./widgets/simulator.jsx";
|
|
33
|
+
import Sorter from "./widgets/sorter.jsx";
|
|
34
|
+
import Table from "./widgets/table.jsx";
|
|
35
|
+
import Transformer from "./widgets/transformer.jsx";
|
|
36
|
+
import Unit from "./widgets/unit.jsx";
|
|
37
|
+
import Video from "./widgets/video.jsx";
|
|
38
|
+
|
|
39
|
+
import type {WidgetExports} from "./types.js";
|
|
40
|
+
|
|
41
|
+
export default ([
|
|
42
|
+
Categorizer,
|
|
43
|
+
CSProgram,
|
|
44
|
+
Dropdown,
|
|
45
|
+
Explanation,
|
|
46
|
+
Definition,
|
|
47
|
+
Grapher,
|
|
48
|
+
GradedGroup,
|
|
49
|
+
GradedGroupSet,
|
|
50
|
+
Group,
|
|
51
|
+
Iframe,
|
|
52
|
+
Image,
|
|
53
|
+
Interactive,
|
|
54
|
+
InteractiveGraph,
|
|
55
|
+
LabelImage,
|
|
56
|
+
LightsPuzzle,
|
|
57
|
+
Matrix,
|
|
58
|
+
Matcher,
|
|
59
|
+
Measurer,
|
|
60
|
+
Molecule,
|
|
61
|
+
NumberLine,
|
|
62
|
+
Orderer,
|
|
63
|
+
Passage,
|
|
64
|
+
PassageRef,
|
|
65
|
+
PassageRefTarget,
|
|
66
|
+
Plotter,
|
|
67
|
+
ReactionDiagram,
|
|
68
|
+
Sequence,
|
|
69
|
+
Simulator,
|
|
70
|
+
Sorter,
|
|
71
|
+
Table,
|
|
72
|
+
Transformer,
|
|
73
|
+
Unit,
|
|
74
|
+
Video,
|
|
75
|
+
]: $ReadOnlyArray<WidgetExports<>>);
|