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