@khanacademy/perseus 19.1.5 → 19.1.7
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/components/graph.d.ts +0 -1
- package/dist/components/graphie.d.ts +0 -1
- package/dist/es/index.js +319 -212
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +338 -222
- package/dist/index.js.map +1 -1
- package/dist/interactive2/movable-point.d.ts +195 -1
- package/dist/interactive2/movable.d.ts +1 -1
- package/dist/interactive2/types.d.ts +4 -2
- package/dist/interactive2.d.ts +2 -1
- package/dist/server-item-renderer.d.ts +2 -2
- package/dist/util/graphie.d.ts +12 -2
- package/dist/widgets/expression.d.ts +6 -6
- 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,520 +0,0 @@
|
|
|
1
|
-
import {linterContextDefault} from "@khanacademy/perseus-linter";
|
|
2
|
-
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import Renderer from "../../renderer";
|
|
6
|
-
import Util from "../../util";
|
|
7
|
-
import PassageRef from "../passage-ref";
|
|
8
|
-
|
|
9
|
-
import BaseRadio from "./base-radio";
|
|
10
|
-
|
|
11
|
-
import type {FocusFunction, ChoiceType} from "./base-radio";
|
|
12
|
-
import type {
|
|
13
|
-
PerseusRadioChoice,
|
|
14
|
-
PerseusRadioWidgetOptions,
|
|
15
|
-
} from "../../perseus-types";
|
|
16
|
-
import type {PerseusScore, WidgetProps, ChoiceState} from "../../types";
|
|
17
|
-
|
|
18
|
-
// RenderProps is the return type for radio.jsx#transform
|
|
19
|
-
export type RenderProps = {
|
|
20
|
-
numCorrect: number;
|
|
21
|
-
hasNoneOfTheAbove?: boolean;
|
|
22
|
-
multipleSelect?: boolean;
|
|
23
|
-
countChoices?: boolean;
|
|
24
|
-
deselectEnabled?: boolean;
|
|
25
|
-
choices: ReadonlyArray<RadioChoiceWithMetadata>;
|
|
26
|
-
selectedChoices: ReadonlyArray<PerseusRadioChoice["correct"]>;
|
|
27
|
-
choiceStates?: ReadonlyArray<ChoiceState>;
|
|
28
|
-
// Depreciated; support for legacy way of handling changes
|
|
29
|
-
// Adds proptype for prop that is used but was lacking type
|
|
30
|
-
values?: ReadonlyArray<boolean>;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
type UserInput = {
|
|
34
|
-
countChoices?: boolean;
|
|
35
|
-
choicesSelected: ReadonlyArray<boolean>;
|
|
36
|
-
numCorrect?: number;
|
|
37
|
-
noneOfTheAboveIndex?: number | null | undefined;
|
|
38
|
-
noneOfTheAboveSelected?: boolean;
|
|
39
|
-
};
|
|
40
|
-
type Rubric = PerseusRadioWidgetOptions;
|
|
41
|
-
type Props = WidgetProps<RenderProps, Rubric>;
|
|
42
|
-
|
|
43
|
-
type DefaultProps = {
|
|
44
|
-
choices: Props["choices"];
|
|
45
|
-
multipleSelect: Props["multipleSelect"];
|
|
46
|
-
countChoices: Props["countChoices"];
|
|
47
|
-
deselectEnabled: Props["deselectEnabled"];
|
|
48
|
-
linterContext: Props["linterContext"];
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export type RadioChoiceWithMetadata = PerseusRadioChoice & {
|
|
52
|
-
originalIndex: number;
|
|
53
|
-
correct: boolean;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
class Radio extends React.Component<Props> {
|
|
57
|
-
// @ts-expect-error - TS2564 - Property 'focusFunction' has no initializer and is not definitely assigned in the constructor.
|
|
58
|
-
focusFunction: FocusFunction;
|
|
59
|
-
|
|
60
|
-
static defaultProps: DefaultProps = {
|
|
61
|
-
choices: [],
|
|
62
|
-
multipleSelect: false,
|
|
63
|
-
countChoices: false,
|
|
64
|
-
deselectEnabled: false,
|
|
65
|
-
linterContext: linterContextDefault,
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
static validate(userInput: UserInput, rubric: Rubric): PerseusScore {
|
|
69
|
-
const numSelected = userInput.choicesSelected.reduce(
|
|
70
|
-
(sum, selected) => {
|
|
71
|
-
return sum + (selected ? 1 : 0);
|
|
72
|
-
},
|
|
73
|
-
0,
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
if (numSelected === 0) {
|
|
77
|
-
return {
|
|
78
|
-
type: "invalid",
|
|
79
|
-
message: null,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
userInput.numCorrect &&
|
|
85
|
-
userInput.numCorrect > 1 &&
|
|
86
|
-
numSelected !== userInput.numCorrect
|
|
87
|
-
) {
|
|
88
|
-
return {
|
|
89
|
-
type: "invalid",
|
|
90
|
-
message: i18n._("Please choose the correct number of answers."),
|
|
91
|
-
};
|
|
92
|
-
// If NOTA and some other answer are checked, ...
|
|
93
|
-
}
|
|
94
|
-
if (userInput.noneOfTheAboveSelected && numSelected > 1) {
|
|
95
|
-
return {
|
|
96
|
-
type: "invalid",
|
|
97
|
-
message: i18n._(
|
|
98
|
-
"'None of the above' may not be selected " +
|
|
99
|
-
"when other answers are selected.",
|
|
100
|
-
),
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const correct = userInput.choicesSelected.every((selected, i) => {
|
|
105
|
-
let isCorrect;
|
|
106
|
-
if (userInput.noneOfTheAboveIndex === i) {
|
|
107
|
-
isCorrect = rubric.choices.every((choice, j) => {
|
|
108
|
-
return i === j || !choice.correct;
|
|
109
|
-
});
|
|
110
|
-
} else {
|
|
111
|
-
isCorrect = !!rubric.choices[i].correct;
|
|
112
|
-
}
|
|
113
|
-
return isCorrect === selected;
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
type: "points",
|
|
118
|
-
earned: correct ? 1 : 0,
|
|
119
|
-
total: 1,
|
|
120
|
-
message: null,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
static getUserInputFromProps(props: Props): UserInput {
|
|
125
|
-
// Return checked inputs in the form {choicesSelected: [bool]}. (Dear
|
|
126
|
-
// future timeline implementers: this used to be {value: i} before
|
|
127
|
-
// multiple select was added)
|
|
128
|
-
if (props.choiceStates) {
|
|
129
|
-
let noneOfTheAboveIndex = null;
|
|
130
|
-
let noneOfTheAboveSelected = false;
|
|
131
|
-
|
|
132
|
-
const choiceStates = props.choiceStates;
|
|
133
|
-
const choicesSelected = choiceStates.map(() => false);
|
|
134
|
-
const countChoices = props.countChoices;
|
|
135
|
-
const numCorrect = props.numCorrect;
|
|
136
|
-
|
|
137
|
-
for (let i = 0; i < choicesSelected.length; i++) {
|
|
138
|
-
const index = props.choices[i].originalIndex;
|
|
139
|
-
|
|
140
|
-
choicesSelected[index] = choiceStates[i].selected;
|
|
141
|
-
|
|
142
|
-
if (props.choices[i].isNoneOfTheAbove) {
|
|
143
|
-
// @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'null'.
|
|
144
|
-
noneOfTheAboveIndex = index;
|
|
145
|
-
|
|
146
|
-
if (choicesSelected[i]) {
|
|
147
|
-
noneOfTheAboveSelected = true;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
countChoices,
|
|
154
|
-
choicesSelected,
|
|
155
|
-
numCorrect,
|
|
156
|
-
noneOfTheAboveIndex,
|
|
157
|
-
noneOfTheAboveSelected,
|
|
158
|
-
};
|
|
159
|
-
// Support legacy choiceState implementation
|
|
160
|
-
}
|
|
161
|
-
/* c8 ignore if - props.values is deprecated */
|
|
162
|
-
const {values} = props;
|
|
163
|
-
if (values) {
|
|
164
|
-
let noneOfTheAboveIndex = null;
|
|
165
|
-
let noneOfTheAboveSelected = false;
|
|
166
|
-
|
|
167
|
-
const choicesSelected = [...values];
|
|
168
|
-
const countChoices = props.countChoices;
|
|
169
|
-
const numCorrect = props.numCorrect;
|
|
170
|
-
const valuesLength = values.length;
|
|
171
|
-
|
|
172
|
-
for (let i = 0; i < valuesLength; i++) {
|
|
173
|
-
const index = props.choices[i].originalIndex;
|
|
174
|
-
choicesSelected[index] = values[i];
|
|
175
|
-
|
|
176
|
-
if (props.choices[i].isNoneOfTheAbove) {
|
|
177
|
-
// @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'null'.
|
|
178
|
-
noneOfTheAboveIndex = index;
|
|
179
|
-
if (choicesSelected[i]) {
|
|
180
|
-
noneOfTheAboveSelected = true;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
return {
|
|
185
|
-
choicesSelected,
|
|
186
|
-
noneOfTheAboveIndex,
|
|
187
|
-
noneOfTheAboveSelected,
|
|
188
|
-
countChoices,
|
|
189
|
-
numCorrect,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
// Nothing checked
|
|
193
|
-
return {
|
|
194
|
-
choicesSelected: props.choices.map(() => false),
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
_renderRenderer: (content?: string) => React.ReactElement = (
|
|
199
|
-
content = "",
|
|
200
|
-
) => {
|
|
201
|
-
let nextPassageRefId = 1;
|
|
202
|
-
const widgets: Record<string, any> = {};
|
|
203
|
-
|
|
204
|
-
const modContent = content.replace(
|
|
205
|
-
/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,
|
|
206
|
-
(
|
|
207
|
-
match: string,
|
|
208
|
-
passageNum: string,
|
|
209
|
-
refNum: string,
|
|
210
|
-
summaryText: string,
|
|
211
|
-
) => {
|
|
212
|
-
const widgetId = "passage-ref " + nextPassageRefId;
|
|
213
|
-
nextPassageRefId++;
|
|
214
|
-
|
|
215
|
-
widgets[widgetId] = {
|
|
216
|
-
type: "passage-ref",
|
|
217
|
-
graded: false,
|
|
218
|
-
options: {
|
|
219
|
-
passageNumber: parseInt(passageNum),
|
|
220
|
-
referenceNumber: parseInt(refNum),
|
|
221
|
-
summaryText: summaryText,
|
|
222
|
-
},
|
|
223
|
-
version: PassageRef.version,
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
return "[[" + Util.snowman + " " + widgetId + "]]";
|
|
227
|
-
},
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
// alwaysUpdate={true} so that passage-refs findWidgets
|
|
231
|
-
// get called when the outer passage updates the renderer
|
|
232
|
-
// TODO(aria): This is really hacky
|
|
233
|
-
// We pass in a key here so that we avoid a semi-spurious
|
|
234
|
-
// react warning when the ChoiceNoneAbove renders a
|
|
235
|
-
// different renderer in the same place. Note this destroys
|
|
236
|
-
// state, but since all we're doing is outputting
|
|
237
|
-
// "None of the above", that is okay.
|
|
238
|
-
// TODO(mdr): Widgets inside this Renderer are not discoverable through
|
|
239
|
-
// the parent Renderer's `findWidgets` function.
|
|
240
|
-
return (
|
|
241
|
-
<Renderer
|
|
242
|
-
key="choiceContentRenderer"
|
|
243
|
-
content={modContent}
|
|
244
|
-
widgets={widgets}
|
|
245
|
-
findExternalWidgets={this.props.findWidgets}
|
|
246
|
-
alwaysUpdate={true}
|
|
247
|
-
linterContext={{
|
|
248
|
-
...this.props.linterContext,
|
|
249
|
-
// @ts-expect-error - TS2322 - Type '{ blockHighlight: true; contentType: string; highlightLint: boolean; paths: readonly string[]; stack: readonly string[]; }' is not assignable to type 'LinterContextProps'.
|
|
250
|
-
blockHighlight: true,
|
|
251
|
-
}}
|
|
252
|
-
/>
|
|
253
|
-
);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
// TODO(LP-10672): I think this might be unused right now. I can't find anywhere
|
|
257
|
-
// that we pass a value to `.focus()` and it seems to have been used for
|
|
258
|
-
// adding hints when editing.
|
|
259
|
-
// See: https://github.com/Khan/perseus/blame/e18582b4b69959270b90e237ef1813899711ddfa/src/widgets/radio.js#L169
|
|
260
|
-
focus(choiceIndex?: number | null): boolean {
|
|
261
|
-
if (this.focusFunction) {
|
|
262
|
-
return this.focusFunction(choiceIndex);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return false;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// lets BaseRadio regiser a focus callback so widget
|
|
269
|
-
// can focus an individual choice
|
|
270
|
-
registerFocusFunction(fun: FocusFunction): void {
|
|
271
|
-
this.focusFunction = fun;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// When `BaseRadio`'s `onChange` handler is called, indicating a change in
|
|
275
|
-
// our choices' state, we need to call our `onChange` handler in order to
|
|
276
|
-
// persist those changes in the item's Perseus state.
|
|
277
|
-
//
|
|
278
|
-
// So, given the new values for each choice, construct the new
|
|
279
|
-
// `choiceStates` objects, and pass them to `this.props.onChange`.
|
|
280
|
-
//
|
|
281
|
-
// `newValueLists` is an object with two keys: `checked` and `crossedOut`.
|
|
282
|
-
// Each contains an array of boolean values, specifying the new checked and
|
|
283
|
-
// crossed-out value of each choice.
|
|
284
|
-
//
|
|
285
|
-
// NOTE(mdr): This method expects to be auto-bound. If this component is
|
|
286
|
-
// converted to an ES6 class, take care to auto-bind this method!
|
|
287
|
-
updateChoices: (
|
|
288
|
-
newValueLists: Readonly<{
|
|
289
|
-
checked: ReadonlyArray<boolean>;
|
|
290
|
-
crossedOut: ReadonlyArray<boolean>;
|
|
291
|
-
}>,
|
|
292
|
-
) => void = (newValueLists) => {
|
|
293
|
-
const {choiceStates, choices} = this.props;
|
|
294
|
-
|
|
295
|
-
// Construct the baseline `choiceStates` objects. If this is the user's
|
|
296
|
-
// first interaction with the widget, we'll need to initialize them to
|
|
297
|
-
// new objects with all fields set to the default values. Otherwise, we
|
|
298
|
-
// should clone the old `choiceStates` objects, in preparation to
|
|
299
|
-
// mutate them.
|
|
300
|
-
const newChoiceStates = choiceStates
|
|
301
|
-
? choiceStates.map((state: ChoiceState) => ({...state}))
|
|
302
|
-
: choices.map(() => ({
|
|
303
|
-
selected: false,
|
|
304
|
-
crossedOut: false,
|
|
305
|
-
highlighted: false,
|
|
306
|
-
rationaleShown: false,
|
|
307
|
-
correctnessShown: false,
|
|
308
|
-
previouslyAnswered: false,
|
|
309
|
-
readOnly: false,
|
|
310
|
-
}));
|
|
311
|
-
|
|
312
|
-
// Mutate the new `choiceState` objects, according to the new `checked`
|
|
313
|
-
// and `crossedOut` values provided in `newValueLists`.
|
|
314
|
-
newChoiceStates.forEach((choiceState: ChoiceState, i) => {
|
|
315
|
-
choiceState.selected = newValueLists.checked[i];
|
|
316
|
-
choiceState.crossedOut = newValueLists.crossedOut[i];
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
this.props.onChange({choiceStates: newChoiceStates});
|
|
320
|
-
this.props.trackInteraction();
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
getUserInput: () => UserInput = () => {
|
|
324
|
-
return Radio.getUserInputFromProps(this.props);
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
simpleValidate: (arg1: PerseusRadioWidgetOptions) => PerseusScore = (
|
|
328
|
-
rubric,
|
|
329
|
-
) => {
|
|
330
|
-
return Radio.validate(this.getUserInput(), rubric);
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Turn on rationale display for the currently selected choices. Note that
|
|
335
|
-
* this leaves rationales on for choices that are already showing
|
|
336
|
-
* rationales.
|
|
337
|
-
*/
|
|
338
|
-
showRationalesForCurrentlySelectedChoices: (
|
|
339
|
-
arg1: PerseusRadioWidgetOptions,
|
|
340
|
-
) => void = (rubric) => {
|
|
341
|
-
const {choiceStates} = this.props;
|
|
342
|
-
if (choiceStates) {
|
|
343
|
-
const score = this.simpleValidate(rubric);
|
|
344
|
-
const widgetCorrect =
|
|
345
|
-
score.type === "points" && score.total === score.earned;
|
|
346
|
-
|
|
347
|
-
const newStates: ReadonlyArray<ChoiceState> = choiceStates.map(
|
|
348
|
-
(state: ChoiceState): ChoiceState => ({
|
|
349
|
-
...state,
|
|
350
|
-
highlighted: state.selected,
|
|
351
|
-
// If the choice is selected, show the rationale now
|
|
352
|
-
rationaleShown:
|
|
353
|
-
state.selected ||
|
|
354
|
-
// If the choice already had a rationale, keep it shown
|
|
355
|
-
state.rationaleShown ||
|
|
356
|
-
// If the widget is correctly answered, show the rationale
|
|
357
|
-
// for all the choices
|
|
358
|
-
widgetCorrect,
|
|
359
|
-
// We use the same behavior for the readOnly flag as for
|
|
360
|
-
// rationaleShown, but we keep it separate in case other
|
|
361
|
-
// behaviors want to disable choices without showing rationales.
|
|
362
|
-
readOnly: state.selected || state.readOnly || widgetCorrect,
|
|
363
|
-
correctnessShown: state.selected || state.correctnessShown,
|
|
364
|
-
previouslyAnswered:
|
|
365
|
-
state.previouslyAnswered || state.selected,
|
|
366
|
-
}),
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
this.props.onChange(
|
|
370
|
-
{
|
|
371
|
-
choiceStates: newStates,
|
|
372
|
-
},
|
|
373
|
-
// @ts-expect-error - TS2345 - Argument of type 'null' is not assignable to parameter of type '(() => unknown) | undefined'.
|
|
374
|
-
null, // cb
|
|
375
|
-
true, // silent
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Deselects any currently-selected choices that are not correct choices.
|
|
382
|
-
*/
|
|
383
|
-
deselectIncorrectSelectedChoices: () => void = () => {
|
|
384
|
-
if (this.props.choiceStates) {
|
|
385
|
-
const newStates: ReadonlyArray<ChoiceState> =
|
|
386
|
-
this.props.choiceStates.map(
|
|
387
|
-
(state: ChoiceState, i): ChoiceState => ({
|
|
388
|
-
...state,
|
|
389
|
-
selected:
|
|
390
|
-
state.selected && !!this.props.choices[i].correct,
|
|
391
|
-
highlighted: false,
|
|
392
|
-
}),
|
|
393
|
-
);
|
|
394
|
-
|
|
395
|
-
this.props.onChange(
|
|
396
|
-
{
|
|
397
|
-
choiceStates: newStates,
|
|
398
|
-
},
|
|
399
|
-
// @ts-expect-error - TS2345 - Argument of type 'null' is not assignable to parameter of type '(() => unknown) | undefined'.
|
|
400
|
-
null, // cb
|
|
401
|
-
false, // silent
|
|
402
|
-
);
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
render(): React.ReactNode {
|
|
407
|
-
const {choices} = this.props;
|
|
408
|
-
let choiceStates: ReadonlyArray<ChoiceState>;
|
|
409
|
-
if (this.props.static) {
|
|
410
|
-
choiceStates = choices.map((choice) => ({
|
|
411
|
-
selected: !!choice.correct,
|
|
412
|
-
crossedOut: false,
|
|
413
|
-
readOnly: true,
|
|
414
|
-
highlighted: false,
|
|
415
|
-
rationaleShown: true,
|
|
416
|
-
correctnessShown: true,
|
|
417
|
-
previouslyAnswered: false,
|
|
418
|
-
}));
|
|
419
|
-
} else if (this.props.choiceStates) {
|
|
420
|
-
choiceStates = this.props.choiceStates;
|
|
421
|
-
} else if (this.props.values) {
|
|
422
|
-
// Support legacy choiceStates implementation
|
|
423
|
-
/* c8 ignore next - props.values is deprecated */
|
|
424
|
-
choiceStates = this.props.values.map((val) => ({
|
|
425
|
-
selected: val,
|
|
426
|
-
crossedOut: false,
|
|
427
|
-
readOnly: false,
|
|
428
|
-
highlighted: false,
|
|
429
|
-
rationaleShown: false,
|
|
430
|
-
correctnessShown: false,
|
|
431
|
-
previouslyAnswered: false,
|
|
432
|
-
}));
|
|
433
|
-
} else {
|
|
434
|
-
choiceStates = choices.map(() => ({
|
|
435
|
-
selected: false,
|
|
436
|
-
crossedOut: false,
|
|
437
|
-
readOnly: false,
|
|
438
|
-
highlighted: false,
|
|
439
|
-
rationaleShown: false,
|
|
440
|
-
correctnessShown: false,
|
|
441
|
-
previouslyAnswered: false,
|
|
442
|
-
}));
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const choicesProp: ReadonlyArray<ChoiceType> = choices.map(
|
|
446
|
-
(choice, i) => {
|
|
447
|
-
const content =
|
|
448
|
-
choice.isNoneOfTheAbove && !choice.content
|
|
449
|
-
? // we use i18n._ instead of $_ here because the content
|
|
450
|
-
// sent to a renderer needs to be a string, not a react
|
|
451
|
-
// node (/renderable/fragment).
|
|
452
|
-
i18n._("None of the above")
|
|
453
|
-
: choice.content;
|
|
454
|
-
|
|
455
|
-
const {
|
|
456
|
-
selected,
|
|
457
|
-
crossedOut,
|
|
458
|
-
rationaleShown,
|
|
459
|
-
correctnessShown,
|
|
460
|
-
readOnly,
|
|
461
|
-
highlighted,
|
|
462
|
-
previouslyAnswered,
|
|
463
|
-
} = choiceStates[i];
|
|
464
|
-
|
|
465
|
-
const reviewChoice =
|
|
466
|
-
this.props.reviewModeRubric &&
|
|
467
|
-
this.props.reviewModeRubric.choices[i];
|
|
468
|
-
|
|
469
|
-
return {
|
|
470
|
-
content: this._renderRenderer(content),
|
|
471
|
-
checked: selected,
|
|
472
|
-
// Current versions of the radio widget always pass in the
|
|
473
|
-
// "correct" value through the choices. Old serialized state
|
|
474
|
-
// for radio widgets doesn't have this though, so we have to
|
|
475
|
-
// pull the correctness out of the review mode rubric. This
|
|
476
|
-
// only works because all of the places we use
|
|
477
|
-
// `restoreSerializedState()` also turn on reviewMode, but is
|
|
478
|
-
// fine for now.
|
|
479
|
-
// TODO(emily): Come up with a more comprehensive way to solve
|
|
480
|
-
// this sort of "serialized state breaks when internal
|
|
481
|
-
// structure changes" problem.
|
|
482
|
-
correct:
|
|
483
|
-
choice.correct === undefined
|
|
484
|
-
? !!reviewChoice && !!reviewChoice.correct
|
|
485
|
-
: choice.correct,
|
|
486
|
-
disabled: readOnly,
|
|
487
|
-
hasRationale: !!choice.clue,
|
|
488
|
-
rationale: this._renderRenderer(choice.clue),
|
|
489
|
-
showRationale: rationaleShown,
|
|
490
|
-
showCorrectness: correctnessShown,
|
|
491
|
-
isNoneOfTheAbove: !!choice.isNoneOfTheAbove,
|
|
492
|
-
revealNoneOfTheAbove: !!(
|
|
493
|
-
this.props.questionCompleted && selected
|
|
494
|
-
),
|
|
495
|
-
crossedOut,
|
|
496
|
-
highlighted,
|
|
497
|
-
previouslyAnswered: previouslyAnswered,
|
|
498
|
-
};
|
|
499
|
-
},
|
|
500
|
-
);
|
|
501
|
-
|
|
502
|
-
return (
|
|
503
|
-
<BaseRadio
|
|
504
|
-
labelWrap={true}
|
|
505
|
-
multipleSelect={this.props.multipleSelect}
|
|
506
|
-
countChoices={this.props.countChoices}
|
|
507
|
-
numCorrect={this.props.numCorrect}
|
|
508
|
-
choices={choicesProp}
|
|
509
|
-
onChange={this.updateChoices}
|
|
510
|
-
reviewModeRubric={this.props.reviewModeRubric}
|
|
511
|
-
deselectEnabled={this.props.deselectEnabled}
|
|
512
|
-
apiOptions={this.props.apiOptions}
|
|
513
|
-
isLastUsedWidget={this.props.isLastUsedWidget}
|
|
514
|
-
registerFocusFunction={(i) => this.registerFocusFunction(i)}
|
|
515
|
-
/>
|
|
516
|
-
);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
export default Radio;
|
package/src/widgets/radio.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
2
|
-
import _ from "underscore";
|
|
3
|
-
|
|
4
|
-
import Util from "../util";
|
|
5
|
-
|
|
6
|
-
import Radio from "./radio/widget";
|
|
7
|
-
|
|
8
|
-
import type {RenderProps, RadioChoiceWithMetadata} from "./radio/widget";
|
|
9
|
-
import type {PerseusRadioWidgetOptions} from "../perseus-types";
|
|
10
|
-
import type {WidgetExports} from "../types";
|
|
11
|
-
|
|
12
|
-
const {shuffle, random} = Util;
|
|
13
|
-
|
|
14
|
-
// Represents choices that we automatically re-order if encountered.
|
|
15
|
-
// Note: these are in the reversed (incorrect) order that we will swap, if
|
|
16
|
-
// found.
|
|
17
|
-
// Note 2: these are internationalized when compared later on.
|
|
18
|
-
const ReversedChoices: ReadonlyArray<[string, string]> = [
|
|
19
|
-
[i18n._("False"), i18n._("True")],
|
|
20
|
-
[i18n._("No"), i18n._("Yes")],
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
// Transforms the choices for display.
|
|
24
|
-
const _choiceTransform = (
|
|
25
|
-
widgetOptions: PerseusRadioWidgetOptions,
|
|
26
|
-
problemNum?: number | null,
|
|
27
|
-
) => {
|
|
28
|
-
const _maybeRandomize = function (
|
|
29
|
-
array: ReadonlyArray<RadioChoiceWithMetadata>,
|
|
30
|
-
) {
|
|
31
|
-
const randomSeed = problemNum === undefined ? random : problemNum;
|
|
32
|
-
// NOTE: `problemNum` will only be set when the radio widget is
|
|
33
|
-
// rendered at the root of an exercise question. It will be `undefined`
|
|
34
|
-
// if it's rendered embedded in another widget, such as `graded-group`,
|
|
35
|
-
// or if rendered within an article. This results in a predictable
|
|
36
|
-
// shuffle order. To avoid this we use a random seed when `problemNum`
|
|
37
|
-
// is `undefined`.
|
|
38
|
-
return widgetOptions.randomize
|
|
39
|
-
? shuffle(array, randomSeed ?? 0)
|
|
40
|
-
: array;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const _addNoneOfAbove = function (
|
|
44
|
-
choices: ReadonlyArray<RadioChoiceWithMetadata>,
|
|
45
|
-
) {
|
|
46
|
-
let noneOfTheAbove = null;
|
|
47
|
-
|
|
48
|
-
const newChoices = choices.filter((choice, index) => {
|
|
49
|
-
if (choice.isNoneOfTheAbove) {
|
|
50
|
-
// @ts-expect-error - TS2322 - Type 'RadioChoiceWithMetadata' is not assignable to type 'null'.
|
|
51
|
-
noneOfTheAbove = choice;
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
return true;
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// Place the "None of the above" options last
|
|
58
|
-
if (noneOfTheAbove) {
|
|
59
|
-
newChoices.push(noneOfTheAbove);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return newChoices;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const enforceOrdering = (
|
|
66
|
-
choices: ReadonlyArray<RadioChoiceWithMetadata>,
|
|
67
|
-
) => {
|
|
68
|
-
const content = choices.map((c) => c.content);
|
|
69
|
-
if (ReversedChoices.some((reversed) => _.isEqual(content, reversed))) {
|
|
70
|
-
return [choices[1], choices[0]];
|
|
71
|
-
}
|
|
72
|
-
return choices;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// Add meta-information to choices
|
|
76
|
-
const choices: ReadonlyArray<RadioChoiceWithMetadata> =
|
|
77
|
-
widgetOptions.choices.map((choice, i): RadioChoiceWithMetadata => {
|
|
78
|
-
return {
|
|
79
|
-
...choice,
|
|
80
|
-
originalIndex: i,
|
|
81
|
-
correct: Boolean(choice.correct),
|
|
82
|
-
};
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Apply all the transforms. Note that the order we call these is
|
|
86
|
-
// important!
|
|
87
|
-
// 3) finally add "None of the above" to the bottom
|
|
88
|
-
return _addNoneOfAbove(
|
|
89
|
-
// 2) then (potentially) enforce ordering (eg. False, True becomes
|
|
90
|
-
// True, False)
|
|
91
|
-
enforceOrdering(
|
|
92
|
-
// 1) we randomize the order first
|
|
93
|
-
_maybeRandomize(choices),
|
|
94
|
-
),
|
|
95
|
-
);
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const transform = (
|
|
99
|
-
widgetOptions: PerseusRadioWidgetOptions,
|
|
100
|
-
problemNum?: number | null,
|
|
101
|
-
): RenderProps => {
|
|
102
|
-
const choices = _choiceTransform(widgetOptions, problemNum);
|
|
103
|
-
|
|
104
|
-
const numCorrect: number = _.reduce(
|
|
105
|
-
widgetOptions.choices,
|
|
106
|
-
function (memo, choice) {
|
|
107
|
-
return choice.correct ? memo + 1 : memo;
|
|
108
|
-
},
|
|
109
|
-
0,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
const {hasNoneOfTheAbove, multipleSelect, countChoices, deselectEnabled} =
|
|
113
|
-
widgetOptions;
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
numCorrect,
|
|
117
|
-
hasNoneOfTheAbove,
|
|
118
|
-
multipleSelect,
|
|
119
|
-
countChoices,
|
|
120
|
-
deselectEnabled,
|
|
121
|
-
choices,
|
|
122
|
-
selectedChoices: _.pluck(choices, "correct"),
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const propUpgrades = {
|
|
127
|
-
"1": (v0props: any): any => {
|
|
128
|
-
let choices;
|
|
129
|
-
let hasNoneOfTheAbove;
|
|
130
|
-
|
|
131
|
-
if (!v0props.noneOfTheAbove) {
|
|
132
|
-
choices = v0props.choices;
|
|
133
|
-
hasNoneOfTheAbove = false;
|
|
134
|
-
} else {
|
|
135
|
-
throw new Error(
|
|
136
|
-
"radio widget v0 no longer supports auto noneOfTheAbove",
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return _.extend(_.omit(v0props, "noneOfTheAbove"), {
|
|
141
|
-
choices: choices,
|
|
142
|
-
hasNoneOfTheAbove: hasNoneOfTheAbove,
|
|
143
|
-
});
|
|
144
|
-
},
|
|
145
|
-
} as const;
|
|
146
|
-
|
|
147
|
-
export default {
|
|
148
|
-
name: "radio",
|
|
149
|
-
displayName: "Radio / Multiple choice",
|
|
150
|
-
accessible: true,
|
|
151
|
-
widget: Radio,
|
|
152
|
-
transform: transform,
|
|
153
|
-
staticTransform: transform,
|
|
154
|
-
version: {major: 1, minor: 0},
|
|
155
|
-
propUpgrades: propUpgrades,
|
|
156
|
-
isLintable: true,
|
|
157
|
-
} as WidgetExports<typeof Radio>;
|