@khanacademy/perseus 12.0.1 → 12.2.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 +21 -0
- package/dist/article-renderer.d.ts +2 -0
- package/dist/es/index.css +5 -2
- package/dist/es/index.js +36 -25
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +5 -2
- package/dist/index.js +36 -25
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/__stories__/article-renderer.stories.tsx +28 -2
- package/src/__testdata__/article-renderer.testdata.ts +85 -0
- package/src/__tests__/article-renderer.test.tsx +131 -0
- package/src/__tests__/item-renderer.test.tsx +1 -19
- package/src/article-renderer.tsx +58 -45
- package/src/styles/perseus-renderer.less +1 -0
- package/src/styles/widgets/image.less +2 -6
- package/src/widgets/__stories__/image.stories.tsx +1 -0
- package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +1 -0
- package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +2 -0
- package/src/widgets/image.tsx +12 -2
- package/tsconfig-build.tsbuildinfo +1 -1
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": "12.0
|
|
6
|
+
"version": "12.2.0",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@khanacademy/kas": "^0.3.3",
|
|
26
26
|
"@khanacademy/kmath": "^0.1.4",
|
|
27
|
-
"@khanacademy/math-input": "^14.
|
|
27
|
+
"@khanacademy/math-input": "^14.2.0",
|
|
28
28
|
"@khanacademy/perseus-core": "1.1.2",
|
|
29
29
|
"@khanacademy/perseus-linter": "^0.3.6",
|
|
30
30
|
"@khanacademy/pure-markdown": "^0.2.8",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"jquery": "^2.1.1",
|
|
58
58
|
"katex": "^0.11.1",
|
|
59
59
|
"lodash.debounce": "^4.0.8",
|
|
60
|
-
"mathquill": "git+https://git@github.com/Khan/mathquill.git#
|
|
60
|
+
"mathquill": "git+https://git@github.com/Khan/mathquill.git#48410e80d760bbd5105544d4a4ab459a28dc2cbc",
|
|
61
61
|
"perseus-build-settings": "^0.2.1",
|
|
62
62
|
"prop-types": "^15.6.1",
|
|
63
63
|
"react": "16.14.0",
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
multiSectionArticle,
|
|
8
8
|
passageArticle,
|
|
9
9
|
articleWithExpression,
|
|
10
|
+
multiSectionArticleWithExpression,
|
|
10
11
|
} from "../__testdata__/article-renderer.testdata";
|
|
11
12
|
import ArticleRenderer from "../article-renderer";
|
|
12
13
|
import TestKeypadContextWrapper from "../widgets/__stories__/test-keypad-context-wrapper";
|
|
@@ -55,7 +56,7 @@ export const PassageArticle = ({useNewStyles}): any => (
|
|
|
55
56
|
export const ExpressionArticle = ({useNewStyles}): any => (
|
|
56
57
|
<TestKeypadContextWrapper>
|
|
57
58
|
<KeypadContext.Consumer>
|
|
58
|
-
{({keypadElement, setRenderer
|
|
59
|
+
{({keypadElement, setRenderer}) => (
|
|
59
60
|
<ArticleRenderer
|
|
60
61
|
ref={(node) => {
|
|
61
62
|
setRenderer(node);
|
|
@@ -63,7 +64,32 @@ export const ExpressionArticle = ({useNewStyles}): any => (
|
|
|
63
64
|
json={articleWithExpression}
|
|
64
65
|
dependencies={storybookDependenciesV2}
|
|
65
66
|
useNewStyles={useNewStyles}
|
|
66
|
-
apiOptions={{
|
|
67
|
+
apiOptions={{
|
|
68
|
+
isMobile: true,
|
|
69
|
+
customKeypad: true,
|
|
70
|
+
}}
|
|
71
|
+
keypadElement={keypadElement}
|
|
72
|
+
/>
|
|
73
|
+
)}
|
|
74
|
+
</KeypadContext.Consumer>
|
|
75
|
+
</TestKeypadContextWrapper>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export const MultiSectionedExpressionArticle = ({useNewStyles}): any => (
|
|
79
|
+
<TestKeypadContextWrapper>
|
|
80
|
+
<KeypadContext.Consumer>
|
|
81
|
+
{({keypadElement, setRenderer}) => (
|
|
82
|
+
<ArticleRenderer
|
|
83
|
+
ref={(node) => {
|
|
84
|
+
setRenderer(node);
|
|
85
|
+
}}
|
|
86
|
+
json={multiSectionArticleWithExpression}
|
|
87
|
+
dependencies={storybookDependenciesV2}
|
|
88
|
+
useNewStyles={useNewStyles}
|
|
89
|
+
apiOptions={{
|
|
90
|
+
isMobile: true,
|
|
91
|
+
customKeypad: true,
|
|
92
|
+
}}
|
|
67
93
|
keypadElement={keypadElement}
|
|
68
94
|
/>
|
|
69
95
|
)}
|
|
@@ -125,3 +125,88 @@ export const multiSectionArticle: ReadonlyArray<PerseusRenderer> = [
|
|
|
125
125
|
widgets: {},
|
|
126
126
|
},
|
|
127
127
|
];
|
|
128
|
+
|
|
129
|
+
export const multiSectionArticleWithExpression: ReadonlyArray<PerseusRenderer> =
|
|
130
|
+
[
|
|
131
|
+
{
|
|
132
|
+
content:
|
|
133
|
+
"### Practice Problem\n\n$8\\cdot(11i+2)=$ [[☃ expression 1]] \n*Your answer should be a complex number in the form $a+bi$ where $a$ and $b$ are real numbers.*",
|
|
134
|
+
images: {},
|
|
135
|
+
widgets: {
|
|
136
|
+
"expression 1": {
|
|
137
|
+
alignment: "default",
|
|
138
|
+
graded: true,
|
|
139
|
+
options: {
|
|
140
|
+
answerForms: [
|
|
141
|
+
{
|
|
142
|
+
considered: "correct",
|
|
143
|
+
form: true,
|
|
144
|
+
simplify: false,
|
|
145
|
+
value: "16+88i",
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
buttonSets: ["basic"],
|
|
149
|
+
functions: ["f", "g", "h"],
|
|
150
|
+
times: false,
|
|
151
|
+
},
|
|
152
|
+
static: false,
|
|
153
|
+
type: "expression",
|
|
154
|
+
version: {major: 1, minor: 0},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
content:
|
|
160
|
+
"### Practice Problem\n\n$8\\cdot(11i+2)=$ [[☃ expression 2]] \n*Your answer should be a complex number in the form $a+bi$ where $a$ and $b$ are real numbers.*",
|
|
161
|
+
images: {},
|
|
162
|
+
widgets: {
|
|
163
|
+
"expression 2": {
|
|
164
|
+
alignment: "default",
|
|
165
|
+
graded: true,
|
|
166
|
+
options: {
|
|
167
|
+
answerForms: [
|
|
168
|
+
{
|
|
169
|
+
considered: "correct",
|
|
170
|
+
form: true,
|
|
171
|
+
simplify: false,
|
|
172
|
+
value: "16+88i",
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
buttonSets: ["basic"],
|
|
176
|
+
functions: ["f", "g", "h"],
|
|
177
|
+
times: false,
|
|
178
|
+
},
|
|
179
|
+
static: false,
|
|
180
|
+
type: "expression",
|
|
181
|
+
version: {major: 1, minor: 0},
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
content:
|
|
187
|
+
"### Practice Problem\n\n$8\\cdot(11i+2)=$ [[☃ expression 3]] \n*Your answer should be a complex number in the form $a+bi$ where $a$ and $b$ are real numbers.*",
|
|
188
|
+
images: {},
|
|
189
|
+
widgets: {
|
|
190
|
+
"expression 3": {
|
|
191
|
+
alignment: "default",
|
|
192
|
+
graded: true,
|
|
193
|
+
options: {
|
|
194
|
+
answerForms: [
|
|
195
|
+
{
|
|
196
|
+
considered: "correct",
|
|
197
|
+
form: true,
|
|
198
|
+
simplify: false,
|
|
199
|
+
value: "16+88i",
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
buttonSets: ["basic"],
|
|
203
|
+
functions: ["f", "g", "h"],
|
|
204
|
+
times: false,
|
|
205
|
+
},
|
|
206
|
+
static: false,
|
|
207
|
+
type: "expression",
|
|
208
|
+
version: {major: 1, minor: 0},
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
];
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StatefulKeypadContextProvider,
|
|
3
|
+
KeypadContext,
|
|
4
|
+
} from "@khanacademy/math-input";
|
|
5
|
+
import {RenderStateRoot} from "@khanacademy/wonder-blocks-core";
|
|
6
|
+
import {screen, render, fireEvent, waitFor} from "@testing-library/react";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import "@testing-library/jest-dom"; // Imports custom matchers
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
testDependencies,
|
|
12
|
+
testDependenciesV2,
|
|
13
|
+
} from "../../../../testing/test-dependencies";
|
|
14
|
+
import KeypadSwitch from "../../../math-input/src/components/keypad-switch";
|
|
15
|
+
import {articleWithExpression} from "../__testdata__/article-renderer.testdata";
|
|
16
|
+
import ArticleRenderer from "../article-renderer";
|
|
17
|
+
import * as Dependencies from "../dependencies";
|
|
18
|
+
import {ApiOptions} from "../perseus-api";
|
|
19
|
+
|
|
20
|
+
import type {APIOptions} from "../types";
|
|
21
|
+
|
|
22
|
+
function KeypadWithContext() {
|
|
23
|
+
return (
|
|
24
|
+
<KeypadContext.Consumer>
|
|
25
|
+
{({setKeypadElement}) => {
|
|
26
|
+
return (
|
|
27
|
+
<KeypadSwitch
|
|
28
|
+
onElementMounted={setKeypadElement}
|
|
29
|
+
onDismiss={() => {}}
|
|
30
|
+
onAnalyticsEvent={async () => {}}
|
|
31
|
+
useV2Keypad
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}}
|
|
35
|
+
</KeypadContext.Consumer>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
// This looks alot like `widgets/__tests__/renderQuestion.jsx', except we use
|
|
39
|
+
// the ArticleRenderer instead of Renderer
|
|
40
|
+
export const RenderArticle = (
|
|
41
|
+
apiOptions: APIOptions = Object.freeze({}),
|
|
42
|
+
): {
|
|
43
|
+
container: HTMLElement;
|
|
44
|
+
renderer: ArticleRenderer;
|
|
45
|
+
} => {
|
|
46
|
+
let renderer: ArticleRenderer | null = null;
|
|
47
|
+
const {container} = render(
|
|
48
|
+
<RenderStateRoot>
|
|
49
|
+
<StatefulKeypadContextProvider>
|
|
50
|
+
<KeypadContext.Consumer>
|
|
51
|
+
{({keypadElement, setRenderer}) => (
|
|
52
|
+
<ArticleRenderer
|
|
53
|
+
ref={(node) => {
|
|
54
|
+
renderer = node;
|
|
55
|
+
setRenderer(node);
|
|
56
|
+
}}
|
|
57
|
+
json={articleWithExpression}
|
|
58
|
+
dependencies={testDependenciesV2}
|
|
59
|
+
apiOptions={{...apiOptions}}
|
|
60
|
+
keypadElement={keypadElement}
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
</KeypadContext.Consumer>
|
|
64
|
+
<KeypadWithContext />
|
|
65
|
+
</StatefulKeypadContextProvider>
|
|
66
|
+
</RenderStateRoot>,
|
|
67
|
+
);
|
|
68
|
+
if (!renderer) {
|
|
69
|
+
throw new Error(`Failed to render!`);
|
|
70
|
+
}
|
|
71
|
+
return {container, renderer};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
describe("article renderer", () => {
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
// Mock ResizeObserver used by the mobile keypad
|
|
77
|
+
window.ResizeObserver = jest.fn().mockImplementation(() => ({
|
|
78
|
+
observe: jest.fn(),
|
|
79
|
+
unobserve: jest.fn(),
|
|
80
|
+
disconnect: jest.fn(),
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
|
|
84
|
+
testDependencies,
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterEach(() => {
|
|
89
|
+
// The Renderer uses a timer to wait for widgets to complete rendering.
|
|
90
|
+
// If we don't spin the timers here, then the timer fires in the test
|
|
91
|
+
// _after_ and breaks it because we do setState() in the callback,
|
|
92
|
+
// and by that point the component has been unmounted.
|
|
93
|
+
jest.runOnlyPendingTimers();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should render the content", () => {
|
|
97
|
+
// Arrange and Act
|
|
98
|
+
RenderArticle({
|
|
99
|
+
...ApiOptions.defaults,
|
|
100
|
+
isMobile: false,
|
|
101
|
+
customKeypad: false,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Assert
|
|
105
|
+
expect(screen.getByRole("textbox")).toBeInTheDocument();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should call the onFocusChanged callback when an input is focused", async () => {
|
|
109
|
+
// Arrange
|
|
110
|
+
const answerableCallback = jest.fn();
|
|
111
|
+
|
|
112
|
+
// Act
|
|
113
|
+
RenderArticle({
|
|
114
|
+
...ApiOptions.defaults,
|
|
115
|
+
onFocusChange: answerableCallback,
|
|
116
|
+
isMobile: true,
|
|
117
|
+
customKeypad: true,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const input = screen.getByLabelText(
|
|
121
|
+
"Math input box Tap with one or two fingers to open keyboard",
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
fireEvent.touchStart(input);
|
|
125
|
+
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
expect(screen.getByRole("button", {name: "4"})).toBeVisible();
|
|
128
|
+
});
|
|
129
|
+
expect(answerableCallback).toHaveBeenCalled();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {StatefulKeypadContextProvider} from "@khanacademy/math-input";
|
|
2
2
|
import {RenderStateRoot} from "@khanacademy/wonder-blocks-core";
|
|
3
|
-
import {fireEvent, render, screen
|
|
3
|
+
import {fireEvent, render, screen} from "@testing-library/react";
|
|
4
4
|
import userEvent from "@testing-library/user-event";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import "@testing-library/jest-dom"; // Imports custom matchers
|
|
@@ -88,7 +88,6 @@ export const renderQuestion = (
|
|
|
88
88
|
area. Without both of these, it fails to render anything! */}
|
|
89
89
|
<div id="workarea" />
|
|
90
90
|
<div id="hintsarea" />
|
|
91
|
-
|
|
92
91
|
<Peripherals />
|
|
93
92
|
</StatefulKeypadContextProvider>
|
|
94
93
|
</RenderStateRoot>,
|
|
@@ -312,23 +311,6 @@ describe("item renderer", () => {
|
|
|
312
311
|
);
|
|
313
312
|
});
|
|
314
313
|
|
|
315
|
-
it("should activate the keypad when widget with input is focused", async () => {
|
|
316
|
-
// Arrange
|
|
317
|
-
const {renderer} = renderQuestion(itemWithInput, {
|
|
318
|
-
isMobile: true,
|
|
319
|
-
customKeypad: true,
|
|
320
|
-
useV2Keypad: true,
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// Act
|
|
324
|
-
renderer.focus();
|
|
325
|
-
|
|
326
|
-
// Assert
|
|
327
|
-
await waitFor(() => {
|
|
328
|
-
expect(screen.getByLabelText("7")).toBeVisible();
|
|
329
|
-
});
|
|
330
|
-
});
|
|
331
|
-
|
|
332
314
|
it("should provide current and previous focus paths on focus change to, and away from, a single widget", () => {
|
|
333
315
|
// Arrange
|
|
334
316
|
const onFocusChange = jest.fn();
|
package/src/article-renderer.tsx
CHANGED
|
@@ -44,6 +44,7 @@ class ArticleRenderer
|
|
|
44
44
|
implements KeypadContextRendererInterface
|
|
45
45
|
{
|
|
46
46
|
_currentFocus: any;
|
|
47
|
+
sectionRenderers: Array<Renderer> = [];
|
|
47
48
|
|
|
48
49
|
static defaultProps: DefaultProps = {
|
|
49
50
|
apiOptions: ApiOptions.defaults,
|
|
@@ -87,14 +88,21 @@ class ArticleRenderer
|
|
|
87
88
|
// paths, so as to check whether the focused path represents an
|
|
88
89
|
// input.
|
|
89
90
|
let didFocusInput = false;
|
|
91
|
+
let focusedInput;
|
|
92
|
+
|
|
90
93
|
if (this._currentFocus) {
|
|
91
|
-
const [
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
const [sectionIndex, ...focusPath] = this._currentFocus;
|
|
95
|
+
|
|
96
|
+
const inputPaths =
|
|
97
|
+
this.sectionRenderers[sectionIndex].getInputPaths();
|
|
98
|
+
|
|
95
99
|
didFocusInput = inputPaths.some((inputPath) => {
|
|
96
100
|
return Util.inputPathsEqual(inputPath, focusPath);
|
|
97
101
|
});
|
|
102
|
+
focusedInput =
|
|
103
|
+
this.sectionRenderers[sectionIndex].getDOMNodeForPath(
|
|
104
|
+
focusPath,
|
|
105
|
+
);
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
if (this.props.apiOptions.onFocusChange != null) {
|
|
@@ -102,6 +110,7 @@ class ArticleRenderer
|
|
|
102
110
|
this._currentFocus,
|
|
103
111
|
prevFocusPath,
|
|
104
112
|
didFocusInput ? keypadElement?.getDOMNode() : null,
|
|
113
|
+
didFocusInput ? focusedInput : null,
|
|
105
114
|
);
|
|
106
115
|
}
|
|
107
116
|
|
|
@@ -137,10 +146,8 @@ class ArticleRenderer
|
|
|
137
146
|
|
|
138
147
|
blur: () => void = () => {
|
|
139
148
|
if (this._currentFocus) {
|
|
140
|
-
const [
|
|
141
|
-
|
|
142
|
-
// @ts-expect-error - TS2339 - Property 'blurPath' does not exist on type 'ReactInstance'.
|
|
143
|
-
this.refs[sectionRef].blurPath(inputPath);
|
|
149
|
+
const [sectionIndex, ...inputPath] = this._currentFocus;
|
|
150
|
+
this.sectionRenderers[sectionIndex].blurPath(inputPath);
|
|
144
151
|
}
|
|
145
152
|
};
|
|
146
153
|
|
|
@@ -166,47 +173,53 @@ class ArticleRenderer
|
|
|
166
173
|
});
|
|
167
174
|
|
|
168
175
|
// TODO(alex): Add mobile api functions and pass them down here
|
|
169
|
-
|
|
170
|
-
|
|
176
|
+
// We're using the index as the key here because we don't have a unique
|
|
177
|
+
// identifier for each section. This should be fine as we never remove
|
|
178
|
+
// or reorder sections.
|
|
179
|
+
const sections = this._sections().map((section, sectionIndex) => {
|
|
171
180
|
return (
|
|
172
|
-
<
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
linterContext
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
</div>
|
|
205
|
-
</DependenciesContext.Provider>
|
|
181
|
+
<div key={sectionIndex} className="clearfix">
|
|
182
|
+
<Renderer
|
|
183
|
+
{...section}
|
|
184
|
+
ref={(elem) => {
|
|
185
|
+
if (elem) {
|
|
186
|
+
this.sectionRenderers[sectionIndex] = elem;
|
|
187
|
+
}
|
|
188
|
+
}}
|
|
189
|
+
key={sectionIndex}
|
|
190
|
+
key_={sectionIndex}
|
|
191
|
+
keypadElement={this.props.keypadElement}
|
|
192
|
+
apiOptions={{
|
|
193
|
+
...apiOptions,
|
|
194
|
+
onFocusChange: (newFocusPath, oldFocusPath) => {
|
|
195
|
+
// Prefix the paths with the relevant section index,
|
|
196
|
+
// so as to allow us to distinguish between
|
|
197
|
+
// equivalently-named inputs across Renderers.
|
|
198
|
+
this._handleFocusChange(
|
|
199
|
+
newFocusPath &&
|
|
200
|
+
[sectionIndex].concat(newFocusPath),
|
|
201
|
+
oldFocusPath &&
|
|
202
|
+
[sectionIndex].concat(oldFocusPath),
|
|
203
|
+
);
|
|
204
|
+
},
|
|
205
|
+
}}
|
|
206
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
207
|
+
this.props.linterContext,
|
|
208
|
+
"article",
|
|
209
|
+
)}
|
|
210
|
+
legacyPerseusLint={this.props.legacyPerseusLint}
|
|
211
|
+
/>
|
|
212
|
+
</div>
|
|
206
213
|
);
|
|
207
214
|
});
|
|
208
215
|
|
|
209
|
-
return
|
|
216
|
+
return (
|
|
217
|
+
<div className={classes}>
|
|
218
|
+
<DependenciesContext.Provider value={this.props.dependencies}>
|
|
219
|
+
{sections}
|
|
220
|
+
</DependenciesContext.Provider>
|
|
221
|
+
</div>
|
|
222
|
+
);
|
|
210
223
|
}
|
|
211
224
|
}
|
|
212
225
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.perseus-image-widget {
|
|
2
|
-
margin:
|
|
2
|
+
margin-left: auto;
|
|
3
|
+
margin-right: auto;
|
|
3
4
|
|
|
4
5
|
.perseus-image-title {
|
|
5
6
|
text-align: center;
|
|
@@ -10,11 +11,6 @@
|
|
|
10
11
|
padding-left: 16px;
|
|
11
12
|
position: relative;
|
|
12
13
|
|
|
13
|
-
// This offsets the paragraph's padding
|
|
14
|
-
// So that the caption sits much closer
|
|
15
|
-
// to the image
|
|
16
|
-
top: -12px;
|
|
17
|
-
|
|
18
14
|
&::before {
|
|
19
15
|
content: "";
|
|
20
16
|
position: absolute;
|
|
@@ -72,6 +72,7 @@ export const Question2 = (args: StoryArgs): React.ReactElement => {
|
|
|
72
72
|
imageOptions != null
|
|
73
73
|
? {
|
|
74
74
|
...imageOptions,
|
|
75
|
+
alignment: "full-width",
|
|
75
76
|
title: args.title,
|
|
76
77
|
caption:
|
|
77
78
|
"There is neither happiness nor unhappiness in this world; there is only the comparison of one state with another. Only a man who has felt ultimate despair is capable of feeling ultimate bliss. It is necessary to have wished for death in order to know how good it is to live.....the sum of all human wisdom will be contained in these two words: Wait and Hope",
|
|
@@ -26,6 +26,7 @@ exports[`image widget - isMobile %b should snapshot: first render 1`] = `
|
|
|
26
26
|
>
|
|
27
27
|
<figure
|
|
28
28
|
class="perseus-image-widget"
|
|
29
|
+
style="max-width: 420px;"
|
|
29
30
|
>
|
|
30
31
|
<div
|
|
31
32
|
class="fixed-to-responsive svg-image"
|
|
@@ -207,6 +208,7 @@ exports[`image widget - isMobile %b should snapshot: first render 2`] = `
|
|
|
207
208
|
>
|
|
208
209
|
<figure
|
|
209
210
|
class="perseus-image-widget"
|
|
211
|
+
style="max-width: 420px;"
|
|
210
212
|
>
|
|
211
213
|
<div
|
|
212
214
|
class="perseus-image-title"
|
package/src/widgets/image.tsx
CHANGED
|
@@ -220,7 +220,12 @@ class ImageWidget extends React.Component<Props> {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
return (
|
|
223
|
-
<figure
|
|
223
|
+
<figure
|
|
224
|
+
className="perseus-image-widget"
|
|
225
|
+
style={{
|
|
226
|
+
maxWidth: backgroundImage.width,
|
|
227
|
+
}}
|
|
228
|
+
>
|
|
224
229
|
{image}
|
|
225
230
|
{alt}
|
|
226
231
|
{titleAndCaption}
|
|
@@ -260,7 +265,12 @@ class ImageWidget extends React.Component<Props> {
|
|
|
260
265
|
}
|
|
261
266
|
|
|
262
267
|
return (
|
|
263
|
-
<figure
|
|
268
|
+
<figure
|
|
269
|
+
className="perseus-image-widget"
|
|
270
|
+
style={{
|
|
271
|
+
maxWidth: backgroundImage.width,
|
|
272
|
+
}}
|
|
273
|
+
>
|
|
264
274
|
{title}
|
|
265
275
|
{image}
|
|
266
276
|
{alt}
|