@khanacademy/perseus 12.2.0 → 12.4.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 +42 -0
- package/dist/article-renderer.d.ts +3 -2
- package/dist/error-boundary.d.ts +1 -0
- package/dist/es/index.css +4 -69
- package/dist/es/index.js +135 -78
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +4 -69
- package/dist/index.js +130 -67
- package/dist/index.js.map +1 -1
- package/dist/renderer.d.ts +4 -1
- package/dist/styles/constants.d.ts +2 -2
- package/dist/widget-container.d.ts +2 -0
- package/dist/widgets/expression.d.ts +5 -4
- package/package.json +8 -8
- package/src/__tests__/renderer-api.test.tsx +18 -23
- package/src/__tests__/widget-container.test.tsx +126 -0
- package/src/article-renderer.tsx +15 -13
- package/src/error-boundary.tsx +4 -0
- package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +5 -5
- package/src/renderer.tsx +29 -27
- package/src/server-item-renderer.tsx +1 -0
- package/src/styles/articles.less +3 -1
- package/src/styles/constants.ts +4 -4
- package/src/styles/perseus-renderer.less +1 -11
- package/src/styles/variables.less +2 -2
- package/src/styles/variables.shared.less +2 -2
- package/src/styles/widgets/expression.less +0 -77
- package/src/styles/widgets/passage.less +1 -19
- package/src/widget-container.tsx +33 -10
- package/src/widgets/__stories__/label-image.stories.tsx +30 -0
- package/src/widgets/__testdata__/label-image.testdata.ts +63 -0
- package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +50 -19
- package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +5 -5
- package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +28 -28
- package/src/widgets/__tests__/expression.test.tsx +12 -9
- package/src/widgets/__tests__/renderQuestion.tsx +30 -13
- package/src/widgets/expression.tsx +19 -25
- package/src/widgets/graded-group-set.tsx +70 -25
- package/src/widgets/transformer.tsx +1 -2
- package/tsconfig-build.tsbuildinfo +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Steal from webapp/stylesheets/shared-package/variables.less
|
|
2
|
-
@baseFontFamily: "
|
|
3
|
-
@boldFontFamily: "
|
|
2
|
+
@baseFontFamily: "Lato", sans-serif;
|
|
3
|
+
@boldFontFamily: "Lato-Bold", "Lato", sans-serif;
|
|
4
4
|
@green: #76a005;
|
|
5
5
|
@kaGreen: #71b307;
|
|
6
6
|
@blue: #1c758a;
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
|
|
87
87
|
// Typography
|
|
88
88
|
@baseFontSize: 14px;
|
|
89
|
-
// The body of the page is setup to use 'Helvetica' by default and
|
|
90
|
-
//
|
|
89
|
+
// The body of the page is setup to use 'Helvetica' by default and
|
|
90
|
+
// 'Lato' if/once it downloads.
|
|
91
91
|
// For your elements to follow this pattern, all you need is to make the text
|
|
92
92
|
// in your element inherit from the body using the "inherit" value.
|
|
93
93
|
@baseFontFamily: inherit;
|
|
@@ -63,80 +63,3 @@
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
// Old expression widget
|
|
68
|
-
.perseus-widget-expression-old {
|
|
69
|
-
&,
|
|
70
|
-
> .output,
|
|
71
|
-
> .output > .tex,
|
|
72
|
-
> .output > .placeholder {
|
|
73
|
-
display: block;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.perseus-widget-expression-old input,
|
|
78
|
-
#answer_area .perseus-widget-expression-old input {
|
|
79
|
-
direction: ltr;
|
|
80
|
-
border: 1px solid #a4a4a4;
|
|
81
|
-
border-radius: 5px;
|
|
82
|
-
box-sizing: border-box;
|
|
83
|
-
font-size: 14px;
|
|
84
|
-
margin-bottom: 5px;
|
|
85
|
-
max-width: 240px;
|
|
86
|
-
padding: 6px;
|
|
87
|
-
width: 100%;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.perseus-widget-expression-old > .output {
|
|
91
|
-
background: #f2f2f2;
|
|
92
|
-
border-radius: 5px;
|
|
93
|
-
padding: 10px;
|
|
94
|
-
margin: 10px 0;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
#answer_area .perseus-widget-expression-old > .output {
|
|
98
|
-
background: #f7f7f7;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.perseus-widget-expression-old > .output > .tex {
|
|
102
|
-
overflow-x: auto;
|
|
103
|
-
padding: 5px;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.perseus-widget-expression-old > .output > .placeholder {
|
|
107
|
-
position: relative;
|
|
108
|
-
height: 40px;
|
|
109
|
-
overflow-y: hidden;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.perseus-widget-expression-old > .output > .placeholder > .error {
|
|
113
|
-
border-radius: 10px;
|
|
114
|
-
background: #f7f7f7;
|
|
115
|
-
border: 1px solid #ddd;
|
|
116
|
-
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
|
|
117
|
-
color: #000;
|
|
118
|
-
display: none;
|
|
119
|
-
font-weight: normal;
|
|
120
|
-
min-height: 22px;
|
|
121
|
-
width: 168px;
|
|
122
|
-
position: absolute;
|
|
123
|
-
top: 0px;
|
|
124
|
-
left: 40px;
|
|
125
|
-
margin: auto;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.perseus-widget-expression-old > .output > .placeholder > .error > .buddy {
|
|
129
|
-
background-image: url(/images/perseus/error-buddy.png);
|
|
130
|
-
background-size: 100%;
|
|
131
|
-
height: 36px;
|
|
132
|
-
width: 40px;
|
|
133
|
-
position: absolute;
|
|
134
|
-
top: -3px;
|
|
135
|
-
left: -42px;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.perseus-widget-expression-old > .output > .placeholder > .error > .message {
|
|
139
|
-
font: 12px @baseFontFamily;
|
|
140
|
-
line-height: 1.4em;
|
|
141
|
-
margin: 0px 4px;
|
|
142
|
-
}
|
|
@@ -17,26 +17,8 @@
|
|
|
17
17
|
margin: 22px;
|
|
18
18
|
position: relative;
|
|
19
19
|
|
|
20
|
-
// Use the "Minion Pro" font, if available. If not, fall back to
|
|
21
|
-
// KaTeX_Main or another serif font.
|
|
22
|
-
//
|
|
23
|
-
// NOTE(mdr): Minion Pro is only loaded on SAT and GTP pages, because
|
|
24
|
-
// those are the main call sites for the passage widget. We
|
|
25
|
-
// considered inserting the relevant stylesheet whenever the
|
|
26
|
-
// passage widget loads, but this approach produced a "flash of
|
|
27
|
-
// unstyled text", so we decided to embed the stylesheet into the
|
|
28
|
-
// relevant page templates instead.
|
|
29
|
-
//
|
|
30
|
-
// NOTE(mdr): Minion Pro will not be available on ZNDs, due to
|
|
31
|
-
// restrictions in our Adobe TypeKit configuration.
|
|
32
|
-
//
|
|
33
|
-
// TODO(mdr): The BodySerif component will hopefully soon use Minion
|
|
34
|
-
// Pro by default (WB-399). Once that happens, we should be able to
|
|
35
|
-
// switch to the BodySerif component (TP-3112), and remove this
|
|
36
|
-
// special font-family rule.
|
|
37
20
|
div.paragraph {
|
|
38
|
-
font-family:
|
|
39
|
-
serif;
|
|
21
|
+
font-family: KaTeX_Main, Times, "Times New Roman", serif;
|
|
40
22
|
}
|
|
41
23
|
|
|
42
24
|
.passage-title div.paragraph {
|
package/src/widget-container.tsx
CHANGED
|
@@ -4,6 +4,8 @@ import classNames from "classnames";
|
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import ReactDOM from "react-dom";
|
|
6
6
|
|
|
7
|
+
import {DependenciesContext} from "./dependencies";
|
|
8
|
+
import ErrorBoundary from "./error-boundary";
|
|
7
9
|
import {zIndexInteractiveComponent} from "./styles/constants";
|
|
8
10
|
import {containerSizeClass, getClassFromWidth} from "./util/sizing-utils";
|
|
9
11
|
import * as Widgets from "./widgets";
|
|
@@ -15,6 +17,7 @@ import type {LinterContextProps} from "@khanacademy/perseus-linter";
|
|
|
15
17
|
type Props = {
|
|
16
18
|
shouldHighlight: boolean;
|
|
17
19
|
type: string; // widget type/name,
|
|
20
|
+
id: string; // widget id
|
|
18
21
|
initialProps: WidgetProps<any, PerseusWidgetOptions>;
|
|
19
22
|
linterContext: LinterContextProps;
|
|
20
23
|
};
|
|
@@ -29,6 +32,8 @@ type State = {
|
|
|
29
32
|
};
|
|
30
33
|
|
|
31
34
|
class WidgetContainer extends React.Component<Props, State> {
|
|
35
|
+
widgetRef = React.createRef<React.ComponentType<any>>();
|
|
36
|
+
|
|
32
37
|
static defaultProps: DefaultProps = {
|
|
33
38
|
linterContext: linterContextDefault,
|
|
34
39
|
};
|
|
@@ -132,14 +137,33 @@ class WidgetContainer extends React.Component<Props, State> {
|
|
|
132
137
|
className={className}
|
|
133
138
|
style={isStatic ? staticContainerStyles : {}}
|
|
134
139
|
>
|
|
135
|
-
<
|
|
136
|
-
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
<DependenciesContext.Consumer>
|
|
141
|
+
{({analytics}) => (
|
|
142
|
+
<ErrorBoundary
|
|
143
|
+
metadata={{
|
|
144
|
+
widget_type: type,
|
|
145
|
+
widget_id: this.props.id,
|
|
146
|
+
}}
|
|
147
|
+
onError={() => {
|
|
148
|
+
analytics.onAnalyticsEvent({
|
|
149
|
+
type: "perseus:widget-rendering-error",
|
|
150
|
+
payload: {
|
|
151
|
+
widgetType: type,
|
|
152
|
+
widgetId: this.props.id,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
<WidgetType
|
|
158
|
+
{...this.state.widgetProps}
|
|
159
|
+
linterContext={linterContext}
|
|
160
|
+
containerSizeClass={this.state.sizeClass}
|
|
161
|
+
ref={this.widgetRef}
|
|
162
|
+
/>
|
|
163
|
+
{isStatic && <div style={staticOverlayStyles} />}
|
|
164
|
+
</ErrorBoundary>
|
|
165
|
+
)}
|
|
166
|
+
</DependenciesContext.Consumer>
|
|
143
167
|
</div>
|
|
144
168
|
);
|
|
145
169
|
}
|
|
@@ -163,8 +187,7 @@ class WidgetContainer extends React.Component<Props, State> {
|
|
|
163
187
|
}
|
|
164
188
|
|
|
165
189
|
getWidget: () => any = () => {
|
|
166
|
-
|
|
167
|
-
return this.refs.widget;
|
|
190
|
+
return this.widgetRef.current;
|
|
168
191
|
};
|
|
169
192
|
|
|
170
193
|
replaceWidgetProps: (arg1: WidgetProps<any, PerseusWidgetOptions>) => void =
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import {RendererWithDebugUI} from "../../../../../testing/renderer-with-debug-ui";
|
|
4
|
+
import {question} from "../__testdata__/label-image.testdata";
|
|
5
|
+
|
|
6
|
+
import type {APIOptions} from "../../types";
|
|
7
|
+
|
|
8
|
+
type StoryArgs = {
|
|
9
|
+
isMobile: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type ImageStory = {
|
|
13
|
+
title: string;
|
|
14
|
+
args: StoryArgs;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const Question1 = (args: StoryArgs): React.ReactElement => {
|
|
18
|
+
const apiOptions: APIOptions = {
|
|
19
|
+
isMobile: args.isMobile,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return <RendererWithDebugUI question={question} apiOptions={apiOptions} />;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
title: "Perseus/Widgets/Label Image",
|
|
27
|
+
args: {
|
|
28
|
+
isMobile: false,
|
|
29
|
+
},
|
|
30
|
+
} as ImageStory;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type {PerseusRenderer} from "../../perseus-types";
|
|
2
|
+
|
|
3
|
+
export const question: PerseusRenderer = {
|
|
4
|
+
content:
|
|
5
|
+
"Carol created a chart and a bar graph to show how many of each type of vehicle were in her supermarket parking lot.\n\nVehicle Type | Number in the parking lot\n:- | :-: \nTrucks| $25$ \nVans | $5$ \nCars| $40$ \nSUVs | $10$ \n\n**Label each bar on the bar graph.**\n\n[[☃ label-image 1]]\n\n",
|
|
6
|
+
images: {
|
|
7
|
+
"web+graphie://ka-perseus-graphie.s3.amazonaws.com/1e28332fd2321975639ab50c9ce442e568c18421":
|
|
8
|
+
{
|
|
9
|
+
width: 341,
|
|
10
|
+
height: 310,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
widgets: {
|
|
14
|
+
"label-image 1": {
|
|
15
|
+
type: "label-image",
|
|
16
|
+
alignment: "default",
|
|
17
|
+
static: false,
|
|
18
|
+
graded: true,
|
|
19
|
+
options: {
|
|
20
|
+
static: false,
|
|
21
|
+
choices: ["Trucks", "Vans", "Cars", "SUVs"],
|
|
22
|
+
imageAlt:
|
|
23
|
+
"A bar graph with four bar lines that shows the horizontal axis labeled Number in the parking lot and the vertical axis labeled Vehicle Type. The horizontal axis is labeled, from left to right: 0, 10, 20, 30, 40, and 50. The vertical axis has, from the bottom to the top, four unlabeled bar lines as follows: the first unlabeled bar line extends to the middle of 0 and 10, the second unlabeled bar line extends to 40, the third unlabeled bar line extends to the middle of 20 and 30, and fourth unlabeled bar line extends to 10.",
|
|
24
|
+
imageUrl:
|
|
25
|
+
"web+graphie://ka-perseus-graphie.s3.amazonaws.com/56c60c72e96cd353e4a8b5434506cd3a21e717af",
|
|
26
|
+
imageWidth: 415,
|
|
27
|
+
imageHeight: 314,
|
|
28
|
+
markers: [
|
|
29
|
+
{
|
|
30
|
+
answers: ["SUVs"],
|
|
31
|
+
label: "The fourth unlabeled bar line.",
|
|
32
|
+
x: 25,
|
|
33
|
+
y: 17.7,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
answers: ["Trucks"],
|
|
37
|
+
label: "The third unlabeled bar line.",
|
|
38
|
+
x: 25,
|
|
39
|
+
y: 35.3,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
answers: ["Cars"],
|
|
43
|
+
label: "The second unlabeled bar line.",
|
|
44
|
+
x: 25,
|
|
45
|
+
y: 53,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
answers: ["Vans"],
|
|
49
|
+
label: "The first unlabeled bar line.",
|
|
50
|
+
x: 25,
|
|
51
|
+
y: 70.3,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
multipleAnswers: false,
|
|
55
|
+
hideChoicesFromInstructions: true,
|
|
56
|
+
},
|
|
57
|
+
version: {
|
|
58
|
+
major: 0,
|
|
59
|
+
minor: 0,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
@@ -38,32 +38,63 @@ exports[`graded group widget should snapshot 1`] = `
|
|
|
38
38
|
class="spacer_bc4egv"
|
|
39
39
|
/>
|
|
40
40
|
<ul
|
|
41
|
-
class="
|
|
41
|
+
class="indicatorContainer_2pd7o4 indicatorContainer"
|
|
42
42
|
>
|
|
43
43
|
<li
|
|
44
|
-
|
|
45
|
-
class="indicator_qk5jgn-o_O-selectedIndicator_14jsc6v"
|
|
46
|
-
role="button"
|
|
47
|
-
tabindex="0"
|
|
44
|
+
class="indicator_7k5kza"
|
|
48
45
|
>
|
|
49
|
-
<
|
|
50
|
-
|
|
46
|
+
<button
|
|
47
|
+
aria-disabled="false"
|
|
48
|
+
aria-label="Skip to Problem 1a"
|
|
49
|
+
class="button_vr44p2-o_O-reset_152ygtm-o_O-link_13xlah4-o_O-indicatorButton_8uaklu"
|
|
50
|
+
role="button"
|
|
51
|
+
type="button"
|
|
51
52
|
>
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
<div
|
|
54
|
+
class="default_xu2jcg-o_O-indicatorDot_yy8ygm"
|
|
55
|
+
>
|
|
56
|
+
<div
|
|
57
|
+
class="default_xu2jcg-o_O-indicatorDotActive_1pky1a"
|
|
58
|
+
>
|
|
59
|
+
<span
|
|
60
|
+
class="srOnly_19bpjuy"
|
|
61
|
+
>
|
|
62
|
+
Current
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</button>
|
|
54
67
|
</li>
|
|
55
68
|
<li
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
class="indicator_7k5kza"
|
|
70
|
+
>
|
|
71
|
+
<button
|
|
72
|
+
aria-disabled="false"
|
|
73
|
+
aria-label="Skip to Problem 1b"
|
|
74
|
+
class="button_vr44p2-o_O-reset_152ygtm-o_O-link_13xlah4-o_O-indicatorButton_8uaklu"
|
|
75
|
+
role="button"
|
|
76
|
+
type="button"
|
|
77
|
+
>
|
|
78
|
+
<div
|
|
79
|
+
class="default_xu2jcg-o_O-indicatorDot_yy8ygm"
|
|
80
|
+
/>
|
|
81
|
+
</button>
|
|
82
|
+
</li>
|
|
61
83
|
<li
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
84
|
+
class="indicator_7k5kza"
|
|
85
|
+
>
|
|
86
|
+
<button
|
|
87
|
+
aria-disabled="false"
|
|
88
|
+
aria-label="Skip to Problem 1c"
|
|
89
|
+
class="button_vr44p2-o_O-reset_152ygtm-o_O-link_13xlah4-o_O-indicatorButton_8uaklu"
|
|
90
|
+
role="button"
|
|
91
|
+
type="button"
|
|
92
|
+
>
|
|
93
|
+
<div
|
|
94
|
+
class="default_xu2jcg-o_O-indicatorDot_yy8ygm"
|
|
95
|
+
/>
|
|
96
|
+
</button>
|
|
97
|
+
</li>
|
|
67
98
|
</ul>
|
|
68
99
|
</div>
|
|
69
100
|
<div
|
|
@@ -192,7 +192,7 @@ exports[`group widget should snapshot: initial render 1`] = `
|
|
|
192
192
|
style="border-color: transparent; border-radius: 50%;"
|
|
193
193
|
>
|
|
194
194
|
<div
|
|
195
|
-
class="
|
|
195
|
+
class="circle_1w6i3h1"
|
|
196
196
|
data-is-radio-icon="true"
|
|
197
197
|
data-test-id="choice-icon__library-choice-icon"
|
|
198
198
|
style="border-color: rgba(33,36,44,0.64); color: rgba(33, 36, 44, 0.64); border-radius: 24px;"
|
|
@@ -307,7 +307,7 @@ exports[`group widget should snapshot: initial render 1`] = `
|
|
|
307
307
|
style="border-color: transparent; border-radius: 50%;"
|
|
308
308
|
>
|
|
309
309
|
<div
|
|
310
|
-
class="
|
|
310
|
+
class="circle_1w6i3h1"
|
|
311
311
|
data-is-radio-icon="true"
|
|
312
312
|
data-test-id="choice-icon__library-choice-icon"
|
|
313
313
|
style="border-color: rgba(33,36,44,0.64); color: rgba(33, 36, 44, 0.64); border-radius: 24px;"
|
|
@@ -422,7 +422,7 @@ exports[`group widget should snapshot: initial render 1`] = `
|
|
|
422
422
|
style="border-color: transparent; border-radius: 50%;"
|
|
423
423
|
>
|
|
424
424
|
<div
|
|
425
|
-
class="
|
|
425
|
+
class="circle_1w6i3h1"
|
|
426
426
|
data-is-radio-icon="true"
|
|
427
427
|
data-test-id="choice-icon__library-choice-icon"
|
|
428
428
|
style="border-color: rgba(33,36,44,0.64); color: rgba(33, 36, 44, 0.64); border-radius: 24px;"
|
|
@@ -537,7 +537,7 @@ exports[`group widget should snapshot: initial render 1`] = `
|
|
|
537
537
|
style="border-color: transparent; border-radius: 50%;"
|
|
538
538
|
>
|
|
539
539
|
<div
|
|
540
|
-
class="
|
|
540
|
+
class="circle_1w6i3h1"
|
|
541
541
|
data-is-radio-icon="true"
|
|
542
542
|
data-test-id="choice-icon__library-choice-icon"
|
|
543
543
|
style="border-color: rgba(33,36,44,0.64); color: rgba(33, 36, 44, 0.64); border-radius: 24px;"
|
|
@@ -652,7 +652,7 @@ exports[`group widget should snapshot: initial render 1`] = `
|
|
|
652
652
|
style="border-color: transparent; border-radius: 50%;"
|
|
653
653
|
>
|
|
654
654
|
<div
|
|
655
|
-
class="
|
|
655
|
+
class="circle_1w6i3h1"
|
|
656
656
|
data-is-radio-icon="true"
|
|
657
657
|
data-test-id="choice-icon__library-choice-icon"
|
|
658
658
|
style="border-color: rgba(33,36,44,0.64); color: rgba(33, 36, 44, 0.64); border-radius: 24px;"
|