@khanacademy/perseus 16.0.0 → 17.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/CHANGELOG.md +74 -0
- package/dist/article-renderer.d.ts +1 -2
- package/dist/components.d.ts +0 -1
- package/dist/dependencies.d.ts +1 -0
- package/dist/es/index.css +20 -90
- package/dist/es/index.js +457 -1028
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +20 -90
- package/dist/index.d.ts +0 -1
- package/dist/index.js +456 -1031
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +1 -0
- package/dist/server-item-renderer.d.ts +42 -15
- package/dist/strings.js +1 -23
- package/dist/widgets/label-image/answer-pill.d.ts +10 -0
- package/dist/widgets/label-image/hide-answers-toggle.d.ts +6 -0
- package/dist/widgets/label-image/marker.d.ts +6 -9
- package/dist/widgets/label-image/types.d.ts +1 -0
- package/dist/widgets/label-image.d.ts +101 -12
- package/package.json +30 -22
- package/src/__stories__/server-item-renderer.stories.tsx +20 -1
- package/src/__testdata__/server-item-renderer.testdata.ts +173 -0
- package/src/__tests__/__snapshots__/renderer.test.tsx.snap +3 -3
- package/src/__tests__/server-item-renderer.test.tsx +38 -1
- package/src/article-renderer.tsx +13 -15
- package/src/components.ts +0 -1
- package/src/dependencies.ts +4 -0
- package/src/index.ts +0 -1
- package/src/perseus-types.ts +2 -0
- package/src/server-item-renderer.tsx +26 -14
- package/src/styles/khan-exercise.css +0 -24
- package/src/styles/widgets/label-image.less +32 -0
- package/src/widgets/__stories__/label-image.stories.tsx +73 -3
- package/src/widgets/__testdata__/label-image.testdata.ts +118 -1
- package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +2 -2
- package/src/widgets/label-image/__stories__/answer-pill.stories.tsx +62 -0
- package/src/widgets/label-image/__tests__/answer-pill.test.tsx +83 -0
- package/src/widgets/label-image/__tests__/hide-answers-toggle.test.tsx +39 -0
- package/src/widgets/label-image/answer-choices.tsx +7 -1
- package/src/widgets/label-image/answer-pill.tsx +89 -0
- package/src/widgets/label-image/hide-answers-toggle.tsx +40 -0
- package/src/widgets/label-image/marker.tsx +116 -174
- package/src/widgets/label-image/types.ts +1 -0
- package/src/widgets/label-image.test.ts +142 -52
- package/src/widgets/label-image.tsx +212 -135
- package/tsconfig-build.tsbuildinfo +1 -1
- package/dist/components/tex-buttons.d.ts +0 -25
- package/dist/item-renderer.d.ts +0 -125
- package/dist/mixins/provide-keypad.d.ts +0 -39
- package/src/__stories__/item-renderer.stories.tsx +0 -30
- package/src/__testdata__/item-renderer.testdata.ts +0 -299
- package/src/__tests__/__snapshots__/item-renderer.test.tsx.snap +0 -224
- package/src/__tests__/item-renderer.test.tsx +0 -930
- package/src/components/__stories__/text-buttons.stories.tsx +0 -54
- package/src/components/tex-buttons.tsx +0 -334
- package/src/item-renderer.tsx +0 -529
- package/src/mixins/provide-keypad.tsx +0 -137
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
InputNumberWidget,
|
|
3
|
+
LabelImageWidget,
|
|
4
|
+
PerseusItem,
|
|
5
|
+
PerseusRenderer,
|
|
6
|
+
} from "../perseus-types";
|
|
7
|
+
|
|
8
|
+
export const itemWithInput: PerseusItem = {
|
|
9
|
+
question: {
|
|
10
|
+
content:
|
|
11
|
+
"Enter the number $$-42$$ in the box: [[\u2603 input-number 1]]",
|
|
12
|
+
images: {},
|
|
13
|
+
widgets: {
|
|
14
|
+
"input-number 1": {
|
|
15
|
+
type: "input-number",
|
|
16
|
+
graded: true,
|
|
17
|
+
options: {
|
|
18
|
+
answerType: "number",
|
|
19
|
+
value: "-42",
|
|
20
|
+
simplify: "required",
|
|
21
|
+
size: "normal",
|
|
22
|
+
inexact: false,
|
|
23
|
+
maxError: 0.1,
|
|
24
|
+
},
|
|
25
|
+
} as InputNumberWidget,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
hints: [
|
|
29
|
+
{content: "Hint #1", images: {}, widgets: {}},
|
|
30
|
+
{content: "Hint #2", images: {}, widgets: {}},
|
|
31
|
+
{content: "Hint #3", images: {}, widgets: {}},
|
|
32
|
+
],
|
|
33
|
+
answerArea: null,
|
|
34
|
+
_multi: null,
|
|
35
|
+
itemDataVersion: {major: 0, minor: 0},
|
|
36
|
+
answer: null,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const labelImageItem: PerseusItem = {
|
|
40
|
+
answerArea: {
|
|
41
|
+
calculator: false,
|
|
42
|
+
chi2Table: false,
|
|
43
|
+
periodicTable: false,
|
|
44
|
+
tTable: false,
|
|
45
|
+
zTable: false,
|
|
46
|
+
},
|
|
47
|
+
_multi: null,
|
|
48
|
+
answer: null,
|
|
49
|
+
hints: [],
|
|
50
|
+
itemDataVersion: {major: 0, minor: 1},
|
|
51
|
+
question: {
|
|
52
|
+
content:
|
|
53
|
+
"Catherine created a chart and a bar graph to show how many dogs of each breed the animal shelter placed into good homes last year. \n\nDog breed | Number of dogs \n:- | :-: \nBulldog | $32$ \nGreyhound | $72$ \nMastiff | $56$ \nCollie | $40$ \n\n**Label each bar on the bar graph.**\n\n[[☃ label-image 1]]\n\n\n\n",
|
|
54
|
+
images: {
|
|
55
|
+
"web+graphie://ka-perseus-graphie.s3.amazonaws.com/2f60b533892fe6cb9351f704ffdada8ae4bc655c":
|
|
56
|
+
{height: 365, width: 503},
|
|
57
|
+
"web+graphie://ka-perseus-graphie.s3.amazonaws.com/75f937c6ea133d655dd9f698a58182efd6cc85d4":
|
|
58
|
+
{height: 293, width: 331},
|
|
59
|
+
},
|
|
60
|
+
widgets: {
|
|
61
|
+
"label-image 1": {
|
|
62
|
+
alignment: "default",
|
|
63
|
+
graded: true,
|
|
64
|
+
static: false,
|
|
65
|
+
type: "label-image",
|
|
66
|
+
version: {major: 0, minor: 0},
|
|
67
|
+
options: {
|
|
68
|
+
choices: ["Bulldog", "Greyhound", "Mastiff", "Collie"],
|
|
69
|
+
hideChoicesFromInstructions: true,
|
|
70
|
+
imageAlt:
|
|
71
|
+
"A bar graph with four bar lines shows the horizontal axis labeled Dog breed and the vertical axis labeled Number of dogs. The vertical axis is labeled from the bottom of the axis to the top of the axis as follows: 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, and 80. The horizontal axis has, from left to right, four unlabeled bar lines as follows: the first unlabeled bar line extends to 56, the second unlabeled bar line extends to 72, the third unlabeled bar line extends to 40, and the fourth unlabeled bar line extends to 32.",
|
|
72
|
+
imageHeight: 293,
|
|
73
|
+
imageUrl:
|
|
74
|
+
"web+graphie://ka-perseus-graphie.s3.amazonaws.com/64ace45942546183c3dc842cb0e9e4f64a312727",
|
|
75
|
+
imageWidth: 331,
|
|
76
|
+
markers: [
|
|
77
|
+
{
|
|
78
|
+
answers: ["Bulldog"],
|
|
79
|
+
label: "The fourth unlabeled bar line.",
|
|
80
|
+
x: 87.3,
|
|
81
|
+
y: 90.2,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
answers: ["Collie"],
|
|
85
|
+
label: "The third unlabeled bar line.",
|
|
86
|
+
x: 67.7,
|
|
87
|
+
y: 90.5,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
answers: ["Greyhound"],
|
|
91
|
+
label: "The second unlabeled bar line.",
|
|
92
|
+
x: 47.7,
|
|
93
|
+
y: 90.2,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
answers: ["Mastiff"],
|
|
97
|
+
label: "The first unlabeled bar line.",
|
|
98
|
+
x: 27.8,
|
|
99
|
+
y: 90.5,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
multipleAnswers: false,
|
|
103
|
+
static: false,
|
|
104
|
+
},
|
|
105
|
+
} as LabelImageWidget,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Note that if this item is used, you _must_ first register the MockWidget
|
|
111
|
+
export const mockedItem: PerseusItem = {
|
|
112
|
+
// The mock widget type is not part of the PerseusWidget type union (and
|
|
113
|
+
// we don't want to make it such to avoid polluting our production types
|
|
114
|
+
// for test purposes) so we force TypeScript to accept it here.
|
|
115
|
+
// @ts-expect-error - TS2352 - Conversion of type '{ content: string; images: {}; widgets: { "mock-widget 1": { graded: true; version: { major: number; minor: number; }; static: false; type: "mock-widget"; options: { static: false; smiling: boolean; }; alignment: string; }; "mock-widget 2": { ...; }; "mock-widget 3": { ...; }; "mock-widget 4": { ...; }; }; }' to type 'PerseusRenderer' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
|
116
|
+
question: {
|
|
117
|
+
content:
|
|
118
|
+
"Mock widget ==> [[\u2603 mock-widget 1]] [[\u2603 mock-widget 2]] [[\u2603 mock-widget 3]] [[\u2603 mock-widget 4]]",
|
|
119
|
+
images: {},
|
|
120
|
+
widgets: {
|
|
121
|
+
"mock-widget 1": {
|
|
122
|
+
graded: true,
|
|
123
|
+
version: {major: 0, minor: 0},
|
|
124
|
+
static: false,
|
|
125
|
+
type: "mock-widget",
|
|
126
|
+
options: {static: false, smiling: true},
|
|
127
|
+
alignment: "default",
|
|
128
|
+
},
|
|
129
|
+
"mock-widget 2": {
|
|
130
|
+
graded: true,
|
|
131
|
+
version: {major: 0, minor: 0},
|
|
132
|
+
static: false,
|
|
133
|
+
type: "mock-widget",
|
|
134
|
+
options: {static: false, smiling: false},
|
|
135
|
+
alignment: "default",
|
|
136
|
+
},
|
|
137
|
+
"mock-widget 3": {
|
|
138
|
+
graded: true,
|
|
139
|
+
version: {major: 0, minor: 0},
|
|
140
|
+
static: false,
|
|
141
|
+
type: "mock-widget",
|
|
142
|
+
options: {static: false, smiling: true},
|
|
143
|
+
alignment: "default",
|
|
144
|
+
},
|
|
145
|
+
"mock-widget 4": {
|
|
146
|
+
graded: true,
|
|
147
|
+
version: {major: 0, minor: 0},
|
|
148
|
+
static: false,
|
|
149
|
+
type: "mock-widget",
|
|
150
|
+
options: {static: false, smiling: false},
|
|
151
|
+
alignment: "default",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
} as PerseusRenderer,
|
|
155
|
+
hints: [],
|
|
156
|
+
answerArea: null,
|
|
157
|
+
_multi: null,
|
|
158
|
+
itemDataVersion: {major: 0, minor: 0},
|
|
159
|
+
answer: null,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export const itemWithLintingError: PerseusItem = {
|
|
163
|
+
question: {
|
|
164
|
+
content: "# h1s aren't allowed",
|
|
165
|
+
images: {},
|
|
166
|
+
widgets: {},
|
|
167
|
+
},
|
|
168
|
+
hints: [],
|
|
169
|
+
answerArea: null,
|
|
170
|
+
_multi: null,
|
|
171
|
+
itemDataVersion: {major: 0, minor: 0},
|
|
172
|
+
answer: null,
|
|
173
|
+
};
|
|
@@ -369,7 +369,7 @@ exports[`renderer snapshots correct answer: correct answer 1`] = `
|
|
|
369
369
|
</span>
|
|
370
370
|
<span
|
|
371
371
|
aria-hidden="true"
|
|
372
|
-
class="
|
|
372
|
+
class="svg_1q6jc65-o_O-icon_eocf2p-o_O-caret_ntkmq-o_O-inlineStyles_u7ovp6"
|
|
373
373
|
/>
|
|
374
374
|
</button>
|
|
375
375
|
</div>
|
|
@@ -434,7 +434,7 @@ exports[`renderer snapshots incorrect answer: incorrect answer 1`] = `
|
|
|
434
434
|
</span>
|
|
435
435
|
<span
|
|
436
436
|
aria-hidden="true"
|
|
437
|
-
class="
|
|
437
|
+
class="svg_1q6jc65-o_O-icon_eocf2p-o_O-caret_ntkmq-o_O-inlineStyles_u7ovp6"
|
|
438
438
|
/>
|
|
439
439
|
</button>
|
|
440
440
|
</div>
|
|
@@ -499,7 +499,7 @@ exports[`renderer snapshots initial render: initial render 1`] = `
|
|
|
499
499
|
</span>
|
|
500
500
|
<span
|
|
501
501
|
aria-hidden="true"
|
|
502
|
-
class="
|
|
502
|
+
class="svg_1q6jc65-o_O-icon_eocf2p-o_O-caret_ntkmq-o_O-inlineStyles_u7ovp6"
|
|
503
503
|
/>
|
|
504
504
|
</button>
|
|
505
505
|
</div>
|
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
} from "../../../../testing/test-dependencies";
|
|
11
11
|
import {
|
|
12
12
|
itemWithInput,
|
|
13
|
+
itemWithLintingError,
|
|
13
14
|
mockedItem,
|
|
14
|
-
} from "../__testdata__/item-renderer.testdata";
|
|
15
|
+
} from "../__testdata__/server-item-renderer.testdata";
|
|
15
16
|
import * as Dependencies from "../dependencies";
|
|
16
17
|
import WrappedServerItemRenderer, {
|
|
17
18
|
ServerItemRenderer,
|
|
@@ -529,4 +530,40 @@ describe("server item renderer", () => {
|
|
|
529
530
|
expect(screen.getByRole("textbox")).toHaveValue("-42");
|
|
530
531
|
});
|
|
531
532
|
});
|
|
533
|
+
|
|
534
|
+
describe("content editing", () => {
|
|
535
|
+
it("shouldn't show linting errors when highlightLint is false", () => {
|
|
536
|
+
// Arrange and Act
|
|
537
|
+
renderQuestion(itemWithLintingError, undefined, {
|
|
538
|
+
linterContext: {
|
|
539
|
+
contentType: "exercise",
|
|
540
|
+
highlightLint: false,
|
|
541
|
+
paths: [],
|
|
542
|
+
stack: [],
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
expect(
|
|
547
|
+
screen.queryByText("Don't use level-1 headings", {
|
|
548
|
+
exact: false,
|
|
549
|
+
}),
|
|
550
|
+
).not.toBeInTheDocument();
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it("should show linting errors when highlightLint is true", () => {
|
|
554
|
+
// Arrange and Act
|
|
555
|
+
renderQuestion(itemWithLintingError, undefined, {
|
|
556
|
+
linterContext: {
|
|
557
|
+
contentType: "exercise",
|
|
558
|
+
highlightLint: true,
|
|
559
|
+
paths: [],
|
|
560
|
+
stack: [],
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
expect(
|
|
565
|
+
screen.getByText("Don't use level-1 headings", {exact: false}),
|
|
566
|
+
).toBeInTheDocument();
|
|
567
|
+
});
|
|
568
|
+
});
|
|
532
569
|
});
|
package/src/article-renderer.tsx
CHANGED
|
@@ -12,27 +12,25 @@ import {ClassNames as ApiClassNames, ApiOptions} from "./perseus-api";
|
|
|
12
12
|
import Renderer from "./renderer";
|
|
13
13
|
import Util from "./util";
|
|
14
14
|
|
|
15
|
-
import type {KeypadProps} from "./mixins/provide-keypad";
|
|
16
15
|
import type {PerseusRenderer} from "./perseus-types";
|
|
17
16
|
import type {APIOptions, PerseusDependenciesV2} from "./types";
|
|
18
17
|
import type {KeypadAPI} from "@khanacademy/math-input";
|
|
19
18
|
import type {KeypadContextRendererInterface} from "@khanacademy/perseus-core";
|
|
20
19
|
import type {LinterContextProps} from "@khanacademy/perseus-linter";
|
|
21
20
|
|
|
22
|
-
type Props = Partial<React.ContextType<typeof DependenciesContext>> &
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
21
|
+
type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
|
|
22
|
+
apiOptions: APIOptions;
|
|
23
|
+
json: PerseusRenderer | ReadonlyArray<PerseusRenderer>;
|
|
24
|
+
// Whether to use the new Bibliotron styles for articles
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Does nothing
|
|
27
|
+
*/
|
|
28
|
+
useNewStyles: boolean;
|
|
29
|
+
linterContext: LinterContextProps;
|
|
30
|
+
legacyPerseusLint?: ReadonlyArray<string>;
|
|
31
|
+
keypadElement?: KeypadAPI | null | undefined;
|
|
32
|
+
dependencies: PerseusDependenciesV2;
|
|
33
|
+
};
|
|
36
34
|
|
|
37
35
|
type DefaultProps = {
|
|
38
36
|
apiOptions: Props["apiOptions"];
|
package/src/components.ts
CHANGED
|
@@ -12,5 +12,4 @@ export {default as PropCheckBox} from "./components/prop-check-box";
|
|
|
12
12
|
export {default as RangeInput} from "./components/range-input";
|
|
13
13
|
export {default as SvgImage} from "./components/svg-image";
|
|
14
14
|
export {default as TextInput} from "./components/text-input";
|
|
15
|
-
export {default as TexButtons} from "./components/tex-buttons";
|
|
16
15
|
export {default as TextListEditor} from "./components/text-list-editor";
|
package/src/dependencies.ts
CHANGED
|
@@ -22,6 +22,10 @@ export const getDependencies = (): PerseusDependencies => {
|
|
|
22
22
|
);
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
export type DependencyProps = Partial<
|
|
26
|
+
React.ContextType<typeof DependenciesContext>
|
|
27
|
+
>;
|
|
28
|
+
|
|
25
29
|
export const DependenciesContext = React.createContext<PerseusDependenciesV2>({
|
|
26
30
|
analytics: {onAnalyticsEvent: async () => {}},
|
|
27
31
|
});
|
package/src/index.ts
CHANGED
|
@@ -14,7 +14,6 @@ export {default as itemVersion} from "./item-version";
|
|
|
14
14
|
* Renderers
|
|
15
15
|
*/
|
|
16
16
|
export {default as ArticleRenderer} from "./article-renderer";
|
|
17
|
-
export {default as ItemRenderer} from "./item-renderer";
|
|
18
17
|
export {default as ServerItemRenderer} from "./server-item-renderer";
|
|
19
18
|
export {default as HintsRenderer} from "./hints-renderer";
|
|
20
19
|
export {default as HintRenderer} from "./hint-renderer";
|
package/src/perseus-types.ts
CHANGED
|
@@ -73,6 +73,8 @@ export type PerseusAnswerArea = {
|
|
|
73
73
|
calculator: boolean;
|
|
74
74
|
// The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
|
|
75
75
|
periodicTable: boolean;
|
|
76
|
+
// The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
|
|
77
|
+
periodicTableWithKey?: boolean;
|
|
76
78
|
};
|
|
77
79
|
|
|
78
80
|
type Widget<Type extends string, Options> = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
2
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
2
3
|
import {StyleSheet, css} from "aphrodite";
|
|
3
4
|
/**
|
|
4
5
|
* A copy of the ItemRenderer which renders its question renderer and hints
|
|
@@ -20,7 +21,6 @@ import {ApiOptions} from "./perseus-api";
|
|
|
20
21
|
import Renderer from "./renderer";
|
|
21
22
|
import Util from "./util";
|
|
22
23
|
|
|
23
|
-
import type {KeypadProps} from "./mixins/provide-keypad";
|
|
24
24
|
import type {APIOptions, FocusPath, PerseusDependenciesV2} from "./types";
|
|
25
25
|
import type {KeypadAPI} from "@khanacademy/math-input";
|
|
26
26
|
import type {
|
|
@@ -28,22 +28,24 @@ import type {
|
|
|
28
28
|
RendererInterface,
|
|
29
29
|
KEScore,
|
|
30
30
|
} from "@khanacademy/perseus-core";
|
|
31
|
+
import type {LinterContextProps} from "@khanacademy/perseus-linter";
|
|
32
|
+
import type {PropsFor} from "@khanacademy/wonder-blocks-core";
|
|
31
33
|
|
|
32
34
|
const {mapObject} = Objective;
|
|
33
35
|
|
|
34
|
-
type OwnProps =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
question: any;
|
|
41
|
-
};
|
|
42
|
-
problemNum?: number;
|
|
43
|
-
reviewMode?: boolean;
|
|
44
|
-
keypadElement?: KeypadAPI | null | undefined;
|
|
45
|
-
dependencies: PerseusDependenciesV2;
|
|
36
|
+
type OwnProps = {
|
|
37
|
+
apiOptions: APIOptions;
|
|
38
|
+
hintsVisible?: number;
|
|
39
|
+
item: {
|
|
40
|
+
hints: ReadonlyArray<any>;
|
|
41
|
+
question: any;
|
|
46
42
|
};
|
|
43
|
+
linterContext: LinterContextProps;
|
|
44
|
+
problemNum?: number;
|
|
45
|
+
reviewMode?: boolean;
|
|
46
|
+
keypadElement?: KeypadAPI | null | undefined;
|
|
47
|
+
dependencies: PerseusDependenciesV2;
|
|
48
|
+
};
|
|
47
49
|
|
|
48
50
|
type HOCProps = {
|
|
49
51
|
onRendered: (isRendered: boolean) => void;
|
|
@@ -54,6 +56,7 @@ type Props = OwnProps & HOCProps;
|
|
|
54
56
|
type DefaultProps = {
|
|
55
57
|
apiOptions: Props["apiOptions"];
|
|
56
58
|
onRendered: Props["onRendered"];
|
|
59
|
+
linterContext: Props["linterContext"];
|
|
57
60
|
};
|
|
58
61
|
|
|
59
62
|
type State = {
|
|
@@ -85,6 +88,7 @@ export class ServerItemRenderer
|
|
|
85
88
|
|
|
86
89
|
static defaultProps: DefaultProps = {
|
|
87
90
|
apiOptions: {} as any, // a deep default is done in `this.update()`
|
|
91
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
88
92
|
onRendered: (isRendered: boolean) => {},
|
|
89
93
|
};
|
|
90
94
|
|
|
@@ -417,6 +421,10 @@ export class ServerItemRenderer
|
|
|
417
421
|
content={this.props.item.question.content}
|
|
418
422
|
widgets={this.props.item.question.widgets}
|
|
419
423
|
images={this.props.item.question.images}
|
|
424
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
425
|
+
this.props.linterContext,
|
|
426
|
+
"question",
|
|
427
|
+
)}
|
|
420
428
|
{...this.props.dependencies}
|
|
421
429
|
/>
|
|
422
430
|
</AssetContext.Provider>
|
|
@@ -428,6 +436,10 @@ export class ServerItemRenderer
|
|
|
428
436
|
hintsVisible={this.props.hintsVisible}
|
|
429
437
|
apiOptions={apiOptions}
|
|
430
438
|
ref={(elem) => (this.hintsRenderer = elem)}
|
|
439
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
440
|
+
this.props.linterContext,
|
|
441
|
+
"hints",
|
|
442
|
+
)}
|
|
431
443
|
/>
|
|
432
444
|
);
|
|
433
445
|
|
|
@@ -462,7 +474,7 @@ const styles = StyleSheet.create({
|
|
|
462
474
|
|
|
463
475
|
const ref = React.forwardRef<
|
|
464
476
|
ServerItemRenderer,
|
|
465
|
-
Omit<
|
|
477
|
+
Omit<PropsFor<typeof ServerItemRenderer>, "onRendered">
|
|
466
478
|
>((props, ref) => (
|
|
467
479
|
<LoadingContext.Consumer>
|
|
468
480
|
{({onRendered}) => (
|
|
@@ -675,30 +675,6 @@ div.timeline-total {
|
|
|
675
675
|
width: 100px;
|
|
676
676
|
}
|
|
677
677
|
|
|
678
|
-
#previous-step {
|
|
679
|
-
margin: 5px;
|
|
680
|
-
cursor: pointer;
|
|
681
|
-
float: left;
|
|
682
|
-
width: 100px;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
#next-step {
|
|
686
|
-
margin: 5px;
|
|
687
|
-
cursor: pointer;
|
|
688
|
-
float: right;
|
|
689
|
-
width: 80px;
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
#previous-step span {
|
|
693
|
-
background: url(/images/previous-step.png) no-repeat 0 50% transparent;
|
|
694
|
-
padding: 4px 0 4px 25px;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
#next-step span {
|
|
698
|
-
background: url(/images/next-step.png) no-repeat 100% 50% transparent;
|
|
699
|
-
padding: 4px 25px 4px 0;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
678
|
#next-problem {
|
|
703
679
|
margin: 5px;
|
|
704
680
|
cursor: pointer;
|
|
@@ -5,6 +5,38 @@
|
|
|
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
|
+
}
|
|
21
|
+
|
|
22
|
+
// Reset mobile text content for answer pills.
|
|
23
|
+
@media (max-width: 767px) {
|
|
24
|
+
[id*="perseus-label-image-widget-answer-pill"] {
|
|
25
|
+
div.paragraph {
|
|
26
|
+
all: revert;
|
|
27
|
+
}
|
|
28
|
+
> div.perseus-renderer-responsive {
|
|
29
|
+
all: revert;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.framework-perseus.perseus-mobile
|
|
34
|
+
[id*="perseus-label-image-widget-answer-pill"] {
|
|
35
|
+
.perseus-renderer > .paragraph,
|
|
36
|
+
.perseus-renderer > .paragraph .paragraph {
|
|
37
|
+
all: revert;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
8
40
|
}
|
|
9
41
|
|
|
10
42
|
.framework-perseus:not(.perseus-article).perseus-mobile {
|
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
import {RendererWithDebugUI} from "../../../../../testing/renderer-with-debug-ui";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
textQuestion,
|
|
6
|
+
mathQuestion,
|
|
7
|
+
numberline,
|
|
8
|
+
} from "../__testdata__/label-image.testdata";
|
|
5
9
|
|
|
10
|
+
import type {PerseusRenderer} from "../../perseus-types";
|
|
6
11
|
import type {APIOptions} from "../../types";
|
|
7
12
|
|
|
13
|
+
const applyStoryArgs = (
|
|
14
|
+
question: PerseusRenderer,
|
|
15
|
+
args: StoryArgs,
|
|
16
|
+
): PerseusRenderer => {
|
|
17
|
+
const q = {
|
|
18
|
+
...question,
|
|
19
|
+
widgets: {},
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
for (const [widgetId, widget] of Object.entries(question.widgets)) {
|
|
23
|
+
const modified = {
|
|
24
|
+
...widget,
|
|
25
|
+
options: {
|
|
26
|
+
...widget.options,
|
|
27
|
+
preferredPopoverDirection: args.preferredPopoverDirection,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
q.widgets[widgetId] = {
|
|
32
|
+
...modified,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return q;
|
|
37
|
+
};
|
|
38
|
+
|
|
8
39
|
type StoryArgs = {
|
|
9
40
|
isMobile: boolean;
|
|
41
|
+
preferredPopoverDirection: string;
|
|
10
42
|
};
|
|
11
43
|
|
|
12
44
|
type ImageStory = {
|
|
@@ -14,17 +46,55 @@ type ImageStory = {
|
|
|
14
46
|
args: StoryArgs;
|
|
15
47
|
};
|
|
16
48
|
|
|
17
|
-
export const
|
|
49
|
+
export const LabelWidgetWithText = (args: StoryArgs): React.ReactElement => {
|
|
50
|
+
const apiOptions: APIOptions = {
|
|
51
|
+
isMobile: args.isMobile,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<RendererWithDebugUI
|
|
56
|
+
question={applyStoryArgs(textQuestion, args)}
|
|
57
|
+
apiOptions={apiOptions}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const LabelWidgetWithMath = (args: StoryArgs): React.ReactElement => {
|
|
18
63
|
const apiOptions: APIOptions = {
|
|
19
64
|
isMobile: args.isMobile,
|
|
20
65
|
};
|
|
21
66
|
|
|
22
|
-
return
|
|
67
|
+
return (
|
|
68
|
+
<RendererWithDebugUI
|
|
69
|
+
question={applyStoryArgs(mathQuestion, args)}
|
|
70
|
+
apiOptions={apiOptions}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const LabelImageNumberline = (args: StoryArgs): React.ReactElement => {
|
|
76
|
+
const apiOptions: APIOptions = {
|
|
77
|
+
isMobile: args.isMobile,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<RendererWithDebugUI
|
|
82
|
+
question={applyStoryArgs(numberline, args)}
|
|
83
|
+
apiOptions={apiOptions}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
23
86
|
};
|
|
24
87
|
|
|
25
88
|
export default {
|
|
26
89
|
title: "Perseus/Widgets/Label Image",
|
|
27
90
|
args: {
|
|
28
91
|
isMobile: false,
|
|
92
|
+
preferredPopoverDirection: "NONE",
|
|
93
|
+
},
|
|
94
|
+
argTypes: {
|
|
95
|
+
preferredPopoverDirection: {
|
|
96
|
+
control: "select",
|
|
97
|
+
options: ["NONE", "UP", "DOWN", "LEFT", "RIGHT"],
|
|
98
|
+
},
|
|
29
99
|
},
|
|
30
100
|
} as ImageStory;
|