@khanacademy/perseus 19.1.5 → 19.1.6
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/dist/es/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +11 -8
- package/.babelrc.js +0 -8
- package/.eslintrc.js +0 -12
- package/CHANGELOG.md +0 -1432
- package/src/__stories__/article-renderer.stories.tsx +0 -100
- package/src/__stories__/hints-renderer.stories.tsx +0 -55
- package/src/__stories__/server-item-renderer.stories.tsx +0 -44
- package/src/__testdata__/article-renderer.testdata.ts +0 -212
- package/src/__testdata__/graphie.testdata.ts +0 -51
- package/src/__testdata__/renderer.testdata.ts +0 -274
- package/src/__testdata__/server-item-renderer.testdata.ts +0 -171
- package/src/__tests__/__snapshots__/perseus-markdown.test.ts.snap +0 -507
- package/src/__tests__/__snapshots__/renderer.test.tsx.snap +0 -525
- package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +0 -285
- package/src/__tests__/a11y.test.ts +0 -303
- package/src/__tests__/article-renderer.test.tsx +0 -130
- package/src/__tests__/error-boundary.test.tsx +0 -76
- package/src/__tests__/extract-perseus-data.test.ts +0 -1027
- package/src/__tests__/init.test.ts +0 -10
- package/src/__tests__/jipt-paragraphs.test.ts +0 -32
- package/src/__tests__/mock-asset-loading-widget.tsx +0 -53
- package/src/__tests__/mock-widget.tsx +0 -33
- package/src/__tests__/perseus-markdown.test.ts +0 -764
- package/src/__tests__/renderability.test.ts +0 -480
- package/src/__tests__/renderer-api.test.tsx +0 -302
- package/src/__tests__/renderer.test.tsx +0 -1816
- package/src/__tests__/server-item-renderer.test.tsx +0 -582
- package/src/__tests__/test-items/image-item.ts +0 -24
- package/src/__tests__/test-items/input-number-1-item.ts +0 -26
- package/src/__tests__/test-items/input-number-2-item.ts +0 -38
- package/src/__tests__/test-items/table-item.ts +0 -29
- package/src/__tests__/tex-wrangler.test.ts +0 -82
- package/src/__tests__/util.test.ts +0 -40
- package/src/__tests__/widget-container.test.tsx +0 -126
- package/src/__tests__/widgets.test.ts +0 -91
- package/src/a11y.ts +0 -45
- package/src/all-widgets.ts +0 -9
- package/src/article-renderer.tsx +0 -237
- package/src/asset-context.ts +0 -30
- package/src/basic-widgets.ts +0 -16
- package/src/components/__stories__/button-group.stories.tsx +0 -55
- package/src/components/__stories__/fixed-to-responsive.stories.tsx +0 -141
- package/src/components/__stories__/graph.stories.tsx +0 -28
- package/src/components/__stories__/graphie.stories.tsx +0 -33
- package/src/components/__stories__/hud.stories.tsx +0 -35
- package/src/components/__stories__/icon.stories.tsx +0 -63
- package/src/components/__stories__/image-loader.stories.tsx +0 -63
- package/src/components/__stories__/info-tip.stories.tsx +0 -31
- package/src/components/__stories__/inline-icon.stories.tsx +0 -40
- package/src/components/__stories__/input-with-examples.stories.tsx +0 -53
- package/src/components/__stories__/lint.stories.tsx +0 -86
- package/src/components/__stories__/math-input.stories.tsx +0 -43
- package/src/components/__stories__/math-output.stories.tsx +0 -23
- package/src/components/__stories__/multi-button-group.stories.tsx +0 -66
- package/src/components/__stories__/number-input.stories.tsx +0 -41
- package/src/components/__stories__/prop-check-box.stories.tsx +0 -65
- package/src/components/__stories__/range-input.stories.tsx +0 -29
- package/src/components/__stories__/simple-keypad-input.stories.tsx +0 -27
- package/src/components/__stories__/sortable.stories.tsx +0 -77
- package/src/components/__stories__/stub-tag-editor.stories.tsx +0 -45
- package/src/components/__stories__/svg-image.stories.tsx +0 -74
- package/src/components/__stories__/tex.stories.tsx +0 -23
- package/src/components/__stories__/text-input.stories.tsx +0 -33
- package/src/components/__stories__/text-list-editor.stories.tsx +0 -32
- package/src/components/__stories__/tooltip.stories.tsx +0 -52
- package/src/components/__stories__/zoomable-tex.stories.tsx +0 -41
- package/src/components/__stories__/zoomable.stories.tsx +0 -49
- package/src/components/__testdata__/sorter.testdata.ts +0 -19
- package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +0 -163
- package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +0 -265
- package/src/components/__tests__/math-input.test.tsx +0 -147
- package/src/components/__tests__/number-input.test.tsx +0 -128
- package/src/components/__tests__/sortable.test.tsx +0 -269
- package/src/components/__tests__/sorter.test.tsx +0 -114
- package/src/components/__tests__/zoomable.test.tsx +0 -399
- package/src/components/button-group.tsx +0 -130
- package/src/components/constants.ts +0 -14
- package/src/components/fixed-to-responsive.tsx +0 -169
- package/src/components/graph.tsx +0 -444
- package/src/components/graphie-classes.ts +0 -153
- package/src/components/graphie-movables.ts +0 -338
- package/src/components/graphie.tsx +0 -400
- package/src/components/highlighting/highlightable-content.tsx +0 -240
- package/src/components/highlighting/highlights.ts +0 -207
- package/src/components/highlighting/ranges.ts +0 -304
- package/src/components/highlighting/types.ts +0 -73
- package/src/components/highlighting/ui/highlight-renderer.tsx +0 -172
- package/src/components/highlighting/ui/highlight-set-renderer.tsx +0 -185
- package/src/components/highlighting/ui/highlight-tooltip.tsx +0 -141
- package/src/components/highlighting/ui/highlighting-ui.tsx +0 -143
- package/src/components/highlighting/ui/selection-tracker.tsx +0 -186
- package/src/components/highlighting/ui/types.ts +0 -21
- package/src/components/highlighting/ui/util.ts +0 -165
- package/src/components/highlighting/word-indexer.tsx +0 -152
- package/src/components/hud.tsx +0 -167
- package/src/components/icon.tsx +0 -141
- package/src/components/image-loader.tsx +0 -177
- package/src/components/info-tip/info-tip.tsx +0 -144
- package/src/components/info-tip.tsx +0 -39
- package/src/components/inline-icon.tsx +0 -60
- package/src/components/input-with-examples.tsx +0 -249
- package/src/components/lint.tsx +0 -459
- package/src/components/math-input.tsx +0 -474
- package/src/components/math-output.tsx +0 -134
- package/src/components/multi-button-group.tsx +0 -135
- package/src/components/number-input.tsx +0 -249
- package/src/components/prop-check-box.tsx +0 -79
- package/src/components/range-input.tsx +0 -60
- package/src/components/simple-keypad-input.tsx +0 -88
- package/src/components/sortable.tsx +0 -958
- package/src/components/stub-tag-editor.tsx +0 -53
- package/src/components/svg-image.tsx +0 -779
- package/src/components/tex.tsx +0 -67
- package/src/components/text-input.tsx +0 -129
- package/src/components/text-list-editor.tsx +0 -166
- package/src/components/tooltip.tsx +0 -410
- package/src/components/visibility-observer/__stories__/visibility-observer.stories.tsx +0 -141
- package/src/components/visibility-observer/create-visibility-observer.ts +0 -108
- package/src/components/visibility-observer/get-scroll-parent.ts +0 -46
- package/src/components/visibility-observer/visibility-observer.tsx +0 -124
- package/src/components/zoomable-tex.tsx +0 -78
- package/src/components/zoomable.tsx +0 -304
- package/src/components.ts +0 -15
- package/src/definition-context.tsx +0 -59
- package/src/dependencies.ts +0 -40
- package/src/error-boundary.tsx +0 -70
- package/src/extra-widgets.ts +0 -75
- package/src/hint-renderer.tsx +0 -151
- package/src/hints-renderer.tsx +0 -372
- package/src/icon-paths.ts +0 -119
- package/src/index.ts +0 -171
- package/src/init.ts +0 -56
- package/src/interaction-tracker.ts +0 -62
- package/src/interactive2/__tests__/movable-mock.ts +0 -55
- package/src/interactive2/__tests__/movable-point.test.ts +0 -144
- package/src/interactive2/interactive-util.test.ts +0 -93
- package/src/interactive2/interactive-util.ts +0 -159
- package/src/interactive2/movable-helper-methods.ts +0 -166
- package/src/interactive2/movable-line-options.ts +0 -419
- package/src/interactive2/movable-line.ts +0 -307
- package/src/interactive2/movable-point-options.ts +0 -224
- package/src/interactive2/movable-point.tsx +0 -585
- package/src/interactive2/movable-polygon-options.ts +0 -389
- package/src/interactive2/movable-polygon.ts +0 -360
- package/src/interactive2/movable.test.ts +0 -249
- package/src/interactive2/movable.ts +0 -437
- package/src/interactive2/objective_.ts +0 -79
- package/src/interactive2/types.ts +0 -17
- package/src/interactive2/wrapped-defaults.ts +0 -87
- package/src/interactive2/wrapped-ellipse.ts +0 -94
- package/src/interactive2/wrapped-line.ts +0 -116
- package/src/interactive2/wrapped-path.ts +0 -51
- package/src/interactive2.ts +0 -70
- package/src/item-version.ts +0 -10
- package/src/jipt-paragraphs.ts +0 -49
- package/src/jquery.mobile.vmouse.js +0 -545
- package/src/loading-context.ts +0 -21
- package/src/logging/log.test.ts +0 -39
- package/src/logging/log.ts +0 -97
- package/src/mixins/__tests__/widget-prop-denylist.test.ts +0 -21
- package/src/mixins/changeable.ts +0 -133
- package/src/mixins/editor-jsonify.ts +0 -13
- package/src/mixins/widget-jsonify-deprecated.ts +0 -23
- package/src/mixins/widget-prop-denylist.ts +0 -48
- package/src/multi-items/__stories__/multi-renderer.stories.tsx +0 -83
- package/src/multi-items/__testdata__/multi-renderer.testdata.ts +0 -172
- package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +0 -1164
- package/src/multi-items/__tests__/items.test.ts +0 -240
- package/src/multi-items/__tests__/multi-renderer.test.tsx +0 -914
- package/src/multi-items/__tests__/prop-type-builders.test.ts +0 -133
- package/src/multi-items/__tests__/shapes.test.ts +0 -43
- package/src/multi-items/__tests__/trees.test.ts +0 -317
- package/src/multi-items/item-types.ts +0 -56
- package/src/multi-items/items.ts +0 -176
- package/src/multi-items/multi-renderer.tsx +0 -569
- package/src/multi-items/prop-type-builders.ts +0 -106
- package/src/multi-items/shape-types.ts +0 -52
- package/src/multi-items/shapes.ts +0 -52
- package/src/multi-items/tree-types.ts +0 -47
- package/src/multi-items/trees.ts +0 -360
- package/src/multi-items.ts +0 -75
- package/src/perseus-api.tsx +0 -188
- package/src/perseus-env.ts +0 -27
- package/src/perseus-error.ts +0 -17
- package/src/perseus-markdown.tsx +0 -405
- package/src/perseus-types.ts +0 -1366
- package/src/perseus-version.ts +0 -9
- package/src/question-paragraph.tsx +0 -34
- package/src/renderability.ts +0 -109
- package/src/renderer.tsx +0 -2000
- package/src/server-item-renderer.tsx +0 -495
- package/src/sigfigs.ts +0 -490
- package/src/styles/articles.less +0 -749
- package/src/styles/constants.ts +0 -94
- package/src/styles/global-constants.ts +0 -343
- package/src/styles/global-styles.ts +0 -306
- package/src/styles/khan-exercise.css +0 -1468
- package/src/styles/media-queries.ts +0 -47
- package/src/styles/perseus-renderer.less +0 -732
- package/src/styles/shared.ts +0 -130
- package/src/styles/util.less +0 -47
- package/src/styles/variables.boostrap.less +0 -277
- package/src/styles/variables.less +0 -56
- package/src/styles/variables.shared.less +0 -340
- package/src/styles/widgets/categorizer.less +0 -38
- package/src/styles/widgets/dropdown.less +0 -3
- package/src/styles/widgets/expression.less +0 -65
- package/src/styles/widgets/graded-group.less +0 -36
- package/src/styles/widgets/grapher.less +0 -12
- package/src/styles/widgets/group.less +0 -19
- package/src/styles/widgets/image.less +0 -54
- package/src/styles/widgets/interactive-graph.less +0 -64
- package/src/styles/widgets/label-image.less +0 -57
- package/src/styles/widgets/matcher.less +0 -8
- package/src/styles/widgets/matrix.less +0 -126
- package/src/styles/widgets/measurer.less +0 -20
- package/src/styles/widgets/orderer.less +0 -98
- package/src/styles/widgets/passage.less +0 -154
- package/src/styles/widgets/plotter.less +0 -31
- package/src/styles/widgets/radio.less +0 -58
- package/src/styles/widgets/reaction-diagram.less +0 -35
- package/src/styles/widgets/sequence.less +0 -5
- package/src/styles/widgets/sortable.less +0 -113
- package/src/styles/widgets/table.less +0 -57
- package/src/styles/widgets/unit.less +0 -15
- package/src/tex-wrangler.ts +0 -182
- package/src/translation-linter.ts +0 -126
- package/src/traversal.ts +0 -138
- package/src/types.ts +0 -513
- package/src/util/a11y.ts +0 -23
- package/src/util/answer-types.test.ts +0 -114
- package/src/util/answer-types.ts +0 -876
- package/src/util/colors.ts +0 -93
- package/src/util/drawing-transform.test.ts +0 -67
- package/src/util/drawing-transform.ts +0 -102
- package/src/util/extract-perseus-data.ts +0 -539
- package/src/util/fix-passage-refs.ts +0 -121
- package/src/util/geometry.test.ts +0 -75
- package/src/util/geometry.ts +0 -312
- package/src/util/graph-bounds.ts +0 -23
- package/src/util/graph-utils.ts +0 -15
- package/src/util/graphie.test.ts +0 -1277
- package/src/util/graphie.ts +0 -1576
- package/src/util/interactive.ts +0 -4174
- package/src/util/interval.ts +0 -4
- package/src/util/katex-preprocess.ts +0 -14
- package/src/util/math.test.ts +0 -11
- package/src/util/math.ts +0 -294
- package/src/util/mobile-native-utils.test.ts +0 -22
- package/src/util/mobile-native-utils.ts +0 -12
- package/src/util/parse-perseus-json.test.ts +0 -10
- package/src/util/parse-perseus-json.ts +0 -13
- package/src/util/react-render.tsx +0 -27
- package/src/util/register-all-widgets-for-testing.ts +0 -13
- package/src/util/scroll-utils.ts +0 -155
- package/src/util/sizing-utils.ts +0 -46
- package/src/util/tex.ts +0 -73
- package/src/util/url-utils.ts +0 -34
- package/src/util.graphie.test.ts +0 -45
- package/src/util.graphie.ts +0 -59
- package/src/util.ts +0 -966
- package/src/version.ts +0 -10
- package/src/widget-container.tsx +0 -199
- package/src/widgets/__stories__/categorizer.stories.tsx +0 -14
- package/src/widgets/__stories__/cs-program.stories.tsx +0 -14
- package/src/widgets/__stories__/definition.stories.tsx +0 -114
- package/src/widgets/__stories__/dropdown.stories.tsx +0 -14
- package/src/widgets/__stories__/explanation.stories.tsx +0 -18
- package/src/widgets/__stories__/expression.stories.tsx +0 -145
- package/src/widgets/__stories__/graded-group-set.stories.tsx +0 -31
- package/src/widgets/__stories__/graded-group.stories.tsx +0 -31
- package/src/widgets/__stories__/grapher.stories.tsx +0 -46
- package/src/widgets/__stories__/group.stories.tsx +0 -14
- package/src/widgets/__stories__/iframe.stories.tsx +0 -14
- package/src/widgets/__stories__/image.stories.tsx +0 -85
- package/src/widgets/__stories__/input-number.stories.tsx +0 -101
- package/src/widgets/__stories__/interaction.stories.tsx +0 -14
- package/src/widgets/__stories__/interactive-graph.stories.tsx +0 -60
- package/src/widgets/__stories__/label-image.stories.tsx +0 -130
- package/src/widgets/__stories__/matcher.stories.tsx +0 -14
- package/src/widgets/__stories__/matrix.stories.tsx +0 -14
- package/src/widgets/__stories__/number-line.stories.tsx +0 -14
- package/src/widgets/__stories__/numeric-input.stories.tsx +0 -105
- package/src/widgets/__stories__/orderer.stories.tsx +0 -18
- package/src/widgets/__stories__/passage-ref.stories.tsx +0 -33
- package/src/widgets/__stories__/passage.stories.tsx +0 -39
- package/src/widgets/__stories__/plotter.stories.tsx +0 -27
- package/src/widgets/__stories__/radio.stories.tsx +0 -86
- package/src/widgets/__stories__/random-widgets.stories.tsx +0 -59
- package/src/widgets/__stories__/sorter.stories.tsx +0 -14
- package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +0 -66
- package/src/widgets/__stories__/unit.stories.tsx +0 -28
- package/src/widgets/__stories__/video-transcript-link.stories.tsx +0 -23
- package/src/widgets/__stories__/video.stories.tsx +0 -22
- package/src/widgets/__testdata__/base-radio.testdata.ts +0 -21
- package/src/widgets/__testdata__/categorizer.testdata.ts +0 -89
- package/src/widgets/__testdata__/cs-program.testdata.ts +0 -27
- package/src/widgets/__testdata__/dropdown.testdata.ts +0 -71
- package/src/widgets/__testdata__/explanation.testdata.ts +0 -85
- package/src/widgets/__testdata__/expression.testdata.ts +0 -198
- package/src/widgets/__testdata__/graded-group-set.testdata.ts +0 -356
- package/src/widgets/__testdata__/graded-group.testdata.ts +0 -77
- package/src/widgets/__testdata__/grapher.testdata.ts +0 -374
- package/src/widgets/__testdata__/group.testdata.ts +0 -153
- package/src/widgets/__testdata__/iframe.testdata.ts +0 -35
- package/src/widgets/__testdata__/image.testdata.ts +0 -36
- package/src/widgets/__testdata__/input-number.testdata.ts +0 -72
- package/src/widgets/__testdata__/interaction.testdata.ts +0 -262
- package/src/widgets/__testdata__/interactive-graph-random.testdata.ts +0 -269
- package/src/widgets/__testdata__/interactive-graph.testdata.ts +0 -644
- package/src/widgets/__testdata__/label-image.testdata.ts +0 -308
- package/src/widgets/__testdata__/matcher.testdata.ts +0 -33
- package/src/widgets/__testdata__/matrix.testdata.ts +0 -28
- package/src/widgets/__testdata__/number-line.testdata.ts +0 -30
- package/src/widgets/__testdata__/numeric-input.testdata.ts +0 -265
- package/src/widgets/__testdata__/orderer.testdata.ts +0 -123
- package/src/widgets/__testdata__/passage-ref.testdata.ts +0 -101
- package/src/widgets/__testdata__/passage.testdata.ts +0 -95
- package/src/widgets/__testdata__/plotter.testdata.ts +0 -36
- package/src/widgets/__testdata__/radio.testdata.ts +0 -324
- package/src/widgets/__testdata__/randomizers.ts +0 -51
- package/src/widgets/__testdata__/sorter.testdata.ts +0 -19
- package/src/widgets/__testdata__/video.testdata.ts +0 -61
- package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +0 -940
- package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +0 -67
- package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +0 -97
- package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +0 -133
- package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +0 -425
- package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +0 -729
- package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +0 -339
- package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +0 -801
- package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +0 -2673
- package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +0 -1211
- package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +0 -61
- package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +0 -378
- package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +0 -495
- package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +0 -292
- package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +0 -2889
- package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +0 -883
- package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +0 -514
- package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +0 -814
- package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +0 -470
- package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +0 -243
- package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +0 -434
- package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +0 -1956
- package/src/widgets/__tests__/__snapshots__/plotter.test.tsx.snap +0 -827
- package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +0 -4237
- package/src/widgets/__tests__/__snapshots__/unit.test.tsx.snap +0 -20
- package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +0 -153
- package/src/widgets/__tests__/categorizer.test.ts +0 -203
- package/src/widgets/__tests__/cs-program.test.ts +0 -43
- package/src/widgets/__tests__/definition.test.ts +0 -136
- package/src/widgets/__tests__/dropdown.test.ts +0 -105
- package/src/widgets/__tests__/explanation.test.ts +0 -198
- package/src/widgets/__tests__/expression-mobile.test.tsx +0 -363
- package/src/widgets/__tests__/expression.test.tsx +0 -484
- package/src/widgets/__tests__/graded-group-set-jipt.test.ts +0 -30
- package/src/widgets/__tests__/graded-group-set.test.ts +0 -288
- package/src/widgets/__tests__/graded-group.test.ts +0 -232
- package/src/widgets/__tests__/grapher.cypress.ts +0 -576
- package/src/widgets/__tests__/grapher.test.ts +0 -33
- package/src/widgets/__tests__/group.test.tsx +0 -510
- package/src/widgets/__tests__/iframe.test.ts +0 -45
- package/src/widgets/__tests__/image.test.ts +0 -62
- package/src/widgets/__tests__/input-number.test.ts +0 -354
- package/src/widgets/__tests__/interaction.test.ts +0 -31
- package/src/widgets/__tests__/interactive-graph.cypress.ts +0 -815
- package/src/widgets/__tests__/interactive-graph.test.ts +0 -106
- package/src/widgets/__tests__/matcher.test.tsx +0 -176
- package/src/widgets/__tests__/matrix.test.ts +0 -82
- package/src/widgets/__tests__/number-line.test.ts +0 -79
- package/src/widgets/__tests__/numeric-input.test.ts +0 -575
- package/src/widgets/__tests__/orderer.test.ts +0 -73
- package/src/widgets/__tests__/passage-ref.test.ts +0 -168
- package/src/widgets/__tests__/passage.test.tsx +0 -224
- package/src/widgets/__tests__/plotter.test.tsx +0 -69
- package/src/widgets/__tests__/radio/base-radio.test.tsx +0 -470
- package/src/widgets/__tests__/radio/choice-icon.test.tsx +0 -90
- package/src/widgets/__tests__/radio/choice.test.tsx +0 -310
- package/src/widgets/__tests__/radio/focus-ring.test.tsx +0 -22
- package/src/widgets/__tests__/radio/option-status.test.tsx +0 -77
- package/src/widgets/__tests__/radio.test.ts +0 -807
- package/src/widgets/__tests__/randomizers.test.ts +0 -53
- package/src/widgets/__tests__/renderQuestion.tsx +0 -101
- package/src/widgets/__tests__/unit.test.tsx +0 -168
- package/src/widgets/__tests__/video.test.ts +0 -69
- package/src/widgets/categorizer.tsx +0 -344
- package/src/widgets/cs-program.tsx +0 -227
- package/src/widgets/definition.tsx +0 -121
- package/src/widgets/deprecated-standin/__stories__/deprecated-standin.stories.tsx +0 -30
- package/src/widgets/deprecated-standin/__tests__/__snapshots__/deprecated-standin.test.ts.snap +0 -70
- package/src/widgets/deprecated-standin/__tests__/deprecated-standin.test.ts +0 -93
- package/src/widgets/deprecated-standin/index.tsx +0 -58
- package/src/widgets/dropdown.tsx +0 -142
- package/src/widgets/explanation.tsx +0 -317
- package/src/widgets/expression.tsx +0 -707
- package/src/widgets/graded-group-answer-bar.tsx +0 -142
- package/src/widgets/graded-group-set.tsx +0 -338
- package/src/widgets/graded-group.tsx +0 -471
- package/src/widgets/grapher/util.tsx +0 -799
- package/src/widgets/grapher.tsx +0 -660
- package/src/widgets/group.tsx +0 -195
- package/src/widgets/iframe.tsx +0 -195
- package/src/widgets/image.tsx +0 -312
- package/src/widgets/input-number.tsx +0 -412
- package/src/widgets/interaction/arrow-picker.tsx +0 -38
- package/src/widgets/interaction/color-picker.tsx +0 -69
- package/src/widgets/interaction/dash-picker.tsx +0 -45
- package/src/widgets/interaction/element-container.tsx +0 -100
- package/src/widgets/interaction.tsx +0 -826
- package/src/widgets/interactive-graph.tsx +0 -2597
- package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -91
- package/src/widgets/label-image/__stories__/answer-pill.stories.tsx +0 -62
- package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -171
- package/src/widgets/label-image/__tests__/answer-pill.test.tsx +0 -75
- package/src/widgets/label-image/__tests__/hide-answers-toggle.test.tsx +0 -39
- package/src/widgets/label-image/answer-choices.tsx +0 -88
- package/src/widgets/label-image/answer-pill.tsx +0 -103
- package/src/widgets/label-image/hide-answers-toggle.tsx +0 -40
- package/src/widgets/label-image/marker.tsx +0 -268
- package/src/widgets/label-image/strings.ts +0 -5
- package/src/widgets/label-image/types.ts +0 -27
- package/src/widgets/label-image.test.ts +0 -928
- package/src/widgets/label-image.tsx +0 -819
- package/src/widgets/lights-puzzle.tsx +0 -359
- package/src/widgets/matcher.tsx +0 -298
- package/src/widgets/matrix.tsx +0 -634
- package/src/widgets/measurer.tsx +0 -222
- package/src/widgets/molecule/__tests__/layout.test.ts +0 -162
- package/src/widgets/molecule/__tests__/parser.test.ts +0 -155
- package/src/widgets/molecule/molecule-drawing.ts +0 -173
- package/src/widgets/molecule/molecule-layout.ts +0 -362
- package/src/widgets/molecule/smiles-parser.ts +0 -296
- package/src/widgets/molecule.tsx +0 -172
- package/src/widgets/number-line.tsx +0 -862
- package/src/widgets/numeric-input.tsx +0 -576
- package/src/widgets/orderer.tsx +0 -786
- package/src/widgets/passage/__tests__/passage-markdown.test.ts +0 -376
- package/src/widgets/passage/passage-markdown.tsx +0 -475
- package/src/widgets/passage-ref-target.tsx +0 -76
- package/src/widgets/passage-ref.tsx +0 -213
- package/src/widgets/passage.tsx +0 -582
- package/src/widgets/plotter.tsx +0 -1194
- package/src/widgets/radio/__stories__/base-radio.stories.tsx +0 -196
- package/src/widgets/radio/__stories__/choice-icon.stories.tsx +0 -166
- package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +0 -40
- package/src/widgets/radio/__stories__/choice.stories.tsx +0 -137
- package/src/widgets/radio/__stories__/focus-ring.stories.tsx +0 -43
- package/src/widgets/radio/__stories__/option-status.stories.tsx +0 -103
- package/src/widgets/radio/base-radio.tsx +0 -511
- package/src/widgets/radio/choice-a11y-text.ts +0 -61
- package/src/widgets/radio/choice-icon/choice-icon.tsx +0 -218
- package/src/widgets/radio/choice-icon/cross-out-line.tsx +0 -51
- package/src/widgets/radio/choice-icon/shared-styles.ts +0 -15
- package/src/widgets/radio/choice-none-above.tsx +0 -56
- package/src/widgets/radio/choice.jsx.fixture.ts +0 -45
- package/src/widgets/radio/choice.tsx +0 -359
- package/src/widgets/radio/focus-ring.tsx +0 -57
- package/src/widgets/radio/option-status.tsx +0 -98
- package/src/widgets/radio/util.test.ts +0 -18
- package/src/widgets/radio/util.ts +0 -31
- package/src/widgets/radio/widget.tsx +0 -520
- package/src/widgets/radio.ts +0 -157
- package/src/widgets/reaction-diagram.tsx +0 -144
- package/src/widgets/sequence.tsx +0 -142
- package/src/widgets/simulator.tsx +0 -829
- package/src/widgets/sorter.tsx +0 -155
- package/src/widgets/table.tsx +0 -393
- package/src/widgets/unit.tsx +0 -374
- package/src/widgets/video-transcript-link.test.tsx +0 -213
- package/src/widgets/video-transcript-link.tsx +0 -84
- package/src/widgets/video.tsx +0 -135
- package/src/widgets.ts +0 -489
- package/src/zoom.ts +0 -555
- package/tsconfig-build.json +0 -26
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,576 +0,0 @@
|
|
|
1
|
-
import {linterContextDefault} from "@khanacademy/perseus-linter";
|
|
2
|
-
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
3
|
-
import {StyleSheet} from "aphrodite";
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import _ from "underscore";
|
|
6
|
-
|
|
7
|
-
import InputWithExamples from "../components/input-with-examples";
|
|
8
|
-
import SimpleKeypadInput from "../components/simple-keypad-input";
|
|
9
|
-
import {ApiOptions} from "../perseus-api";
|
|
10
|
-
import TexWrangler from "../tex-wrangler";
|
|
11
|
-
import KhanAnswerTypes from "../util/answer-types";
|
|
12
|
-
import KhanMath from "../util/math";
|
|
13
|
-
|
|
14
|
-
import type {
|
|
15
|
-
PerseusNumericInputAnswer,
|
|
16
|
-
PerseusNumericInputWidgetOptions,
|
|
17
|
-
PerseusNumericInputAnswerForm,
|
|
18
|
-
MathFormat,
|
|
19
|
-
} from "../perseus-types";
|
|
20
|
-
import type {
|
|
21
|
-
FocusPath,
|
|
22
|
-
PerseusScore,
|
|
23
|
-
WidgetExports,
|
|
24
|
-
WidgetProps,
|
|
25
|
-
} from "../types";
|
|
26
|
-
|
|
27
|
-
const ParseTex = TexWrangler.parseTex;
|
|
28
|
-
|
|
29
|
-
const answerFormButtons: ReadonlyArray<{
|
|
30
|
-
title: string;
|
|
31
|
-
value: MathFormat;
|
|
32
|
-
content: string;
|
|
33
|
-
}> = [
|
|
34
|
-
{title: "Integers", value: "integer", content: "6"},
|
|
35
|
-
{title: "Decimals", value: "decimal", content: "0.75"},
|
|
36
|
-
{title: "Proper fractions", value: "proper", content: "\u2157"},
|
|
37
|
-
{
|
|
38
|
-
title: "Improper fractions",
|
|
39
|
-
value: "improper",
|
|
40
|
-
content: "\u2077\u2044\u2084",
|
|
41
|
-
},
|
|
42
|
-
{title: "Mixed numbers", value: "mixed", content: "1\u00BE"},
|
|
43
|
-
{title: "Numbers with \u03C0", value: "pi", content: "\u03C0"},
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
const formExamples: {
|
|
47
|
-
[key: string]: (arg1: PerseusNumericInputAnswerForm) => string;
|
|
48
|
-
} = {
|
|
49
|
-
integer: () => i18n._("an integer, like $6$"),
|
|
50
|
-
proper: (form) =>
|
|
51
|
-
form.simplify === "optional"
|
|
52
|
-
? i18n._("a *proper* fraction, like $1/2$ or $6/10$")
|
|
53
|
-
: i18n._("a *simplified proper* fraction, like $3/5$"),
|
|
54
|
-
improper: (form) =>
|
|
55
|
-
form.simplify === "optional"
|
|
56
|
-
? i18n._("an *improper* fraction, like $10/7$ or $14/8$")
|
|
57
|
-
: i18n._("a *simplified improper* fraction, like $7/4$"),
|
|
58
|
-
mixed: () => i18n._("a mixed number, like $1\\ 3/4$"),
|
|
59
|
-
decimal: () => i18n._("an *exact* decimal, like $0.75$"),
|
|
60
|
-
pi: () =>
|
|
61
|
-
i18n._(
|
|
62
|
-
"a multiple of pi, like $12\\ \\text{pi}$ or " +
|
|
63
|
-
"$2/3\\ \\text{pi}$",
|
|
64
|
-
),
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
type UserInput = {
|
|
68
|
-
currentValue: string;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export type Rubric = PerseusNumericInputWidgetOptions;
|
|
72
|
-
|
|
73
|
-
type ExternalProps = WidgetProps<PerseusNumericInputWidgetOptions, Rubric>;
|
|
74
|
-
|
|
75
|
-
type Props = ExternalProps & {
|
|
76
|
-
size: NonNullable<ExternalProps["size"]>;
|
|
77
|
-
rightAlign: NonNullable<ExternalProps["rightAlign"]>;
|
|
78
|
-
apiOptions: NonNullable<ExternalProps["apiOptions"]>;
|
|
79
|
-
coefficient: NonNullable<ExternalProps["coefficient"]>;
|
|
80
|
-
answerForms: NonNullable<ExternalProps["answerForms"]>;
|
|
81
|
-
labelText: NonNullable<ExternalProps["labelText"]>;
|
|
82
|
-
linterContext: NonNullable<ExternalProps["linterContext"]>;
|
|
83
|
-
currentValue: string;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
type DefaultProps = {
|
|
87
|
-
currentValue: Props["currentValue"];
|
|
88
|
-
size: Props["size"];
|
|
89
|
-
rightAlign: Props["rightAlign"];
|
|
90
|
-
apiOptions: Props["apiOptions"];
|
|
91
|
-
coefficient: Props["coefficient"];
|
|
92
|
-
answerForms: Props["answerForms"];
|
|
93
|
-
labelText: Props["labelText"];
|
|
94
|
-
linterContext: Props["linterContext"];
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
type State = {
|
|
98
|
-
// keeps track of the other set of values when switching
|
|
99
|
-
// between 0 and finite solutions
|
|
100
|
-
previousValues: ReadonlyArray<string>;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export class NumericInput extends React.Component<Props, State> {
|
|
104
|
-
inputRef: SimpleKeypadInput | InputWithExamples | null | undefined;
|
|
105
|
-
|
|
106
|
-
static defaultProps: DefaultProps = {
|
|
107
|
-
currentValue: "",
|
|
108
|
-
size: "normal",
|
|
109
|
-
rightAlign: false,
|
|
110
|
-
apiOptions: ApiOptions.defaults,
|
|
111
|
-
coefficient: false,
|
|
112
|
-
answerForms: [],
|
|
113
|
-
labelText: "",
|
|
114
|
-
linterContext: linterContextDefault,
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
static getUserInputFromProps(props: Props): UserInput {
|
|
118
|
-
return {
|
|
119
|
-
currentValue: props.currentValue,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
static getOneCorrectAnswerFromRubric(
|
|
124
|
-
rubric: Rubric,
|
|
125
|
-
): string | null | undefined {
|
|
126
|
-
const correctAnswers = rubric.answers.filter(
|
|
127
|
-
(answer) => answer.status === "correct",
|
|
128
|
-
);
|
|
129
|
-
const answerStrings = correctAnswers.map((answer) => {
|
|
130
|
-
// Figure out how this answer is supposed to be
|
|
131
|
-
// displayed
|
|
132
|
-
let format = "decimal";
|
|
133
|
-
if (answer.answerForms && answer.answerForms[0]) {
|
|
134
|
-
// NOTE(johnsullivan): This isn't exactly ideal, but
|
|
135
|
-
// it does behave well for all the currently known
|
|
136
|
-
// problems. See D14742 for some discussion on
|
|
137
|
-
// alternate strategies.
|
|
138
|
-
format = answer.answerForms[0];
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
142
|
-
let answerString = KhanMath.toNumericString(answer.value, format);
|
|
143
|
-
if (answer.maxError) {
|
|
144
|
-
answerString +=
|
|
145
|
-
" \u00B1 " +
|
|
146
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
147
|
-
KhanMath.toNumericString(answer.maxError, format);
|
|
148
|
-
}
|
|
149
|
-
return answerString;
|
|
150
|
-
});
|
|
151
|
-
if (answerStrings.length === 0) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
return answerStrings[0];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
static validate(userInput: UserInput, rubric: Rubric): PerseusScore {
|
|
158
|
-
const defaultAnswerForms = answerFormButtons
|
|
159
|
-
.map((e) => e["value"])
|
|
160
|
-
// Don't default to validating the answer as a pi answer
|
|
161
|
-
// if answerForm isn't set on the answer
|
|
162
|
-
// https://khanacademy.atlassian.net/browse/LC-691
|
|
163
|
-
.filter((e) => e !== "pi");
|
|
164
|
-
|
|
165
|
-
const createValidator = (answer: PerseusNumericInputAnswer) => {
|
|
166
|
-
const stringAnswer = `${answer.value}`;
|
|
167
|
-
|
|
168
|
-
// Always validate against the provided answer forms (pi, decimal, etc.)
|
|
169
|
-
const validatorForms = [...(answer.answerForms ?? [])];
|
|
170
|
-
|
|
171
|
-
// When an answer is set to strict, we validate using ONLY
|
|
172
|
-
// the provided answerForms. If strict is false, or if there
|
|
173
|
-
// were no provided answer forms, we will include all
|
|
174
|
-
// of the default answer forms in our validator.
|
|
175
|
-
if (!answer.strict || validatorForms.length === 0) {
|
|
176
|
-
validatorForms.push(...defaultAnswerForms);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return KhanAnswerTypes.number.createValidatorFunctional(
|
|
180
|
-
stringAnswer,
|
|
181
|
-
{
|
|
182
|
-
message: answer.message,
|
|
183
|
-
simplify:
|
|
184
|
-
answer.status === "correct"
|
|
185
|
-
? answer.simplify
|
|
186
|
-
: "optional",
|
|
187
|
-
inexact: true, // TODO(merlob) backfill / delete
|
|
188
|
-
maxError: answer.maxError,
|
|
189
|
-
forms: validatorForms,
|
|
190
|
-
},
|
|
191
|
-
);
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// We may have received TeX; try to parse it before grading.
|
|
195
|
-
// If `currentValue` is not TeX, this should be a no-op.
|
|
196
|
-
const currentValue = ParseTex(userInput.currentValue);
|
|
197
|
-
const correctAnswers = rubric.answers.filter(
|
|
198
|
-
(answer) => answer.status === "correct",
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
const normalizedAnswerExpected = correctAnswers.every(
|
|
202
|
-
(answer) => Math.abs(answer.value) <= 1,
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
// Look through all correct answers for one that matches either
|
|
206
|
-
// precisely or approximately and return the appropriate message:
|
|
207
|
-
// - if precise, return the message that the answer came with
|
|
208
|
-
// - if it needs to be simplified, etc., show that message
|
|
209
|
-
let result = correctAnswers
|
|
210
|
-
.map((answer) => {
|
|
211
|
-
// The coefficient is an attribute of the widget
|
|
212
|
-
let localValue = currentValue;
|
|
213
|
-
if (rubric.coefficient) {
|
|
214
|
-
if (!localValue) {
|
|
215
|
-
// @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'string'.
|
|
216
|
-
localValue = 1;
|
|
217
|
-
} else if (localValue === "-") {
|
|
218
|
-
// @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'string'.
|
|
219
|
-
localValue = -1;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
const validate = createValidator(answer);
|
|
223
|
-
return validate(
|
|
224
|
-
maybeParsePercentInput(
|
|
225
|
-
localValue,
|
|
226
|
-
normalizedAnswerExpected,
|
|
227
|
-
),
|
|
228
|
-
);
|
|
229
|
-
})
|
|
230
|
-
.find((match) => match.correct || match.empty);
|
|
231
|
-
|
|
232
|
-
if (!result) {
|
|
233
|
-
// Otherwise, if the guess is not correct
|
|
234
|
-
const otherAnswers = [].concat(
|
|
235
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
236
|
-
rubric.answers.filter((answer) => answer.status === "ungraded"),
|
|
237
|
-
rubric.answers.filter((answer) => answer.status === "wrong"),
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
// Look through all other answers and if one matches either
|
|
241
|
-
// precisely or approximately return the answer's message
|
|
242
|
-
const match = otherAnswers.find((answer) => {
|
|
243
|
-
const validate = createValidator(answer);
|
|
244
|
-
return validate(
|
|
245
|
-
maybeParsePercentInput(
|
|
246
|
-
currentValue,
|
|
247
|
-
normalizedAnswerExpected,
|
|
248
|
-
),
|
|
249
|
-
).correct;
|
|
250
|
-
});
|
|
251
|
-
result = {
|
|
252
|
-
// @ts-expect-error - TS2339 - Property 'status' does not exist on type 'never'.
|
|
253
|
-
empty: match ? match.status === "ungraded" : false,
|
|
254
|
-
// @ts-expect-error - TS2339 - Property 'status' does not exist on type 'never'.
|
|
255
|
-
correct: match ? match.status === "correct" : false,
|
|
256
|
-
// @ts-expect-error - TS2339 - Property 'message' does not exist on type 'never'.
|
|
257
|
-
message: match ? match.message : null,
|
|
258
|
-
guess: currentValue,
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// TODO(eater): Seems silly to translate result to this
|
|
263
|
-
// invalid/points thing and immediately translate it
|
|
264
|
-
// back in ItemRenderer.scoreInput()
|
|
265
|
-
if (result.empty) {
|
|
266
|
-
return {
|
|
267
|
-
type: "invalid",
|
|
268
|
-
message: result.message,
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
return {
|
|
272
|
-
type: "points",
|
|
273
|
-
earned: result.correct ? 1 : 0,
|
|
274
|
-
total: 1,
|
|
275
|
-
message: result.message,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
state: State = {
|
|
280
|
-
// keeps track of the other set of values when switching
|
|
281
|
-
// between 0 and finite solutions
|
|
282
|
-
previousValues: [""],
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
// TODO(Nicole, Jeremy): This is maybe never used and should be removed
|
|
286
|
-
examples: () => ReadonlyArray<string> = () => {
|
|
287
|
-
// if the set of specified forms are empty, allow all forms
|
|
288
|
-
const forms =
|
|
289
|
-
this.props.answerForms?.length !== 0
|
|
290
|
-
? this.props.answerForms
|
|
291
|
-
: Object.keys(formExamples).map((name) => {
|
|
292
|
-
return {
|
|
293
|
-
name: name,
|
|
294
|
-
simplify: "required",
|
|
295
|
-
};
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
let examples = _.map(forms, (form) => {
|
|
299
|
-
// @ts-expect-error - TS2345 - Argument of type 'PerseusNumericInputAnswerForm | { name: string; simplify: string; }' is not assignable to parameter of type 'PerseusNumericInputAnswerForm'.
|
|
300
|
-
return formExamples[form.name](form);
|
|
301
|
-
});
|
|
302
|
-
// Ensure no duplicate tooltip text from simplified and unsimplified
|
|
303
|
-
// versions of the same format
|
|
304
|
-
examples = _.uniq(examples);
|
|
305
|
-
|
|
306
|
-
return [i18n._("**Your answer should be** ")].concat(examples);
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
shouldShowExamples: () => boolean = () => {
|
|
310
|
-
const noFormsAccepted = this.props.answerForms?.length === 0;
|
|
311
|
-
// To check if all answer forms are accepted, we must first
|
|
312
|
-
// find the *names* of all accepted forms, and see if they are
|
|
313
|
-
// all present, ignoring duplicates
|
|
314
|
-
const answerFormNames: ReadonlyArray<string> = _.uniq(
|
|
315
|
-
this.props.answerForms?.map((form) => form.name),
|
|
316
|
-
);
|
|
317
|
-
const allFormsAccepted =
|
|
318
|
-
answerFormNames.length >= Object.keys(formExamples).length;
|
|
319
|
-
return !noFormsAccepted && !allFormsAccepted;
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
simpleValidate: (arg1: Rubric) => PerseusScore = (rubric) => {
|
|
323
|
-
return NumericInput.validate(this.getUserInput(), rubric);
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
focus: () => boolean = () => {
|
|
327
|
-
this.inputRef?.focus();
|
|
328
|
-
return true;
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
focusInputPath: () => void = () => {
|
|
332
|
-
this.inputRef?.focus();
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
blurInputPath: () => void = () => {
|
|
336
|
-
this.inputRef?.blur();
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
getInputPaths: () => ReadonlyArray<ReadonlyArray<string>> = () => {
|
|
340
|
-
// The widget itself is an input, so we return a single empty list to
|
|
341
|
-
// indicate this.
|
|
342
|
-
/* c8 ignore next */
|
|
343
|
-
return [[]];
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
getGrammarTypeForPath: (arg1: FocusPath) => string = (inputPath) => {
|
|
347
|
-
/* c8 ignore next */
|
|
348
|
-
return "number";
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
setInputValue: (
|
|
352
|
-
arg1: FocusPath,
|
|
353
|
-
arg2: string,
|
|
354
|
-
arg3?: () => unknown | null | undefined,
|
|
355
|
-
) => void = (path, newValue, cb) => {
|
|
356
|
-
/* c8 ignore next */
|
|
357
|
-
this.props.onChange(
|
|
358
|
-
{
|
|
359
|
-
currentValue: newValue,
|
|
360
|
-
},
|
|
361
|
-
cb,
|
|
362
|
-
);
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
getUserInput: () => UserInput = () => {
|
|
366
|
-
return NumericInput.getUserInputFromProps(this.props);
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
handleChange: (
|
|
370
|
-
arg1: string,
|
|
371
|
-
arg2?: () => unknown | null | undefined,
|
|
372
|
-
) => void = (newValue, cb) => {
|
|
373
|
-
this.props.onChange({currentValue: newValue}, cb);
|
|
374
|
-
this.props.trackInteraction();
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
_handleFocus: () => void = () => {
|
|
378
|
-
this.props.onFocus([]);
|
|
379
|
-
// HACK(kevinb): We want to dismiss the feedback popover that webapp
|
|
380
|
-
// displays as soon as a user clicks in in the input field so we call
|
|
381
|
-
// interactionCallback directly.
|
|
382
|
-
const {interactionCallback} = this.props.apiOptions;
|
|
383
|
-
if (interactionCallback) {
|
|
384
|
-
interactionCallback();
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
_handleBlur: () => void = () => {
|
|
389
|
-
this.props.onBlur([]);
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
render(): React.ReactNode {
|
|
393
|
-
let labelText = this.props.labelText;
|
|
394
|
-
if (labelText == null || labelText === "") {
|
|
395
|
-
labelText = i18n._("Your answer:");
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// To right align a custom keypad we need to wrap it.
|
|
399
|
-
const maybeRightAlignKeypadInput = (
|
|
400
|
-
keypadInput: React.ReactElement<
|
|
401
|
-
React.ComponentProps<typeof SimpleKeypadInput>
|
|
402
|
-
>,
|
|
403
|
-
) => {
|
|
404
|
-
return this.props.rightAlign ? (
|
|
405
|
-
<div className="perseus-input-right-align">{keypadInput}</div>
|
|
406
|
-
) : (
|
|
407
|
-
keypadInput
|
|
408
|
-
);
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
if (this.props.apiOptions.customKeypad) {
|
|
412
|
-
// TODO(charlie): Support "Review Mode".
|
|
413
|
-
return maybeRightAlignKeypadInput(
|
|
414
|
-
<SimpleKeypadInput
|
|
415
|
-
ref={(ref) => (this.inputRef = ref)}
|
|
416
|
-
value={this.props.currentValue}
|
|
417
|
-
keypadElement={this.props.keypadElement}
|
|
418
|
-
onChange={this.handleChange}
|
|
419
|
-
onFocus={this._handleFocus}
|
|
420
|
-
onBlur={this._handleBlur}
|
|
421
|
-
/>,
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Note: This is _very_ similar to what `input-number.jsx` does. If
|
|
426
|
-
// you modify this, double-check if you also need to modify that
|
|
427
|
-
// component.
|
|
428
|
-
const styles = StyleSheet.create({
|
|
429
|
-
input: {
|
|
430
|
-
textAlign: this.props.rightAlign ? "right" : "left",
|
|
431
|
-
width: this.props.size === "small" ? 40 : 80,
|
|
432
|
-
padding: 0,
|
|
433
|
-
height: "auto",
|
|
434
|
-
},
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
return (
|
|
438
|
-
<div>
|
|
439
|
-
<InputWithExamples
|
|
440
|
-
ref={(ref) => (this.inputRef = ref)}
|
|
441
|
-
value={this.props.currentValue}
|
|
442
|
-
onChange={this.handleChange}
|
|
443
|
-
labelText={labelText}
|
|
444
|
-
type="text"
|
|
445
|
-
examples={this.examples()}
|
|
446
|
-
shouldShowExamples={this.shouldShowExamples()}
|
|
447
|
-
onFocus={this._handleFocus}
|
|
448
|
-
onBlur={this._handleBlur}
|
|
449
|
-
id={this.props.widgetId}
|
|
450
|
-
disabled={this.props.apiOptions.readOnly}
|
|
451
|
-
style={styles.input}
|
|
452
|
-
/>
|
|
453
|
-
</div>
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// TODO(thomas): Currently we receive a list of lists of acceptable answer types
|
|
459
|
-
// and union them down into a single set. It's worth considering whether it
|
|
460
|
-
// wouldn't make more sense to have a single set of acceptable answer types for
|
|
461
|
-
// a given *problem* rather than for each possible [correct/wrong] *answer*.
|
|
462
|
-
// When should two answers to a problem take different answer types?
|
|
463
|
-
// See D27790 for more discussion.
|
|
464
|
-
export const unionAnswerForms: (
|
|
465
|
-
arg1: ReadonlyArray<ReadonlyArray<PerseusNumericInputAnswerForm>>,
|
|
466
|
-
) => ReadonlyArray<PerseusNumericInputAnswerForm> = function (answerFormsList) {
|
|
467
|
-
// Takes a list of lists of answer forms, and returns a list of the forms
|
|
468
|
-
// in each of these lists in the same order that they're listed in the
|
|
469
|
-
// `formExamples` forms from above.
|
|
470
|
-
|
|
471
|
-
// uniqueBy takes a list of elements and a function which compares whether
|
|
472
|
-
// two elements are equal, and returns a list of unique elements. This is
|
|
473
|
-
// just a helper function here, but works generally.
|
|
474
|
-
const uniqueBy = function (list, iteratee: any) {
|
|
475
|
-
// @ts-expect-error - TS2347 - Untyped function calls may not accept type arguments.
|
|
476
|
-
return list.reduce<Array<any>>((uniqueList, element) => {
|
|
477
|
-
// For each element, decide whether it's already in the list of
|
|
478
|
-
// unique items.
|
|
479
|
-
const inList = _.find(uniqueList, iteratee.bind(null, element));
|
|
480
|
-
if (inList) {
|
|
481
|
-
return uniqueList;
|
|
482
|
-
}
|
|
483
|
-
return uniqueList.concat([element]);
|
|
484
|
-
}, []);
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
// Pull out all of the forms from the different lists.
|
|
488
|
-
const allForms = answerFormsList.flat();
|
|
489
|
-
// Pull out the unique forms using uniqueBy.
|
|
490
|
-
const uniqueForms = uniqueBy(allForms, _.isEqual);
|
|
491
|
-
// Sort them by the order they appear in the `formExamples` list.
|
|
492
|
-
const formExampleKeys = Object.keys(formExamples);
|
|
493
|
-
return _.sortBy(uniqueForms, (form) => {
|
|
494
|
-
return formExampleKeys.indexOf(form.name);
|
|
495
|
-
});
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
type RenderProps = {
|
|
499
|
-
answerForms: ReadonlyArray<{
|
|
500
|
-
simplify: "required" | "correct" | "enforced" | null | undefined;
|
|
501
|
-
name: "integer" | "decimal" | "proper" | "improper" | "mixed" | "pi";
|
|
502
|
-
}>;
|
|
503
|
-
labelText: string;
|
|
504
|
-
size: "normal" | "small";
|
|
505
|
-
coefficient: boolean;
|
|
506
|
-
rightAlign?: boolean;
|
|
507
|
-
static: boolean;
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
// This function checks if the user inputted a percent value, parsing
|
|
511
|
-
// it as a number (and maybe scaling) so that it can be graded.
|
|
512
|
-
// NOTE(michaelpolyak): Unlike `KhanAnswerTypes.number.percent()` which
|
|
513
|
-
// can accept several input forms with or without "%", the decision
|
|
514
|
-
// to parse based on the presence of "%" in the input, is so that we
|
|
515
|
-
// don't accidently scale the user typed value before grading, CP-930.
|
|
516
|
-
export function maybeParsePercentInput(
|
|
517
|
-
inputValue: string | number,
|
|
518
|
-
normalizedAnswerExpected: boolean,
|
|
519
|
-
): string | number {
|
|
520
|
-
// If the input value is not a string ending with "%", then there's
|
|
521
|
-
// nothing more to do. The value will be graded as inputted by user.
|
|
522
|
-
if (!(typeof inputValue === "string" && inputValue.endsWith("%"))) {
|
|
523
|
-
return inputValue;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const value = parseFloat(inputValue.slice(0, -1));
|
|
527
|
-
// If the input value stripped of the "%" cannot be parsed as a
|
|
528
|
-
// number (the slice is not really necessary for parseFloat to work
|
|
529
|
-
// if the string starts with a number) then return the original
|
|
530
|
-
// input for grading.
|
|
531
|
-
if (isNaN(value)) {
|
|
532
|
-
return inputValue;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// Next, if all correct answers are in the range of |0,1| then we
|
|
536
|
-
// scale the user typed value. We assume this is the correct thing
|
|
537
|
-
// to do since the input value ends with "%".
|
|
538
|
-
if (normalizedAnswerExpected) {
|
|
539
|
-
return value / 100;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// Otherwise, we return input valuåe (number) stripped of the "%".
|
|
543
|
-
return value;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
const propsTransform = function (
|
|
547
|
-
widgetOptions: PerseusNumericInputWidgetOptions,
|
|
548
|
-
): RenderProps {
|
|
549
|
-
const rendererProps = _.extend(_.omit(widgetOptions, "answers"), {
|
|
550
|
-
answerForms: unionAnswerForms(
|
|
551
|
-
// Pull out the name of each form and whether that form has
|
|
552
|
-
// required simplification.
|
|
553
|
-
widgetOptions.answers.map((answer) => {
|
|
554
|
-
// @ts-expect-error - TS2345 - Argument of type 'readonly MathFormat[] | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
555
|
-
return _.map(answer.answerForms, (form) => {
|
|
556
|
-
return {
|
|
557
|
-
simplify: answer.simplify,
|
|
558
|
-
name: form,
|
|
559
|
-
};
|
|
560
|
-
});
|
|
561
|
-
}),
|
|
562
|
-
),
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
return rendererProps;
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
export default {
|
|
569
|
-
name: "numeric-input",
|
|
570
|
-
displayName: "Numeric input",
|
|
571
|
-
defaultAlignment: "inline-block",
|
|
572
|
-
accessible: true,
|
|
573
|
-
widget: NumericInput,
|
|
574
|
-
transform: propsTransform,
|
|
575
|
-
isLintable: true,
|
|
576
|
-
} as WidgetExports<typeof NumericInput>;
|