@khanacademy/perseus 17.3.0 → 17.3.2
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 +15 -0
- package/dist/es/index.css +1 -13
- package/dist/es/index.js +29 -12
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +1 -13
- package/dist/index.js +28 -12
- package/dist/index.js.map +1 -1
- package/dist/question-paragraph.d.ts +1 -0
- package/dist/renderer.d.ts +1 -0
- package/package.json +2 -2
- package/src/__tests__/error-boundary.test.tsx +76 -0
- package/src/error-boundary.tsx +22 -7
- package/src/question-paragraph.tsx +6 -1
- package/src/renderer.tsx +14 -7
- package/src/styles/widgets/label-image.less +1 -18
- package/src/widgets/__stories__/label-image.stories.tsx +30 -0
- package/src/widgets/__testdata__/label-image.testdata.ts +128 -0
- package/src/widgets/__tests__/expression-mobile.test.tsx +29 -0
- package/src/widgets/label-image/__stories__/answer-pill.stories.tsx +3 -3
- package/src/widgets/label-image/answer-pill.tsx +1 -1
- package/src/widgets/label-image.tsx +1 -1
- package/src/widgets/passage-ref-target.tsx +5 -2
- package/tsconfig-build.tsbuildinfo +1 -1
package/dist/renderer.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
|
|
|
59
59
|
linterContext: LinterContextProps;
|
|
60
60
|
legacyPerseusLint?: ReadonlyArray<string>;
|
|
61
61
|
widgets: PerseusRenderer["widgets"];
|
|
62
|
+
inline?: boolean;
|
|
62
63
|
};
|
|
63
64
|
type State = {
|
|
64
65
|
translationLintErrors: ReadonlyArray<string>;
|
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": "17.3.
|
|
6
|
+
"version": "17.3.2",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@khanacademy/kas": "^0.3.7",
|
|
26
26
|
"@khanacademy/kmath": "^0.1.8",
|
|
27
|
-
"@khanacademy/math-input": "^16.
|
|
27
|
+
"@khanacademy/math-input": "^16.4.0",
|
|
28
28
|
"@khanacademy/perseus-core": "1.4.1",
|
|
29
29
|
"@khanacademy/perseus-linter": "^0.3.10",
|
|
30
30
|
"@khanacademy/pure-markdown": "^0.2.13",
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {screen, render} from "@testing-library/react";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
|
|
4
|
+
import {testDependencies} from "../../../../testing/test-dependencies";
|
|
5
|
+
import * as Dependencies from "../dependencies";
|
|
6
|
+
import ErrorBoundary from "../error-boundary";
|
|
7
|
+
|
|
8
|
+
import "@testing-library/jest-dom";
|
|
9
|
+
|
|
10
|
+
const ProblematicComponent = () => {
|
|
11
|
+
throw new Error("I can haz error");
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe("error boundary", () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
|
|
17
|
+
testDependencies,
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should render children", () => {
|
|
22
|
+
render(
|
|
23
|
+
<ErrorBoundary>
|
|
24
|
+
<span>Hello world</span>
|
|
25
|
+
</ErrorBoundary>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
expect(screen.getByText("Hello world")).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should render error icon when children error", () => {
|
|
32
|
+
render(
|
|
33
|
+
<ErrorBoundary>
|
|
34
|
+
<ProblematicComponent />
|
|
35
|
+
</ErrorBoundary>,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(screen.getByRole("img")).toBeInTheDocument();
|
|
39
|
+
expect(screen.getByTitle("Rendering Error!")).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should call the onError callback when children error", () => {
|
|
43
|
+
const onErrorCallback = jest.fn();
|
|
44
|
+
|
|
45
|
+
render(
|
|
46
|
+
<ErrorBoundary onError={onErrorCallback}>
|
|
47
|
+
<ProblematicComponent />
|
|
48
|
+
</ErrorBoundary>,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(onErrorCallback).toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should log the error when children error", () => {
|
|
55
|
+
const errorSpy = jest.spyOn(testDependencies.Log, "error");
|
|
56
|
+
|
|
57
|
+
render(
|
|
58
|
+
<ErrorBoundary>
|
|
59
|
+
<ProblematicComponent />
|
|
60
|
+
</ErrorBoundary>,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(errorSpy).toHaveBeenCalledWith(
|
|
64
|
+
"Unhandled Perseus error: I can haz error",
|
|
65
|
+
"Internal",
|
|
66
|
+
{
|
|
67
|
+
cause: expect.anything(),
|
|
68
|
+
loggedMetadata: {
|
|
69
|
+
componentStack: `
|
|
70
|
+
in ProblematicComponent
|
|
71
|
+
in ErrorBoundary`,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
});
|
package/src/error-boundary.tsx
CHANGED
|
@@ -22,13 +22,27 @@ class ErrorBoundary extends React.Component<Props, State> {
|
|
|
22
22
|
componentDidCatch(error: Error, info: any) {
|
|
23
23
|
this.setState({error: error.toString()});
|
|
24
24
|
this.props.onError?.(error, info);
|
|
25
|
-
Log.error(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
Log.error(
|
|
26
|
+
// NOTE(jeremy): We concatenate the error messsage here. Typical
|
|
27
|
+
// Khan Academy error handling guidance says that you should never
|
|
28
|
+
// "build" the error message that might be sent to our error
|
|
29
|
+
// reporting tool (currently Sentry). However, if we don't
|
|
30
|
+
// differentiate between the different errors that are thrown, they
|
|
31
|
+
// all end up being grouped as a single Sentry event, which is very
|
|
32
|
+
// unhelpful.
|
|
33
|
+
"Unhandled Perseus error: " + error.message,
|
|
34
|
+
Errors.Internal,
|
|
35
|
+
{
|
|
36
|
+
cause: error,
|
|
37
|
+
loggedMetadata: {
|
|
38
|
+
componentStack:
|
|
39
|
+
!!info && "componentStack" in info
|
|
40
|
+
? info.componentStack
|
|
41
|
+
: "componentStack not provided",
|
|
42
|
+
...this.props.metadata,
|
|
43
|
+
},
|
|
30
44
|
},
|
|
31
|
-
|
|
45
|
+
);
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
render(): React.ReactNode {
|
|
@@ -39,7 +53,8 @@ class ErrorBoundary extends React.Component<Props, State> {
|
|
|
39
53
|
// errors into inline elements.
|
|
40
54
|
// TODO(michaelpolyak): Link error icon to "Report a problem".
|
|
41
55
|
return (
|
|
42
|
-
<svg height="16" width="16" viewBox="0 0 16 16">
|
|
56
|
+
<svg height="16" width="16" viewBox="0 0 16 16" role={"img"}>
|
|
57
|
+
<title>Rendering Error!</title>
|
|
43
58
|
<path
|
|
44
59
|
d="m8 16c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm0-3c0.55 0 1-0.45 1-1s-0.45-1-1-1-1 0.45-1 1 0.45 1 1 1zm0-9c-0.55 0-1 0.45-1 1v4c0 0.55.45 1 1 1s1-0.45 1-1v-4c0-0.55-0.45-1-1-1z"
|
|
45
60
|
fill="#d92916"
|
|
@@ -5,6 +5,7 @@ type Props = {
|
|
|
5
5
|
translationIndex: number;
|
|
6
6
|
paragraphIndex?: number;
|
|
7
7
|
children?: React.ReactNode;
|
|
8
|
+
inline?: boolean;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
class QuestionParagraph extends React.Component<Props> {
|
|
@@ -16,7 +17,11 @@ class QuestionParagraph extends React.Component<Props> {
|
|
|
16
17
|
// to attach some metadata to top-level QuestionParagraphs:
|
|
17
18
|
return (
|
|
18
19
|
<div
|
|
19
|
-
className={
|
|
20
|
+
className={
|
|
21
|
+
this.props.inline
|
|
22
|
+
? this.props.className ?? undefined
|
|
23
|
+
: className
|
|
24
|
+
}
|
|
20
25
|
data-perseus-component-index={this.props.translationIndex}
|
|
21
26
|
data-perseus-paragraph-index={this.props.paragraphIndex}
|
|
22
27
|
>
|
package/src/renderer.tsx
CHANGED
|
@@ -172,6 +172,8 @@ type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
|
|
|
172
172
|
linterContext: LinterContextProps;
|
|
173
173
|
legacyPerseusLint?: ReadonlyArray<string>;
|
|
174
174
|
widgets: PerseusRenderer["widgets"];
|
|
175
|
+
// Skip adding paragraph class
|
|
176
|
+
inline?: boolean;
|
|
175
177
|
};
|
|
176
178
|
|
|
177
179
|
type State = {
|
|
@@ -1060,6 +1062,7 @@ class Renderer extends React.Component<Props, State> {
|
|
|
1060
1062
|
className={className}
|
|
1061
1063
|
translationIndex={this.translationIndex}
|
|
1062
1064
|
paragraphIndex={state.paragraphIndex}
|
|
1065
|
+
inline={this.props.inline}
|
|
1063
1066
|
>
|
|
1064
1067
|
<ErrorBoundary>{output}</ErrorBoundary>
|
|
1065
1068
|
</QuestionParagraph>
|
|
@@ -1919,13 +1922,17 @@ class Renderer extends React.Component<Props, State> {
|
|
|
1919
1922
|
this._isTwoColumn = false;
|
|
1920
1923
|
|
|
1921
1924
|
// Parse the string of markdown to a parse tree
|
|
1922
|
-
const parsedMarkdown =
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1925
|
+
const parsedMarkdown = this.props.inline
|
|
1926
|
+
? PerseusMarkdown.parseInline(content, {
|
|
1927
|
+
// Recognize crowdin IDs while translating articles
|
|
1928
|
+
// (This should never be hit by exercises, though if you
|
|
1929
|
+
// decide you want to add a check that this is an article,
|
|
1930
|
+
// go for it.)
|
|
1931
|
+
isJipt: this.translationIndex != null,
|
|
1932
|
+
})
|
|
1933
|
+
: PerseusMarkdown.parse(content, {
|
|
1934
|
+
isJipt: this.translationIndex != null,
|
|
1935
|
+
});
|
|
1929
1936
|
|
|
1930
1937
|
// Optionally apply the linter to the parse tree
|
|
1931
1938
|
if (this.props.linterContext.highlightLint) {
|
|
@@ -5,35 +5,18 @@
|
|
|
5
5
|
margin: 0;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
-
button[id*="perseus-label-image-widget-answer-pill"],
|
|
9
|
-
div[id*="perseus-label-image-widget-answer-pill"] {
|
|
10
|
-
// Reset text content.
|
|
11
|
-
div.paragraph {
|
|
12
|
-
all: revert;
|
|
13
|
-
}
|
|
14
|
-
// Allow for padding around math content. Accounting for the negative margin here:
|
|
15
|
-
// https://github.com/Khan/perseus/blob/bafd35daee723456bf259a39b88e7638d91c8c3b/packages/perseus/src/renderer.tsx#L1176
|
|
16
|
-
div.perseus-block-math-inner {
|
|
17
|
-
margin: -5px 0 !important;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
8
|
}
|
|
21
9
|
|
|
22
10
|
// Reset mobile text content for answer pills.
|
|
23
11
|
@media (max-width: 767px) {
|
|
24
12
|
[id*="perseus-label-image-widget-answer-pill"] {
|
|
25
|
-
div.paragraph {
|
|
26
|
-
all: revert;
|
|
27
|
-
}
|
|
28
13
|
> div.perseus-renderer-responsive {
|
|
29
14
|
all: revert;
|
|
30
15
|
}
|
|
31
16
|
}
|
|
32
|
-
|
|
33
17
|
.framework-perseus.perseus-mobile
|
|
34
18
|
[id*="perseus-label-image-widget-answer-pill"] {
|
|
35
|
-
|
|
36
|
-
.perseus-renderer > .paragraph .paragraph {
|
|
19
|
+
mjx-container {
|
|
37
20
|
all: revert;
|
|
38
21
|
}
|
|
39
22
|
}
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
textQuestion,
|
|
6
6
|
mathQuestion,
|
|
7
7
|
numberline,
|
|
8
|
+
longTextFromArticle,
|
|
9
|
+
mixedContentQuestion,
|
|
8
10
|
} from "../__testdata__/label-image.testdata";
|
|
9
11
|
|
|
10
12
|
import type {PerseusRenderer} from "../../perseus-types";
|
|
@@ -59,6 +61,21 @@ export const LabelWidgetWithText = (args: StoryArgs): React.ReactElement => {
|
|
|
59
61
|
);
|
|
60
62
|
};
|
|
61
63
|
|
|
64
|
+
export const LabelWidgetWithLongText = (
|
|
65
|
+
args: StoryArgs,
|
|
66
|
+
): React.ReactElement => {
|
|
67
|
+
const apiOptions: APIOptions = {
|
|
68
|
+
isMobile: args.isMobile,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<RendererWithDebugUI
|
|
73
|
+
question={applyStoryArgs(longTextFromArticle, args)}
|
|
74
|
+
apiOptions={apiOptions}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
62
79
|
export const LabelWidgetWithMath = (args: StoryArgs): React.ReactElement => {
|
|
63
80
|
const apiOptions: APIOptions = {
|
|
64
81
|
isMobile: args.isMobile,
|
|
@@ -85,6 +102,19 @@ export const LabelImageNumberline = (args: StoryArgs): React.ReactElement => {
|
|
|
85
102
|
);
|
|
86
103
|
};
|
|
87
104
|
|
|
105
|
+
export const LabelImageMixedContent = (args: StoryArgs): React.ReactElement => {
|
|
106
|
+
const apiOptions: APIOptions = {
|
|
107
|
+
isMobile: args.isMobile,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<RendererWithDebugUI
|
|
112
|
+
question={applyStoryArgs(mixedContentQuestion, args)}
|
|
113
|
+
apiOptions={apiOptions}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
88
118
|
export default {
|
|
89
119
|
title: "Perseus/Widgets/Label Image",
|
|
90
120
|
args: {
|
|
@@ -178,3 +178,131 @@ export const numberline: PerseusRenderer = {
|
|
|
178
178
|
},
|
|
179
179
|
},
|
|
180
180
|
};
|
|
181
|
+
|
|
182
|
+
export const longTextFromArticle: PerseusRenderer = {
|
|
183
|
+
content: "[[☃ label-image 1]]",
|
|
184
|
+
images: {},
|
|
185
|
+
widgets: {
|
|
186
|
+
"label-image 1": {
|
|
187
|
+
type: "label-image",
|
|
188
|
+
alignment: "default",
|
|
189
|
+
static: false,
|
|
190
|
+
graded: true,
|
|
191
|
+
options: {
|
|
192
|
+
static: false,
|
|
193
|
+
choices: [
|
|
194
|
+
"long wavelength & low frequency",
|
|
195
|
+
"short wavelength & high frequency",
|
|
196
|
+
],
|
|
197
|
+
imageAlt:
|
|
198
|
+
"Section of a rainbow in the sky. From left to right, the colors appear as violet, indigo, blue, green, yellow, orange, and red.",
|
|
199
|
+
imageUrl:
|
|
200
|
+
"https://cdn.kastatic.org/ka-content-images/227d402cb09ebc1b67f197467212fa4ab3ced5b3.jpg",
|
|
201
|
+
imageWidth: 400,
|
|
202
|
+
imageHeight: 289,
|
|
203
|
+
markers: [
|
|
204
|
+
{
|
|
205
|
+
answers: ["short wavelength & high frequency"],
|
|
206
|
+
label: "Violet side of the rainbow",
|
|
207
|
+
x: 35.8,
|
|
208
|
+
y: 13,
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
answers: ["long wavelength & low frequency"],
|
|
212
|
+
label: "Red side of the rainbow",
|
|
213
|
+
x: 71.8,
|
|
214
|
+
y: 50.5,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
multipleAnswers: false,
|
|
218
|
+
hideChoicesFromInstructions: true,
|
|
219
|
+
},
|
|
220
|
+
version: {
|
|
221
|
+
major: 0,
|
|
222
|
+
minor: 0,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export const mixedContentQuestion: PerseusRenderer = {
|
|
229
|
+
content:
|
|
230
|
+
"A beach ball floats on water. The ball is at rest.\n\n[[☃ image 1]]\n\n**Complete the free body diagram by labeling the forces acting on the ball.**\n\n[[☃ label-image 1]]",
|
|
231
|
+
images: {
|
|
232
|
+
"https://cdn.kastatic.org/ka-content-images/0fa7eefde0067d986d2e6dc377e8d2db3e1d466f.svg":
|
|
233
|
+
{
|
|
234
|
+
width: 150,
|
|
235
|
+
height: 300,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
widgets: {
|
|
239
|
+
"image 1": {
|
|
240
|
+
type: "image",
|
|
241
|
+
alignment: "block",
|
|
242
|
+
static: false,
|
|
243
|
+
graded: true,
|
|
244
|
+
options: {
|
|
245
|
+
static: false,
|
|
246
|
+
title: "",
|
|
247
|
+
range: [
|
|
248
|
+
[0, 10],
|
|
249
|
+
[0, 10],
|
|
250
|
+
],
|
|
251
|
+
box: [350, 219],
|
|
252
|
+
backgroundImage: {
|
|
253
|
+
url: "https://cdn.kastatic.org/ka-content-images/581c7d3928ba5f81e9dc5720291ec895764cc7e8.png",
|
|
254
|
+
width: 350,
|
|
255
|
+
height: 219,
|
|
256
|
+
},
|
|
257
|
+
labels: [],
|
|
258
|
+
alt: "An inflated beach ball floats on the surface of water. Only a small portion of the ball is underwater.",
|
|
259
|
+
caption: "",
|
|
260
|
+
},
|
|
261
|
+
version: {
|
|
262
|
+
major: 0,
|
|
263
|
+
minor: 0,
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
"label-image 1": {
|
|
267
|
+
type: "label-image",
|
|
268
|
+
alignment: "default",
|
|
269
|
+
static: false,
|
|
270
|
+
graded: true,
|
|
271
|
+
options: {
|
|
272
|
+
static: false,
|
|
273
|
+
choices: [
|
|
274
|
+
"lift $(F_\\text{L})$",
|
|
275
|
+
"buoyant force $(F_\\text{B})$",
|
|
276
|
+
"gravity $(F_\\text{g})$",
|
|
277
|
+
"normal force $(F_\\text{N})$",
|
|
278
|
+
],
|
|
279
|
+
imageAlt:
|
|
280
|
+
"A model shows a square with two arrows pointing out of it. One arrow points up and another arrow points down.",
|
|
281
|
+
imageUrl:
|
|
282
|
+
"https://cdn.kastatic.org/ka-content-images/b24e40b5a36890130acfb7bd237c4bf0d85c7b44.svg",
|
|
283
|
+
imageWidth: 150,
|
|
284
|
+
imageHeight: 300,
|
|
285
|
+
markers: [
|
|
286
|
+
{
|
|
287
|
+
answers: ["buoyant force $(F_\\text{B})$"],
|
|
288
|
+
label: "An arrow that points upward from the square",
|
|
289
|
+
x: 64.2,
|
|
290
|
+
y: 17.6,
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
answers: ["gravity $(F_\\text{g})$"],
|
|
294
|
+
label: "An arrow that points downward from the square",
|
|
295
|
+
x: 66.2,
|
|
296
|
+
y: 81.8,
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
multipleAnswers: false,
|
|
300
|
+
hideChoicesFromInstructions: true,
|
|
301
|
+
},
|
|
302
|
+
version: {
|
|
303
|
+
major: 0,
|
|
304
|
+
minor: 0,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
};
|
|
@@ -121,6 +121,35 @@ describe("expression mobile", () => {
|
|
|
121
121
|
);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
+
it("shows keypad after focused input interaction", async () => {
|
|
125
|
+
render(<ConnectedRenderer />);
|
|
126
|
+
|
|
127
|
+
const input = screen.getByLabelText(
|
|
128
|
+
"Math input box Tap with one or two fingers to open keyboard",
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
fireEvent.touchStart(input);
|
|
132
|
+
|
|
133
|
+
// waiting because `visibility` is animated
|
|
134
|
+
await waitFor(() =>
|
|
135
|
+
expect(screen.getByRole("button", {name: "1"})).toBeVisible(),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
userEvent.click(screen.getByRole("tab", {name: "Dismiss"}));
|
|
139
|
+
|
|
140
|
+
// wait for the keypad to close
|
|
141
|
+
await waitFor(() =>
|
|
142
|
+
expect(screen.queryByRole("button", {name: "1"})).toBeNull(),
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
fireEvent.touchStart(input);
|
|
146
|
+
|
|
147
|
+
// confirm that the keypad has reopened
|
|
148
|
+
await waitFor(() =>
|
|
149
|
+
expect(screen.getByRole("button", {name: "1"})).toBeVisible(),
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
124
153
|
it("is possible to use the keypad", async () => {
|
|
125
154
|
render(<ConnectedRenderer />);
|
|
126
155
|
|
|
@@ -22,7 +22,7 @@ export default story;
|
|
|
22
22
|
export const SingleAnswer = {
|
|
23
23
|
args: {
|
|
24
24
|
id: "1",
|
|
25
|
-
selectedAnswers: ["Answer Pill
|
|
25
|
+
selectedAnswers: ["Answer Pill"],
|
|
26
26
|
markerRef: null,
|
|
27
27
|
side: "top",
|
|
28
28
|
onClick: () => {},
|
|
@@ -42,7 +42,7 @@ export const MultipleAnswers = {
|
|
|
42
42
|
export const Correct = {
|
|
43
43
|
args: {
|
|
44
44
|
id: "1",
|
|
45
|
-
selectedAnswers: ["Right Answer
|
|
45
|
+
selectedAnswers: ["Right Answer"],
|
|
46
46
|
showCorrectness: "correct",
|
|
47
47
|
markerRef: null,
|
|
48
48
|
side: "top",
|
|
@@ -53,7 +53,7 @@ export const Correct = {
|
|
|
53
53
|
export const Incorrect = {
|
|
54
54
|
args: {
|
|
55
55
|
id: "1",
|
|
56
|
-
selectedAnswers: ["Wrong Answer
|
|
56
|
+
selectedAnswers: ["Wrong Answer"],
|
|
57
57
|
showCorrectness: "incorrect",
|
|
58
58
|
markerRef: null,
|
|
59
59
|
side: "top",
|
|
@@ -667,7 +667,7 @@ export class LabelImage extends React.Component<
|
|
|
667
667
|
[`margin${
|
|
668
668
|
markerPosition.charAt(0).toUpperCase() +
|
|
669
669
|
markerPosition.slice(1)
|
|
670
|
-
}`]:
|
|
670
|
+
}`]: 15, // move pill further from marker
|
|
671
671
|
};
|
|
672
672
|
|
|
673
673
|
const showAnswerChoice =
|
|
@@ -50,8 +50,11 @@ class PassageRefTarget extends React.Component<any> {
|
|
|
50
50
|
return (
|
|
51
51
|
<Renderer
|
|
52
52
|
content={this.props.content}
|
|
53
|
-
//
|
|
54
|
-
|
|
53
|
+
// This was already here before inline was recently added (#873)
|
|
54
|
+
// It was for a different use case a long time ago:
|
|
55
|
+
// https://phabricator.khanacademy.org/D12113
|
|
56
|
+
// Commenting out to prevent unanticipated side effects
|
|
57
|
+
// inline={true}
|
|
55
58
|
apiOptions={this.props.apiOptions}
|
|
56
59
|
linterContext={this.props.linterContext}
|
|
57
60
|
/>
|