@khanacademy/perseus 0.4.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +6 -1
- package/CHANGELOG.md +45 -0
- package/dist/es/index.css +15 -8
- package/dist/es/index.js +1214 -1404
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +15 -8
- package/dist/index.js +1217 -1411
- package/dist/index.js.map +1 -1
- package/dist/strings.js +0 -4
- package/package.json +9 -8
- package/src/components/number-input.jsx +2 -2
- package/src/components/simple-keypad-input.jsx +18 -21
- package/src/index.js +1 -1
- package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +426 -135
- package/src/multi-items/__tests__/multi-renderer_test.js +9 -9
- package/src/perseus-api.jsx +10 -36
- package/src/perseus-types.js +18 -145
- package/src/styles/constants.js +0 -2
- package/src/styles/perseus-renderer.less +8 -2
- package/src/styles/variables.less +0 -2
- package/src/styles/widgets/passage.less +9 -5
- package/src/types.js +18 -35
- package/src/util/answer-types.js +2 -3
- package/src/util/math.js +3 -10
- package/src/util.js +0 -6
- package/src/version.js +1 -1
- package/src/widgets/__stories__/numeric-input.stories.jsx +43 -2
- package/src/widgets/__testdata__/base-radio_testdata.js +22 -0
- package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +4 -4
- package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +291 -130
- package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +3293 -1415
- package/src/widgets/__tests__/group_test.jsx +4 -4
- package/src/widgets/__tests__/numeric-input_test.jsx +12 -8
- package/src/widgets/__tests__/passage_test.jsx +81 -0
- package/src/widgets/__tests__/radio/base-radio_test.jsx +291 -41
- package/src/widgets/__tests__/radio/choice-icon_test.jsx +67 -0
- package/src/widgets/__tests__/radio/choice_test.jsx +302 -0
- package/src/widgets/__tests__/radio/focus-ring_test.jsx +23 -0
- package/src/widgets/__tests__/radio/option-status_test.jsx +65 -0
- package/src/widgets/__tests__/radio_test.jsx +39 -15
- package/src/widgets/definition.jsx +1 -1
- package/src/widgets/group.jsx +84 -102
- package/src/widgets/input-number.jsx +6 -1
- package/src/widgets/numeric-input.jsx +87 -80
- package/src/widgets/passage/__tests__/passage-markdown_test.jsx +0 -9
- package/src/widgets/passage/get-line-height-for-node.js +4 -5
- package/src/widgets/passage/passage-markdown.jsx +176 -120
- package/src/widgets/passage.jsx +48 -46
- package/src/widgets/radio/__stories__/base-radio.stories.jsx +164 -17
- package/src/widgets/radio/__stories__/choice-icon.stories.jsx +202 -111
- package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +21 -6
- package/src/widgets/radio/__stories__/choice.stories.jsx +138 -0
- package/src/widgets/radio/__stories__/focus-ring.stories.jsx +29 -23
- package/src/widgets/radio/__stories__/option-status.stories.jsx +93 -99
- package/src/widgets/radio/base-radio.jsx +485 -556
- package/src/widgets/radio/choice-a11y-text.js +62 -0
- package/src/widgets/radio/choice-icon/choice-icon.jsx +87 -0
- package/src/widgets/radio/choice-icon/cross-out-line.jsx +55 -0
- package/src/widgets/radio/choice-icon/library-choice-icon.jsx +214 -0
- package/src/widgets/radio/choice-icon/sat-choice-icon.jsx +120 -0
- package/src/widgets/radio/choice-icon/shared-styles.js +17 -0
- package/src/widgets/radio/choice-none-above.jsx +49 -40
- package/src/widgets/radio/choice.jsx +319 -347
- package/src/widgets/radio/choice.jsx.fixture.js +0 -18
- package/src/widgets/radio/focus-ring.jsx +29 -22
- package/src/widgets/radio/option-status.jsx +58 -36
- package/src/widgets/radio/widget.jsx +181 -136
- package/src/widgets/radio.jsx +16 -17
- package/src/widgets/radio/__stories__/cross-out-button.stories.jsx +0 -64
- package/src/widgets/radio/choice-icon.jsx +0 -469
- package/src/widgets/radio/cross-out-button.jsx +0 -134
|
@@ -3,35 +3,25 @@ export const instances: $ReadOnlyArray<mixed> = [
|
|
|
3
3
|
({}: {...}),
|
|
4
4
|
{
|
|
5
5
|
content: "Plain Content",
|
|
6
|
-
goToPrevChoice: () => {},
|
|
7
|
-
goToNextChoice: () => {},
|
|
8
6
|
},
|
|
9
7
|
{
|
|
10
8
|
content: "Correct Content (Review)",
|
|
11
9
|
correct: true,
|
|
12
10
|
reviewMode: true,
|
|
13
|
-
goToPrevChoice: () => {},
|
|
14
|
-
goToNextChoice: () => {},
|
|
15
11
|
},
|
|
16
12
|
{
|
|
17
13
|
content: "Incorrect Content (Review)",
|
|
18
14
|
correct: false,
|
|
19
15
|
reviewMode: true,
|
|
20
|
-
goToPrevChoice: () => {},
|
|
21
|
-
goToNextChoice: () => {},
|
|
22
16
|
},
|
|
23
17
|
{
|
|
24
18
|
content: "Content (Review, correctness not specified)",
|
|
25
19
|
reviewMode: true,
|
|
26
|
-
goToPrevChoice: () => {},
|
|
27
|
-
goToNextChoice: () => {},
|
|
28
20
|
},
|
|
29
21
|
{
|
|
30
22
|
content: "Content with Rationale",
|
|
31
23
|
rationale: "This is some additional information",
|
|
32
24
|
showRationale: true,
|
|
33
|
-
goToPrevChoice: () => {},
|
|
34
|
-
goToNextChoice: () => {},
|
|
35
25
|
},
|
|
36
26
|
{
|
|
37
27
|
content: "Correct Content with Rationale (Review)",
|
|
@@ -39,8 +29,6 @@ export const instances: $ReadOnlyArray<mixed> = [
|
|
|
39
29
|
rationale: "This is some additional information",
|
|
40
30
|
reviewMode: true,
|
|
41
31
|
showRationale: true,
|
|
42
|
-
goToPrevChoice: () => {},
|
|
43
|
-
goToNextChoice: () => {},
|
|
44
32
|
},
|
|
45
33
|
{
|
|
46
34
|
content: "Incorrect Content with Rationale (Review)",
|
|
@@ -48,17 +36,11 @@ export const instances: $ReadOnlyArray<mixed> = [
|
|
|
48
36
|
rationale: "This is some additional information",
|
|
49
37
|
reviewMode: true,
|
|
50
38
|
showRationale: true,
|
|
51
|
-
goToPrevChoice: () => {},
|
|
52
|
-
goToNextChoice: () => {},
|
|
53
39
|
},
|
|
54
40
|
{
|
|
55
41
|
content: "Content with Rationale (Review, correctness not specified)",
|
|
56
42
|
rationale: "This is some additional information",
|
|
57
43
|
reviewMode: true,
|
|
58
44
|
showRationale: true,
|
|
59
|
-
goToPrevChoice: () => {},
|
|
60
|
-
goToNextChoice: () => {},
|
|
61
45
|
},
|
|
62
46
|
];
|
|
63
|
-
|
|
64
|
-
export const log = ["goToPrevChoice", "goToNextChoice"];
|
|
@@ -8,40 +8,47 @@ import * as React from "react";
|
|
|
8
8
|
|
|
9
9
|
import * as styleConstants from "../../styles/constants.js";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
children?:
|
|
11
|
+
type Props = {|
|
|
12
|
+
children?: React.Node,
|
|
13
13
|
// Whether the focus ring is visible. Allows for positioning
|
|
14
14
|
// the child identically regardless of whether the ring is visible.
|
|
15
15
|
visible: boolean,
|
|
16
16
|
// Color of the focus ring
|
|
17
17
|
color: string,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
18
|
+
// Whether a user can select multiple options or not
|
|
19
|
+
multipleSelect: boolean,
|
|
20
|
+
|};
|
|
21
|
+
|
|
22
|
+
function FocusRing(props: Props): React.Node {
|
|
23
|
+
const {visible, color, children, multipleSelect} = props;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
const borderColor = visible ? color : "transparent";
|
|
26
|
+
const borderRadius = multipleSelect ? 5 : "50%";
|
|
27
|
+
const style = {
|
|
28
|
+
borderColor,
|
|
29
|
+
borderRadius,
|
|
30
|
+
};
|
|
31
|
+
return (
|
|
32
|
+
<span
|
|
33
|
+
data-test-id="focus-ring"
|
|
34
|
+
className={css(styles.ring)}
|
|
35
|
+
style={style}
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</span>
|
|
39
|
+
);
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
FocusRing.defaultProps = {
|
|
43
|
+
visible: true,
|
|
44
|
+
color: styleConstants.kaGreen,
|
|
45
|
+
multipleSelect: false,
|
|
46
|
+
};
|
|
47
|
+
|
|
40
48
|
const styles = StyleSheet.create({
|
|
41
49
|
ring: {
|
|
42
50
|
margin: "auto",
|
|
43
51
|
display: "inline-block",
|
|
44
|
-
borderRadius: "50%",
|
|
45
52
|
borderWidth: 2,
|
|
46
53
|
padding: 2,
|
|
47
54
|
borderStyle: "solid",
|
|
@@ -12,7 +12,7 @@ import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
|
12
12
|
import {StyleSheet, css} from "aphrodite";
|
|
13
13
|
import * as React from "react";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
type OptionStatusProps = {|
|
|
16
16
|
// Was this option the correct answer?
|
|
17
17
|
correct: boolean,
|
|
18
18
|
// Did the user select this option as the answer?
|
|
@@ -21,49 +21,71 @@ class OptionStatus extends React.Component<{
|
|
|
21
21
|
crossedOut: boolean,
|
|
22
22
|
// Did the user select this option as the answer earlier?
|
|
23
23
|
previouslyAnswered: boolean,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
return i18n._("Correct");
|
|
38
|
-
}
|
|
39
|
-
// But, for incorrect answers, we only surface checked state,
|
|
40
|
-
// because crossing out an incorrect answer is not noteworthy.
|
|
24
|
+
reviewMode: boolean,
|
|
25
|
+
satStyling?: boolean,
|
|
26
|
+
|};
|
|
27
|
+
|
|
28
|
+
function renderText(
|
|
29
|
+
checked: boolean,
|
|
30
|
+
correct: boolean,
|
|
31
|
+
crossedOut: boolean,
|
|
32
|
+
): string {
|
|
33
|
+
if (correct) {
|
|
34
|
+
// For correct answers, we surface checked _or_ crossedOut state,
|
|
35
|
+
// because any interaction with the correct answer is noteworthy!
|
|
41
36
|
if (checked) {
|
|
42
|
-
return i18n._("
|
|
37
|
+
return i18n._("Correct (selected)");
|
|
38
|
+
}
|
|
39
|
+
if (crossedOut) {
|
|
40
|
+
return i18n._("Correct (but you crossed it out)");
|
|
43
41
|
}
|
|
44
|
-
return i18n._("
|
|
42
|
+
return i18n._("Correct");
|
|
43
|
+
}
|
|
44
|
+
// But, for incorrect answers, we only surface checked state,
|
|
45
|
+
// because crossing out an incorrect answer is not noteworthy.
|
|
46
|
+
if (checked) {
|
|
47
|
+
return i18n._("Incorrect (selected)");
|
|
45
48
|
}
|
|
49
|
+
return i18n._("Incorrect");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function OptionStatus(props: OptionStatusProps): React.Node {
|
|
53
|
+
const {
|
|
54
|
+
checked,
|
|
55
|
+
correct,
|
|
56
|
+
crossedOut,
|
|
57
|
+
previouslyAnswered,
|
|
58
|
+
reviewMode,
|
|
59
|
+
satStyling,
|
|
60
|
+
} = props;
|
|
46
61
|
|
|
47
|
-
|
|
48
|
-
|
|
62
|
+
// Option status is exclued for SAT
|
|
63
|
+
if (satStyling) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
49
66
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
// Option status is shown only in review mode, or for incorrectly
|
|
68
|
+
// answered items.
|
|
69
|
+
if (!reviewMode && !previouslyAnswered) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let textStyle;
|
|
74
|
+
if (correct) {
|
|
75
|
+
textStyle = styles.correct;
|
|
76
|
+
} else {
|
|
77
|
+
if (checked || previouslyAnswered) {
|
|
78
|
+
textStyle = styles.incorrectAnswered;
|
|
53
79
|
} else {
|
|
54
|
-
|
|
55
|
-
textStyle = styles.incorrectAnswered;
|
|
56
|
-
} else {
|
|
57
|
-
textStyle = styles.incorrect;
|
|
58
|
-
}
|
|
80
|
+
textStyle = styles.incorrect;
|
|
59
81
|
}
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<div className={css(styles.text, textStyle)}>
|
|
63
|
-
{this._renderText()}
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
82
|
}
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className={css(styles.text, textStyle)}>
|
|
86
|
+
{renderText(checked, correct, crossedOut)}
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
67
89
|
}
|
|
68
90
|
|
|
69
91
|
const styles = StyleSheet.create({
|