@khanacademy/perseus 1.1.2 → 1.3.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/CHANGELOG.md +23 -0
- package/dist/es/index.css +4 -5
- package/dist/es/index.js +1282 -1429
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +4 -5
- package/dist/index.js +1283 -1429
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/__tests__/__snapshots__/renderer_test.jsx.snap +21 -3
- package/src/components/highlighting/ui/highlight-tooltip.jsx +29 -23
- package/src/components/highlighting/ui/selection-tracker.jsx +17 -28
- package/src/styles/articles.less +0 -2
- package/src/styles/perseus-renderer.less +1 -1
- package/src/styles/widgets/passage.less +7 -3
- package/src/widgets/__stories__/passage-ref.stories.jsx +6 -2
- package/src/widgets/__stories__/passage.stories.jsx +9 -1
- package/src/widgets/__stories__/radio.stories.jsx +11 -0
- package/src/widgets/__testdata__/passage-ref_testdata.js +62 -0
- package/src/widgets/__testdata__/passage_testdata.js +25 -0
- package/src/widgets/__testdata__/radio_testdata.js +52 -0
- package/src/widgets/__tests__/__snapshots__/dropdown_test.jsx.snap +16 -2
- package/src/widgets/__tests__/__snapshots__/passage-ref_test.jsx.snap +18 -18
- package/src/widgets/__tests__/__snapshots__/passage_test.jsx.snap +36 -36
- package/src/widgets/__tests__/passage_test.jsx +6 -8
- package/src/widgets/__tests__/radio_test.jsx +3 -1
- package/src/widgets/passage.jsx +12 -41
- package/src/widgets/radio/widget.jsx +128 -129
- package/src/components/new-tooltip/README.md +0 -3
- package/src/components/new-tooltip/__stories__/new-tooltip.stories.jsx +0 -665
- package/src/components/new-tooltip/__tests__/style-constants_test.js +0 -8
- package/src/components/new-tooltip/new-tooltip.jsx +0 -155
- package/src/components/new-tooltip/style-constants.js +0 -13
- package/src/components/new-tooltip/types.js +0 -183
- package/src/widgets/passage/get-line-height-for-node.js +0 -9
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Core Perseus API (includes renderers and widgets)",
|
|
4
4
|
"author": "Khan Academy",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.3.0",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -35,16 +35,16 @@
|
|
|
35
35
|
"@khanacademy/wonder-blocks-color": "^1.1.20",
|
|
36
36
|
"@khanacademy/wonder-blocks-core": "^4.3.0",
|
|
37
37
|
"@khanacademy/wonder-blocks-data": "^7.0.0",
|
|
38
|
-
"@khanacademy/wonder-blocks-dropdown": "^2.
|
|
38
|
+
"@khanacademy/wonder-blocks-dropdown": "^2.10.1",
|
|
39
39
|
"@khanacademy/wonder-blocks-form": "^2.4.5",
|
|
40
40
|
"@khanacademy/wonder-blocks-i18n": "^1.2.3",
|
|
41
41
|
"@khanacademy/wonder-blocks-layout": "^1.4.9",
|
|
42
42
|
"@khanacademy/wonder-blocks-link": "^3.8.5",
|
|
43
43
|
"@khanacademy/wonder-blocks-modal": "^2.3.1",
|
|
44
|
-
"@khanacademy/wonder-blocks-popover": "^1.1.
|
|
44
|
+
"@khanacademy/wonder-blocks-popover": "^1.1.24",
|
|
45
45
|
"@khanacademy/wonder-blocks-progress-spinner": "^1.1.31",
|
|
46
46
|
"@khanacademy/wonder-blocks-spacing": "^3.0.5",
|
|
47
|
-
"@khanacademy/wonder-blocks-tooltip": "^1.
|
|
47
|
+
"@khanacademy/wonder-blocks-tooltip": "^1.4.0",
|
|
48
48
|
"@khanacademy/wonder-blocks-typography": "^1.1.31",
|
|
49
49
|
"@khanacademy/wonder-stuff-core": "^0.1.2",
|
|
50
50
|
"aphrodite": "^1.2.5",
|
|
@@ -68,16 +68,16 @@
|
|
|
68
68
|
"@khanacademy/wonder-blocks-color": "^1.1.20",
|
|
69
69
|
"@khanacademy/wonder-blocks-core": "^4.3.0",
|
|
70
70
|
"@khanacademy/wonder-blocks-data": "^7.0.0",
|
|
71
|
-
"@khanacademy/wonder-blocks-dropdown": "^2.
|
|
71
|
+
"@khanacademy/wonder-blocks-dropdown": "^2.10.1",
|
|
72
72
|
"@khanacademy/wonder-blocks-form": "^2.4.5",
|
|
73
73
|
"@khanacademy/wonder-blocks-i18n": "^1.2.3",
|
|
74
74
|
"@khanacademy/wonder-blocks-layout": "^1.4.9",
|
|
75
75
|
"@khanacademy/wonder-blocks-link": "^3.8.5",
|
|
76
76
|
"@khanacademy/wonder-blocks-modal": "^2.3.1",
|
|
77
|
-
"@khanacademy/wonder-blocks-popover": "^1.1.
|
|
77
|
+
"@khanacademy/wonder-blocks-popover": "^1.1.24",
|
|
78
78
|
"@khanacademy/wonder-blocks-progress-spinner": "^1.1.31",
|
|
79
79
|
"@khanacademy/wonder-blocks-spacing": "^3.0.5",
|
|
80
|
-
"@khanacademy/wonder-blocks-tooltip": "^1.
|
|
80
|
+
"@khanacademy/wonder-blocks-tooltip": "^1.4.0",
|
|
81
81
|
"@khanacademy/wonder-blocks-typography": "^1.1.31",
|
|
82
82
|
"@khanacademy/wonder-stuff-core": "^0.1.2",
|
|
83
83
|
"aphrodite": "^1.2.5",
|
|
@@ -385,11 +385,17 @@ exports[`renderer snapshots correct answer: correct answer 1`] = `
|
|
|
385
385
|
<div
|
|
386
386
|
class="default_xu2jcg-o_O-menuWrapper_wvrnr4"
|
|
387
387
|
>
|
|
388
|
+
<span
|
|
389
|
+
aria-atomic="true"
|
|
390
|
+
aria-live="polite"
|
|
391
|
+
aria-relevant="additions text"
|
|
392
|
+
class="srOnly_19bpjuy"
|
|
393
|
+
data-test-id="dropdown-live-region"
|
|
394
|
+
/>
|
|
388
395
|
<button
|
|
389
396
|
aria-expanded="false"
|
|
390
397
|
aria-haspopup="listbox"
|
|
391
398
|
class="button_vr44p2-o_O-shared_u51dsh-o_O-default_kjzwx1-o_O-focus_1qpi544"
|
|
392
|
-
tabindex="0"
|
|
393
399
|
type="button"
|
|
394
400
|
>
|
|
395
401
|
<span
|
|
@@ -456,11 +462,17 @@ exports[`renderer snapshots incorrect answer: incorrect answer 1`] = `
|
|
|
456
462
|
<div
|
|
457
463
|
class="default_xu2jcg-o_O-menuWrapper_wvrnr4"
|
|
458
464
|
>
|
|
465
|
+
<span
|
|
466
|
+
aria-atomic="true"
|
|
467
|
+
aria-live="polite"
|
|
468
|
+
aria-relevant="additions text"
|
|
469
|
+
class="srOnly_19bpjuy"
|
|
470
|
+
data-test-id="dropdown-live-region"
|
|
471
|
+
/>
|
|
459
472
|
<button
|
|
460
473
|
aria-expanded="false"
|
|
461
474
|
aria-haspopup="listbox"
|
|
462
475
|
class="button_vr44p2-o_O-shared_u51dsh-o_O-default_kjzwx1-o_O-focus_1qpi544"
|
|
463
|
-
tabindex="0"
|
|
464
476
|
type="button"
|
|
465
477
|
>
|
|
466
478
|
<span
|
|
@@ -527,11 +539,17 @@ exports[`renderer snapshots initial render: initial render 1`] = `
|
|
|
527
539
|
<div
|
|
528
540
|
class="default_xu2jcg-o_O-menuWrapper_wvrnr4"
|
|
529
541
|
>
|
|
542
|
+
<span
|
|
543
|
+
aria-atomic="true"
|
|
544
|
+
aria-live="polite"
|
|
545
|
+
aria-relevant="additions text"
|
|
546
|
+
class="srOnly_19bpjuy"
|
|
547
|
+
data-test-id="dropdown-live-region"
|
|
548
|
+
/>
|
|
530
549
|
<button
|
|
531
550
|
aria-expanded="false"
|
|
532
551
|
aria-haspopup="listbox"
|
|
533
552
|
class="button_vr44p2-o_O-shared_u51dsh-o_O-default_kjzwx1"
|
|
534
|
-
tabindex="0"
|
|
535
553
|
type="button"
|
|
536
554
|
>
|
|
537
555
|
<span
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
* still have to notify the tooltip to remeasure itself when the highlight
|
|
14
14
|
* focus _changes_.
|
|
15
15
|
*/
|
|
16
|
+
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
17
|
+
import Tooltip from "@khanacademy/wonder-blocks-tooltip";
|
|
16
18
|
import {StyleSheet, css} from "aphrodite";
|
|
17
19
|
import * as React from "react";
|
|
18
20
|
|
|
19
21
|
import {Log} from "../../../logging/log.js";
|
|
20
|
-
import {colors} from "../../../styles/global-styles.js";
|
|
21
|
-
import NewTooltip from "../../new-tooltip/new-tooltip.jsx";
|
|
22
22
|
|
|
23
23
|
import {getRelativeRect} from "./util.js";
|
|
24
24
|
|
|
@@ -36,8 +36,6 @@ type HighlightTooltipProps = {|
|
|
|
36
36
|
|};
|
|
37
37
|
|
|
38
38
|
class HighlightTooltip extends React.PureComponent<HighlightTooltipProps> {
|
|
39
|
-
_tooltip: ?React.ElementRef<typeof NewTooltip>;
|
|
40
|
-
|
|
41
39
|
_getFocusRect(): ?Rect {
|
|
42
40
|
const {focusNode, focusOffset, offsetParent} = this.props;
|
|
43
41
|
|
|
@@ -94,31 +92,36 @@ class HighlightTooltip extends React.PureComponent<HighlightTooltipProps> {
|
|
|
94
92
|
return null;
|
|
95
93
|
}
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
// using div instead of TooltipContent because
|
|
96
|
+
// TooltipContent wouldn't let me overwrite
|
|
97
|
+
// user-select and onClick
|
|
98
|
+
const content: $FlowFixMe = (
|
|
99
|
+
<div
|
|
100
|
+
className={css(styles.tooltipLabel)}
|
|
101
|
+
onClick={this.props.onClick}
|
|
102
|
+
>
|
|
103
|
+
{this.props.label}
|
|
104
|
+
</div>
|
|
99
105
|
);
|
|
100
106
|
|
|
107
|
+
const style = {
|
|
108
|
+
position: "absolute",
|
|
109
|
+
left: focusRect.left,
|
|
110
|
+
// offset the spacing WB provides around tooltips
|
|
111
|
+
top: `calc(${Math.round(focusRect.top)}px + 0.95em)`,
|
|
112
|
+
height: 0,
|
|
113
|
+
};
|
|
114
|
+
|
|
101
115
|
return (
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
color={colors.kaBlue}
|
|
105
|
-
inverted={true}
|
|
106
|
-
onClick={this.props.onClick}
|
|
116
|
+
<div
|
|
117
|
+
style={style}
|
|
107
118
|
onMouseEnter={this.props.onMouseEnter}
|
|
108
119
|
onMouseLeave={this.props.onMouseLeave}
|
|
109
|
-
toggleOnHover={false}
|
|
110
|
-
showOnMount={true}
|
|
111
|
-
ref={(e) => (this._tooltip = e)}
|
|
112
120
|
>
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
top: focusRect.top,
|
|
118
|
-
height: focusRect.height,
|
|
119
|
-
}}
|
|
120
|
-
/>
|
|
121
|
-
</NewTooltip>
|
|
121
|
+
<Tooltip content={content} opened={true}>
|
|
122
|
+
<div />
|
|
123
|
+
</Tooltip>
|
|
124
|
+
</div>
|
|
122
125
|
);
|
|
123
126
|
}
|
|
124
127
|
}
|
|
@@ -131,6 +134,9 @@ const styles = StyleSheet.create({
|
|
|
131
134
|
// we lose our reference to the _actual_ text they want to highlight,
|
|
132
135
|
// and the "Add highlight" action fails.
|
|
133
136
|
userSelect: "none",
|
|
137
|
+
fontFamily: `"Lato", sans-serif`,
|
|
138
|
+
padding: `10px ${Spacing.medium_16}px`,
|
|
139
|
+
cursor: "pointer",
|
|
134
140
|
},
|
|
135
141
|
});
|
|
136
142
|
|
|
@@ -24,7 +24,7 @@ export type TrackedSelection = {|
|
|
|
24
24
|
proposedHighlight: DOMHighlight,
|
|
25
25
|
|};
|
|
26
26
|
|
|
27
|
-
type SelectionTrackerProps = {
|
|
27
|
+
type SelectionTrackerProps = {|
|
|
28
28
|
// A function that builds a DOMHighlight from the given DOMRange, if
|
|
29
29
|
// possible. If it would not currently be valid to add a highlight over the
|
|
30
30
|
// given DOMRange, returns null.
|
|
@@ -38,17 +38,15 @@ type SelectionTrackerProps = {
|
|
|
38
38
|
) => React.Element<any>,
|
|
39
39
|
// If false, will not track selections.
|
|
40
40
|
enabled: boolean,
|
|
41
|
-
|
|
42
|
-
};
|
|
41
|
+
|};
|
|
43
42
|
|
|
44
|
-
type SelectionTrackerState = {
|
|
43
|
+
type SelectionTrackerState = {|
|
|
45
44
|
// The current state of the mouse button. We distinguish between down,
|
|
46
45
|
// down and the selection has changed since going down, and up.
|
|
47
46
|
mouseState: "down" | "down-and-selecting" | "up",
|
|
48
47
|
// The current TrackedSelection, if any.
|
|
49
48
|
trackedSelection: ?TrackedSelection,
|
|
50
|
-
|
|
51
|
-
};
|
|
49
|
+
|};
|
|
52
50
|
|
|
53
51
|
class SelectionTracker extends React.PureComponent<
|
|
54
52
|
SelectionTrackerProps,
|
|
@@ -63,15 +61,15 @@ class SelectionTracker extends React.PureComponent<
|
|
|
63
61
|
this._updateListeners(false, this.props.enabled);
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
if (this.props.buildHighlight !==
|
|
64
|
+
componentDidUpdate(prevProps: SelectionTrackerProps) {
|
|
65
|
+
if (this.props.buildHighlight !== prevProps.buildHighlight) {
|
|
68
66
|
// The highlight-building function changed, so the
|
|
69
67
|
// proposedHighlight we built with it might be different, or no
|
|
70
68
|
// longer be valid. Update accordingly.
|
|
71
|
-
this._updateTrackedSelection(
|
|
69
|
+
this._updateTrackedSelection();
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
this._updateListeners(
|
|
72
|
+
this._updateListeners(prevProps.enabled, this.props.enabled);
|
|
75
73
|
}
|
|
76
74
|
|
|
77
75
|
componentWillUnmount() {
|
|
@@ -133,37 +131,28 @@ class SelectionTracker extends React.PureComponent<
|
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
/**
|
|
136
|
-
* Compute the
|
|
134
|
+
* Compute and update the TrackedSelection to reflect the document state.
|
|
137
135
|
*/
|
|
138
|
-
|
|
139
|
-
buildHighlight: (domRange: DOMRange) => ?DOMHighlight,
|
|
140
|
-
): ?TrackedSelection {
|
|
136
|
+
_updateTrackedSelection(): void {
|
|
141
137
|
const focusAndRange = this._computeFocusAndRange();
|
|
142
138
|
if (!focusAndRange) {
|
|
143
|
-
|
|
139
|
+
this.setState({trackedSelection: null});
|
|
140
|
+
return;
|
|
144
141
|
}
|
|
145
142
|
|
|
146
143
|
const {focusNode, focusOffset, range} = focusAndRange;
|
|
147
|
-
const proposedHighlight = buildHighlight(range);
|
|
144
|
+
const proposedHighlight = this.props.buildHighlight(range);
|
|
148
145
|
if (!proposedHighlight) {
|
|
149
|
-
|
|
146
|
+
this.setState({trackedSelection: null});
|
|
147
|
+
return;
|
|
150
148
|
}
|
|
151
149
|
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Update the TrackedSelection to reflect the document state.
|
|
157
|
-
*/
|
|
158
|
-
_updateTrackedSelection(
|
|
159
|
-
buildHighlight: (domRange: DOMRange) => ?DOMHighlight,
|
|
160
|
-
) {
|
|
161
|
-
const trackedSelection = this._computeTrackedSelection(buildHighlight);
|
|
150
|
+
const trackedSelection = {focusNode, focusOffset, proposedHighlight};
|
|
162
151
|
this.setState({trackedSelection});
|
|
163
152
|
}
|
|
164
153
|
|
|
165
154
|
_handleSelectionChange: () => void = () => {
|
|
166
|
-
this._updateTrackedSelection(
|
|
155
|
+
this._updateTrackedSelection();
|
|
167
156
|
|
|
168
157
|
if (this.state.mouseState === "down") {
|
|
169
158
|
this.setState({
|
package/src/styles/articles.less
CHANGED
|
@@ -45,12 +45,16 @@
|
|
|
45
45
|
|
|
46
46
|
margin: 0 0 10px;
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
// note(matthewc): If you need to change any of this,
|
|
50
|
+
// check that line numbers line up correctly.
|
|
51
|
+
// The margin should probably be 0 or the line height
|
|
48
52
|
.passage-text div.paragraph {
|
|
49
|
-
font-family: "Noto Serif", serif;
|
|
50
53
|
font-weight: 400;
|
|
51
|
-
font-size:
|
|
52
|
-
line-height:
|
|
54
|
+
font-size: @font-size;
|
|
55
|
+
line-height: @line-height;
|
|
53
56
|
text-indent: 20px;
|
|
57
|
+
margin: 0;
|
|
54
58
|
|
|
55
59
|
span {
|
|
56
60
|
text-indent: 0;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
|
|
4
4
|
import {RendererWithDebugUI} from "../../../../../testing/renderer-with-debug-ui.jsx";
|
|
5
|
-
import {question1} from "../__testdata__/passage-ref_testdata.js";
|
|
5
|
+
import {question1, question2} from "../__testdata__/passage-ref_testdata.js";
|
|
6
6
|
|
|
7
7
|
type StoryArgs = {||};
|
|
8
8
|
|
|
@@ -14,6 +14,10 @@ export default ({
|
|
|
14
14
|
title: "Perseus/Widgets/PassageRef",
|
|
15
15
|
}: Story);
|
|
16
16
|
|
|
17
|
-
export const
|
|
17
|
+
export const ShortPassage = (args: StoryArgs): React.Node => {
|
|
18
18
|
return <RendererWithDebugUI question={question1} />;
|
|
19
19
|
};
|
|
20
|
+
|
|
21
|
+
export const LongPassage = (args: StoryArgs): React.Node => {
|
|
22
|
+
return <RendererWithDebugUI question={question2} />;
|
|
23
|
+
};
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
|
|
4
4
|
import {RendererWithDebugUI} from "../../../../../testing/renderer-with-debug-ui.jsx";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
question1,
|
|
7
|
+
question2,
|
|
8
|
+
question3,
|
|
9
|
+
} from "../__testdata__/passage_testdata.js";
|
|
6
10
|
|
|
7
11
|
export default {
|
|
8
12
|
title: "Perseus/Widgets/Passage",
|
|
@@ -17,3 +21,7 @@ export const SimpleQuestion = (args: StoryArgs): React.Node => {
|
|
|
17
21
|
export const MultiPassageQuestion = (args: StoryArgs): React.Node => {
|
|
18
22
|
return <RendererWithDebugUI question={question2} />;
|
|
19
23
|
};
|
|
24
|
+
|
|
25
|
+
export const SingleNumberedPassage = (args: StoryArgs): React.Node => {
|
|
26
|
+
return <RendererWithDebugUI question={question3} />;
|
|
27
|
+
};
|
|
@@ -6,6 +6,7 @@ import {RendererWithDebugUI} from "../../../../../testing/renderer-with-debug-ui
|
|
|
6
6
|
import {
|
|
7
7
|
questionWithPassage,
|
|
8
8
|
multiChoiceQuestion,
|
|
9
|
+
multiChoiceQuestionSimple,
|
|
9
10
|
} from "../__testdata__/radio_testdata.js";
|
|
10
11
|
|
|
11
12
|
import type {PerseusRenderer} from "../../perseus-types.js";
|
|
@@ -71,6 +72,16 @@ export const SingleSelect = (args: StoryArgs): React.Node => {
|
|
|
71
72
|
);
|
|
72
73
|
};
|
|
73
74
|
|
|
75
|
+
export const MultiSelectSimple = (args: StoryArgs): React.Node => {
|
|
76
|
+
return (
|
|
77
|
+
<RendererWithDebugUI
|
|
78
|
+
question={applyStoryArgs(multiChoiceQuestionSimple, args)}
|
|
79
|
+
apiOptions={buildApiOptions(args)}
|
|
80
|
+
reviewMode={args.reviewMode}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
74
85
|
export const MultiSelect = (args: StoryArgs): React.Node => {
|
|
75
86
|
return (
|
|
76
87
|
<RendererWithDebugUI
|
|
@@ -39,3 +39,65 @@ export const question1: PerseusRenderer = {
|
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
};
|
|
42
|
+
|
|
43
|
+
export const question2: PerseusRenderer = {
|
|
44
|
+
content:
|
|
45
|
+
'[[☃ passage 1]]\n\n"It is!" is used in [[☃ passage-ref 1]]\n\n"unsettle" is used in [[☃ passage-ref 2]]\n\n"flagon" is used in [[☃ passage-ref 3]]\n\n',
|
|
46
|
+
images: {},
|
|
47
|
+
widgets: {
|
|
48
|
+
"passage 1": {
|
|
49
|
+
alignment: "default",
|
|
50
|
+
graded: true,
|
|
51
|
+
options: {
|
|
52
|
+
footnotes: "",
|
|
53
|
+
passageText:
|
|
54
|
+
'\n\nOne afternoon, Mrs. Bretton, coaxing [Paulina] from her usual station in a corner, had lifted her into the window-seat, and, by way of occupying her attention, told her to watch the passengers and count how many ladies should go down the street in a given time. She had sat listlessly, hardly looking, and not counting, when—my eye being fixed on hers—I witnessed in its iris and pupil a startling transfiguration. These sudden, dangerous natures—*sensitive* as they are called—offer many a curious spectacle to those whom a cooler temperament has secured from participation in their angular vagaries. The fixed and heavy gaze swum, trembled, then glittered in fire; the small, overcast brow cleared; the trivial and dejected features lit up; the sad countenance vanished, and in its place appeared a sudden eagerness, an intense expectancy. {{"It *is!*"}} were her words.\n\nLike a bird or a shaft, or any other swift thing, she was gone from the room. How she got the house-door open I cannot tell; probably it might be ajar; perhaps Warren was in the way and obeyed her behest, which would be impetuous enough. I—watching calmly from the window—saw her, in her black frock and tiny braided apron (to pinafores she had an antipathy), dart half the length of the street; and, as I was on the point of turning, and quietly announcing to Mrs. Bretton that the child was run out mad, and ought instantly to be pursued, I saw her caught up, and rapt at once from my cool observation, and from the wondering stare of the passengers. A gentleman had done this good turn, and now, covering her with his cloak, advanced to restore her to the house whence he had seen her issue.\n\nI concluded he would leave her in a servant\'s charge and withdraw; but he entered: having tarried a little while below, he came up-stairs.\n\nHis reception immediately explained that he was known to Mrs. Bretton. She recognised him; she greeted him, and yet she was fluttered, surprised, taken unawares. Her look and manner were even expostulatory; and in reply to these, rather than her words, he said,—"I could not help it, madam: I found it impossible to leave the country without seeing with my own eyes how she settled."\n\n"But you will {{unsettle}} her."\n\n"I hope not. And how is papa\'s little Polly?"\n\nThis question he addressed to Paulina, as he sat down and placed her gently on the ground before him.\n\n"How is Polly\'s papa?" was the reply, as she leaned on his knee, and gazed up into his face.\n\nIt was not a noisy, not a wordy scene: for that I was thankful; but it was a scene of feeling too brimful, and which, because the cup did not foam up high or furiously overflow, only oppressed one the more. On all occasions of vehement, unrestrained expansion, a sense of disdain or ridicule comes to the weary spectator\'s relief; whereas I have ever felt most burdensome that sort of sensibility which bends of its own will, a giant slave under the sway of good sense.\n\nMr. Home was a stern-featured—perhaps I should rather say, a hard-featured man: his forehead was knotty, and his cheekbones were marked and prominent. The character of his face was quite Scotch; but there was feeling in his eye, and emotion in his now agitated countenance. His northern accent in speaking harmonised with his physiognomy. He was at once proud-looking and homely-looking. He laid his hand on the child\'s uplifted head. She said—"Kiss Polly."\n\nHe kissed her. I wished she would utter some hysterical cry, so that I might get relief and be at ease. She made wonderfully little noise: she seemed to have got what she wanted—all she wanted, and to be in a trance of content. Neither in mien nor in features was this creature like her sire, and yet she was of his strain: her mind had been filled from his, as the cup from the {{flagon}}.\n',
|
|
55
|
+
passageTitle: "",
|
|
56
|
+
showLineNumbers: true,
|
|
57
|
+
static: false,
|
|
58
|
+
},
|
|
59
|
+
static: false,
|
|
60
|
+
type: "passage",
|
|
61
|
+
version: {
|
|
62
|
+
major: 0,
|
|
63
|
+
minor: 0,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
"passage-ref 1": {
|
|
67
|
+
options: {
|
|
68
|
+
passageNumber: 1,
|
|
69
|
+
referenceNumber: 1,
|
|
70
|
+
summaryText: "",
|
|
71
|
+
},
|
|
72
|
+
type: "passage-ref",
|
|
73
|
+
version: {
|
|
74
|
+
major: 0,
|
|
75
|
+
minor: 1,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
"passage-ref 2": {
|
|
79
|
+
options: {
|
|
80
|
+
passageNumber: 1,
|
|
81
|
+
referenceNumber: 2,
|
|
82
|
+
summaryText: "",
|
|
83
|
+
},
|
|
84
|
+
type: "passage-ref",
|
|
85
|
+
version: {
|
|
86
|
+
major: 0,
|
|
87
|
+
minor: 1,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
"passage-ref 3": {
|
|
91
|
+
options: {
|
|
92
|
+
passageNumber: 1,
|
|
93
|
+
referenceNumber: 3,
|
|
94
|
+
summaryText: "",
|
|
95
|
+
},
|
|
96
|
+
type: "passage-ref",
|
|
97
|
+
version: {
|
|
98
|
+
major: 0,
|
|
99
|
+
minor: 1,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
@@ -69,3 +69,28 @@ export const question2: PerseusRenderer = {
|
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
71
|
};
|
|
72
|
+
|
|
73
|
+
export const question3: PerseusRenderer = {
|
|
74
|
+
content: "[[☃ passage 1]]",
|
|
75
|
+
images: {},
|
|
76
|
+
widgets: {
|
|
77
|
+
"passage 1": {
|
|
78
|
+
alignment: "default",
|
|
79
|
+
graded: true,
|
|
80
|
+
options: {
|
|
81
|
+
footnotes: "An example footnote",
|
|
82
|
+
passageText:
|
|
83
|
+
"{{For reasons that are not entirely clear, when animals make their way to isolated islands [[1]], they tend to evolve relatively quickly toward an outsized or pint-sized version of their mainland counterpart.}} \n\n{{Perhaps the most famous example of an island giant—and, sadly, of species extinction—is the dodo, once found on the Indian Ocean island of Mauritius.}} {{When the dodo's ancestor (thought to be a migratory pigeon) settled on this island with abundant food, no competition from terrestrial mammals, and no predators, it could survive without flying, and thus was freed from the energetic and size constraints of flight.}} {{New Zealand also had avian giants, now extinct, including the flightless moa, an ostrich-like bird, and Haast's eagle (_Harpagornis moorei_), which had a wingspan up to 3 meters.}} {{Though Haast's eagle could fly—and presumably used its wings to {{launch}} brutal attacks on the hapless moa—its body mass (10–14 kilograms) pushed the limits for self-propelled flight.}}\n\n{{As extreme evolutionary examples, these island birds can offer insights into the forces and events shaping evolutionary change.}} In a new study, Michael Bunce et al. compared ancient mitochondrial DNA extracted from Haast's eagle bones with DNA sequences of 16 living eagle species to better characterize the evolutionary history of the extinct giant raptor. {{Their results suggest the extinct raptor underwent a rapid evolutionary transformation that belies its kinship to some of the world's smallest eagle species.}}\n\nThe authors characterized the rates of sequence evolution within mitochondrial DNA to establish the evolutionary relationships between the different eagle species. Their analysis places Haast's eagle in the same evolutionary lineage as a group of small eagle species in the genus _Hieraaetus_. Surprisingly, the genetic distance separating the giant eagle and its more diminutive _Hieraaetus_ cousins from their last {{common}} ancestor is relatively small.\n",
|
|
84
|
+
passageTitle: "Passage 1",
|
|
85
|
+
showLineNumbers: true,
|
|
86
|
+
static: false,
|
|
87
|
+
},
|
|
88
|
+
static: false,
|
|
89
|
+
type: "passage",
|
|
90
|
+
version: {
|
|
91
|
+
major: 0,
|
|
92
|
+
minor: 0,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -194,6 +194,58 @@ export const multiChoiceQuestion: PerseusRenderer = {
|
|
|
194
194
|
},
|
|
195
195
|
};
|
|
196
196
|
|
|
197
|
+
export const multiChoiceQuestionSimple: PerseusRenderer = {
|
|
198
|
+
content: "What are some ways to say hello?\n\n[[\u2603 radio 1]]",
|
|
199
|
+
images: {},
|
|
200
|
+
widgets: {
|
|
201
|
+
"radio 1": ({
|
|
202
|
+
graded: true,
|
|
203
|
+
version: {
|
|
204
|
+
major: 1,
|
|
205
|
+
minor: 0,
|
|
206
|
+
},
|
|
207
|
+
static: false,
|
|
208
|
+
type: "radio",
|
|
209
|
+
options: {
|
|
210
|
+
onePerLine: true,
|
|
211
|
+
displayCount: null,
|
|
212
|
+
choices: [
|
|
213
|
+
{
|
|
214
|
+
content: "Hola",
|
|
215
|
+
isNoneOfTheAbove: false,
|
|
216
|
+
correct: true,
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
content: "Hey",
|
|
220
|
+
isNoneOfTheAbove: false,
|
|
221
|
+
correct: true,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
content: "Hi",
|
|
225
|
+
isNoneOfTheAbove: false,
|
|
226
|
+
correct: true,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
content: "Goodbye",
|
|
230
|
+
isNoneOfTheAbove: false,
|
|
231
|
+
correct: false,
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
content: "None of these",
|
|
235
|
+
isNoneOfTheAbove: true,
|
|
236
|
+
correct: false,
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
hasNoneOfTheAbove: true,
|
|
240
|
+
multipleSelect: true,
|
|
241
|
+
randomize: false,
|
|
242
|
+
deselectEnabled: false,
|
|
243
|
+
},
|
|
244
|
+
alignment: "default",
|
|
245
|
+
}: RadioWidget),
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
|
|
197
249
|
export const multiChoiceQuestionAndAnswer: [
|
|
198
250
|
PerseusRenderer,
|
|
199
251
|
$ReadOnlyArray<number>,
|
|
@@ -23,11 +23,19 @@ exports[`Dropdown widget should snapshot when opened: dropdown open 1`] = `
|
|
|
23
23
|
<div
|
|
24
24
|
class="default_xu2jcg-o_O-menuWrapper_wvrnr4"
|
|
25
25
|
>
|
|
26
|
+
<span
|
|
27
|
+
aria-atomic="true"
|
|
28
|
+
aria-live="polite"
|
|
29
|
+
aria-relevant="additions text"
|
|
30
|
+
class="srOnly_19bpjuy"
|
|
31
|
+
data-test-id="dropdown-live-region"
|
|
32
|
+
>
|
|
33
|
+
3 items
|
|
34
|
+
</span>
|
|
26
35
|
<button
|
|
27
36
|
aria-expanded="true"
|
|
28
37
|
aria-haspopup="listbox"
|
|
29
38
|
class="button_vr44p2-o_O-shared_u51dsh-o_O-default_kjzwx1-o_O-focus_1qpi544"
|
|
30
|
-
tabindex="0"
|
|
31
39
|
type="button"
|
|
32
40
|
>
|
|
33
41
|
<span
|
|
@@ -94,11 +102,17 @@ exports[`Dropdown widget should snapshot: initial render 1`] = `
|
|
|
94
102
|
<div
|
|
95
103
|
class="default_xu2jcg-o_O-menuWrapper_wvrnr4"
|
|
96
104
|
>
|
|
105
|
+
<span
|
|
106
|
+
aria-atomic="true"
|
|
107
|
+
aria-live="polite"
|
|
108
|
+
aria-relevant="additions text"
|
|
109
|
+
class="srOnly_19bpjuy"
|
|
110
|
+
data-test-id="dropdown-live-region"
|
|
111
|
+
/>
|
|
97
112
|
<button
|
|
98
113
|
aria-expanded="false"
|
|
99
114
|
aria-haspopup="listbox"
|
|
100
115
|
class="button_vr44p2-o_O-shared_u51dsh-o_O-default_kjzwx1"
|
|
101
|
-
tabindex="0"
|
|
102
116
|
type="button"
|
|
103
117
|
>
|
|
104
118
|
<span
|
|
@@ -55,13 +55,13 @@ exports[`passage-ref widget should render with invalid reference 1`] = `
|
|
|
55
55
|
<div>
|
|
56
56
|
<div>
|
|
57
57
|
<div
|
|
58
|
-
|
|
58
|
+
aria-hidden="true"
|
|
59
|
+
class="measurer_225hir"
|
|
59
60
|
>
|
|
60
|
-
<div
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<div />
|
|
61
|
+
<div
|
|
62
|
+
class="paragraph"
|
|
63
|
+
>
|
|
64
|
+
Line Height Measurement
|
|
65
65
|
</div>
|
|
66
66
|
</div>
|
|
67
67
|
<div
|
|
@@ -200,13 +200,13 @@ exports[`passage-ref widget should render with multi-line reference 1`] = `
|
|
|
200
200
|
<div>
|
|
201
201
|
<div>
|
|
202
202
|
<div
|
|
203
|
-
|
|
203
|
+
aria-hidden="true"
|
|
204
|
+
class="measurer_225hir"
|
|
204
205
|
>
|
|
205
|
-
<div
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<div />
|
|
206
|
+
<div
|
|
207
|
+
class="paragraph"
|
|
208
|
+
>
|
|
209
|
+
Line Height Measurement
|
|
210
210
|
</div>
|
|
211
211
|
</div>
|
|
212
212
|
<div
|
|
@@ -350,13 +350,13 @@ exports[`passage-ref widget should render with single-line reference 1`] = `
|
|
|
350
350
|
<div>
|
|
351
351
|
<div>
|
|
352
352
|
<div
|
|
353
|
-
|
|
353
|
+
aria-hidden="true"
|
|
354
|
+
class="measurer_225hir"
|
|
354
355
|
>
|
|
355
|
-
<div
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
<div />
|
|
356
|
+
<div
|
|
357
|
+
class="paragraph"
|
|
358
|
+
>
|
|
359
|
+
Line Height Measurement
|
|
360
360
|
</div>
|
|
361
361
|
</div>
|
|
362
362
|
<div
|