@khanacademy/perseus 5.0.0 → 6.0.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/components/fixed-to-responsive.d.ts +27 -1
- package/dist/components/fixed-to-responsive.js.flow +27 -1
- package/dist/components/graph.d.ts +42 -26
- package/dist/components/graph.js.flow +42 -28
- package/dist/components/graphie.d.ts +34 -22
- package/dist/components/graphie.js.flow +37 -24
- package/dist/components/hud.d.ts +8 -14
- package/dist/components/hud.js.flow +7 -14
- package/dist/components/inline-icon.d.ts +9 -19
- package/dist/components/inline-icon.js.flow +26 -13
- package/dist/components/lint.d.ts +41 -13
- package/dist/components/lint.js.flow +42 -13
- package/dist/components/math-output.d.ts +15 -11
- package/dist/components/math-output.js.flow +15 -11
- package/dist/components/sortable.d.ts +17 -9
- package/dist/components/sortable.js.flow +22 -9
- package/dist/components/svg-image.d.ts +5 -3
- package/dist/components/svg-image.js.flow +5 -3
- package/dist/components/tooltip.d.ts +45 -4
- package/dist/components/tooltip.js.flow +44 -31
- package/dist/es/index.css +0 -3
- package/dist/es/index.js +477 -648
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +0 -3
- package/dist/index.js +481 -645
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +11 -9
- package/dist/perseus-types.js.flow +11 -9
- package/dist/renderer.d.ts +2 -2
- package/dist/renderer.js.flow +1 -3
- package/dist/styles/shared.d.ts +0 -1
- package/dist/styles/shared.js.flow +0 -1
- package/dist/types.d.ts +0 -10
- package/dist/types.js.flow +0 -13
- package/dist/util/a11y.d.ts +0 -1
- package/dist/util/a11y.js.flow +0 -1
- package/dist/util/interactive.d.ts +2 -0
- package/dist/util/interactive.js.flow +2 -0
- package/dist/util.d.ts +3 -3
- package/dist/util.js.flow +4 -3
- package/dist/widgets/grapher.d.ts +1 -1
- package/dist/widgets/grapher.js.flow +12 -3
- package/dist/widgets/matcher.d.ts +7 -3
- package/dist/widgets/matcher.js.flow +7 -3
- package/dist/widgets/number-line.d.ts +1 -1
- package/dist/widgets/number-line.js.flow +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/item-renderer.test.tsx.snap +151 -159
- package/src/__tests__/__snapshots__/renderer.test.tsx.snap +358 -394
- package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +169 -189
- package/src/components/__stories__/lint.stories.tsx +56 -21
- package/src/components/__stories__/sortable.stories.tsx +5 -5
- package/src/components/__stories__/tooltip.stories.tsx +52 -0
- package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +114 -30
- package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +172 -204
- package/src/components/__tests__/sortable.test.tsx +54 -16
- package/src/components/__tests__/sorter.test.tsx +12 -9
- package/src/components/fixed-to-responsive.tsx +43 -38
- package/src/components/graph.tsx +95 -81
- package/src/components/graphie.tsx +62 -32
- package/src/components/hud.tsx +104 -115
- package/src/components/inline-icon.tsx +15 -32
- package/src/components/input-with-examples.tsx +4 -4
- package/src/components/lint.tsx +47 -41
- package/src/components/math-output.tsx +17 -11
- package/src/components/simple-keypad-input.tsx +2 -2
- package/src/components/sortable.tsx +134 -94
- package/src/components/svg-image.tsx +10 -11
- package/src/components/tooltip.tsx +189 -171
- package/src/interactive2/types.ts +2 -2
- package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +708 -764
- package/src/perseus-types.ts +13 -9
- package/src/renderer.tsx +11 -22
- package/src/types.ts +0 -18
- package/src/util/interactive.ts +18 -5
- package/src/util/tex.ts +13 -77
- package/src/util.ts +3 -4
- package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +717 -773
- package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +28 -36
- package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +52 -60
- package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +100 -108
- package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +212 -260
- package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +613 -641
- package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +249 -261
- package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +671 -735
- package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +2676 -2684
- package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +938 -1002
- package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +28 -36
- package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +227 -255
- package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +353 -357
- package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +255 -259
- package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +2401 -2433
- package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +600 -756
- package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +420 -428
- package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +762 -770
- package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +373 -393
- package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +116 -148
- package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +289 -301
- package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +1679 -1711
- package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +2692 -2960
- package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +90 -98
- package/src/widgets/__tests__/matcher.test.tsx +33 -9
- package/src/widgets/expression.tsx +9 -6
- package/src/widgets/grapher.tsx +3 -3
- package/src/widgets/image.tsx +2 -2
- package/src/widgets/interactive-graph.tsx +5 -5
- package/src/widgets/matcher.tsx +43 -24
- package/src/widgets/number-line.tsx +1 -1
- package/src/widgets/simulator.tsx +4 -6
- package/{tsconfig.json → tsconfig-build.json} +6 -6
- package/tsconfig-build.tsbuildinfo +1 -0
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -4,7 +4,7 @@ import "@testing-library/jest-dom"; // Imports custom mathers
|
|
|
4
4
|
|
|
5
5
|
import {testDependencies} from "../../../../../testing/test-dependencies";
|
|
6
6
|
import * as Dependencies from "../../dependencies";
|
|
7
|
-
import Sortable from "../sortable";
|
|
7
|
+
import Sortable, {Layout} from "../sortable";
|
|
8
8
|
|
|
9
9
|
describe("Sortable", () => {
|
|
10
10
|
beforeEach(() => {
|
|
@@ -17,15 +17,53 @@ describe("Sortable", () => {
|
|
|
17
17
|
// Arrange and Act
|
|
18
18
|
const {container} = render(
|
|
19
19
|
<Sortable
|
|
20
|
-
layout=
|
|
20
|
+
layout={Layout.HORIZONTAL}
|
|
21
21
|
options={["a", "b", "c"]}
|
|
22
|
-
|
|
22
|
+
waitForTexRendererToLoad={false}
|
|
23
23
|
/>,
|
|
24
24
|
);
|
|
25
25
|
|
|
26
26
|
// Assert
|
|
27
27
|
expect(container).toMatchSnapshot("first render");
|
|
28
28
|
});
|
|
29
|
+
|
|
30
|
+
it("renders a spinner while waiting for the TeX renderer to load", () => {
|
|
31
|
+
let simulateFakeTeXRendering = () => {};
|
|
32
|
+
function FakeTeX({
|
|
33
|
+
children,
|
|
34
|
+
onRender,
|
|
35
|
+
}: {
|
|
36
|
+
children: string;
|
|
37
|
+
onRender?: () => unknown;
|
|
38
|
+
}) {
|
|
39
|
+
simulateFakeTeXRendering = onRender || simulateFakeTeXRendering;
|
|
40
|
+
return <div className="fake-tex">{children}</div>;
|
|
41
|
+
}
|
|
42
|
+
jest.spyOn(Dependencies, "getDependencies").mockReturnValue({
|
|
43
|
+
...testDependencies,
|
|
44
|
+
TeX: FakeTeX,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Act
|
|
48
|
+
const {container} = render(
|
|
49
|
+
<Sortable
|
|
50
|
+
waitForTexRendererToLoad={true}
|
|
51
|
+
layout={Layout.HORIZONTAL}
|
|
52
|
+
options={["a", "b", "c"]}
|
|
53
|
+
/>,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Assert
|
|
57
|
+
expect(container).toMatchSnapshot("first render: displays a spinner");
|
|
58
|
+
|
|
59
|
+
// Act
|
|
60
|
+
simulateFakeTeXRendering();
|
|
61
|
+
|
|
62
|
+
// Assert
|
|
63
|
+
expect(container).toMatchSnapshot(
|
|
64
|
+
"second render: displays the sortable",
|
|
65
|
+
);
|
|
66
|
+
});
|
|
29
67
|
});
|
|
30
68
|
|
|
31
69
|
describe("moveOptionToIndex", () => {
|
|
@@ -41,9 +79,9 @@ describe("moveOptionToIndex", () => {
|
|
|
41
79
|
render(
|
|
42
80
|
<Sortable
|
|
43
81
|
ref={(r) => (sortable = r)}
|
|
44
|
-
layout=
|
|
82
|
+
layout={Layout.HORIZONTAL}
|
|
45
83
|
options={["a", "b", "c"]}
|
|
46
|
-
|
|
84
|
+
waitForTexRendererToLoad={false}
|
|
47
85
|
/>,
|
|
48
86
|
);
|
|
49
87
|
|
|
@@ -64,9 +102,9 @@ describe("moveOptionToIndex", () => {
|
|
|
64
102
|
render(
|
|
65
103
|
<Sortable
|
|
66
104
|
ref={(r) => (sortable = r)}
|
|
67
|
-
layout=
|
|
105
|
+
layout={Layout.HORIZONTAL}
|
|
68
106
|
options={["a", "b", "c"]}
|
|
69
|
-
|
|
107
|
+
waitForTexRendererToLoad={false}
|
|
70
108
|
/>,
|
|
71
109
|
);
|
|
72
110
|
|
|
@@ -85,9 +123,9 @@ describe("moveOptionToIndex", () => {
|
|
|
85
123
|
render(
|
|
86
124
|
<Sortable
|
|
87
125
|
ref={(r) => (sortable = r)}
|
|
88
|
-
layout=
|
|
126
|
+
layout={Layout.HORIZONTAL}
|
|
89
127
|
options={["a", "b", "c"]}
|
|
90
|
-
|
|
128
|
+
waitForTexRendererToLoad={false}
|
|
91
129
|
/>,
|
|
92
130
|
);
|
|
93
131
|
|
|
@@ -106,9 +144,9 @@ describe("moveOptionToIndex", () => {
|
|
|
106
144
|
render(
|
|
107
145
|
<Sortable
|
|
108
146
|
ref={(r) => (sortable = r)}
|
|
109
|
-
layout=
|
|
147
|
+
layout={Layout.HORIZONTAL}
|
|
110
148
|
options={["a", "b", "c"]}
|
|
111
|
-
|
|
149
|
+
waitForTexRendererToLoad={false}
|
|
112
150
|
/>,
|
|
113
151
|
);
|
|
114
152
|
|
|
@@ -147,7 +185,7 @@ describe("Sortable.itemsFromProps", () => {
|
|
|
147
185
|
"height": 0,
|
|
148
186
|
"key": 0,
|
|
149
187
|
"option": "a",
|
|
150
|
-
"
|
|
188
|
+
"state": "static",
|
|
151
189
|
"width": 0,
|
|
152
190
|
},
|
|
153
191
|
{
|
|
@@ -155,7 +193,7 @@ describe("Sortable.itemsFromProps", () => {
|
|
|
155
193
|
"height": 0,
|
|
156
194
|
"key": 1,
|
|
157
195
|
"option": "b",
|
|
158
|
-
"
|
|
196
|
+
"state": "static",
|
|
159
197
|
"width": 0,
|
|
160
198
|
},
|
|
161
199
|
{
|
|
@@ -163,7 +201,7 @@ describe("Sortable.itemsFromProps", () => {
|
|
|
163
201
|
"height": 0,
|
|
164
202
|
"key": 2,
|
|
165
203
|
"option": "c",
|
|
166
|
-
"
|
|
204
|
+
"state": "static",
|
|
167
205
|
"width": 0,
|
|
168
206
|
},
|
|
169
207
|
]
|
|
@@ -182,7 +220,7 @@ describe("Sortable.itemsFromProps", () => {
|
|
|
182
220
|
|
|
183
221
|
// Assert
|
|
184
222
|
items.forEach((item) => {
|
|
185
|
-
expect(item.
|
|
223
|
+
expect(item.state).toBe("disabled");
|
|
186
224
|
});
|
|
187
225
|
});
|
|
188
226
|
it("sets the item type to static if disabled is false", () => {
|
|
@@ -197,7 +235,7 @@ describe("Sortable.itemsFromProps", () => {
|
|
|
197
235
|
|
|
198
236
|
// Assert
|
|
199
237
|
items.forEach((item) => {
|
|
200
|
-
expect(item.
|
|
238
|
+
expect(item.state).toBe("static");
|
|
201
239
|
});
|
|
202
240
|
});
|
|
203
241
|
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import getRenderA11yString from "katex/dist/contrib/render-a11y-string";
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
import "@testing-library/jest-dom";
|
|
4
3
|
|
|
@@ -22,15 +21,19 @@ describe("sorter widget", () => {
|
|
|
22
21
|
|
|
23
22
|
jest.spyOn(Dependencies, "getDependencies").mockReturnValue({
|
|
24
23
|
...testDependencies,
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
TeX: ({
|
|
25
|
+
children,
|
|
26
|
+
// alias onRender to onLoad to quiet the overzealous testing-library linter
|
|
27
|
+
onRender: onLoad,
|
|
28
|
+
}: {
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
onRender?: () => unknown;
|
|
31
|
+
}) => {
|
|
32
|
+
React.useLayoutEffect(() => {
|
|
33
|
+
onLoad?.();
|
|
34
|
+
}, [onLoad]);
|
|
35
|
+
return <span className="tex-mock">{children}</span>;
|
|
27
36
|
},
|
|
28
|
-
TeX: ({children}: {children: React.ReactNode}) => (
|
|
29
|
-
<span className="tex-mock">{children}</span>
|
|
30
|
-
),
|
|
31
|
-
// @ts-expect-error [FEI-5003] - TS2322 - Type 'Promise<any>' is not assignable to type '() => Promise<katexA11y>'.
|
|
32
|
-
getRenderA11yString: Promise.resolve(getRenderA11yString),
|
|
33
|
-
shouldUseFutureKaTeX: (flag: boolean) => {},
|
|
34
37
|
});
|
|
35
38
|
});
|
|
36
39
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable react/prop-types */
|
|
2
1
|
/**
|
|
3
2
|
* A wrapper for a component that would otherwise have a fixed width and
|
|
4
3
|
* height, that magically makes it reponsive while preserving its aspect ratio.
|
|
@@ -15,41 +14,47 @@
|
|
|
15
14
|
* </FixedToResponsive>
|
|
16
15
|
*/
|
|
17
16
|
import classNames from "classnames";
|
|
18
|
-
import createReactClass from "create-react-class";
|
|
19
|
-
import PropTypes from "prop-types";
|
|
20
17
|
import * as React from "react";
|
|
21
18
|
|
|
22
19
|
import {negativePhoneMargin} from "../styles/constants";
|
|
23
20
|
|
|
24
21
|
const MIN_VIEWPORT_HEIGHT = 480;
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
23
|
+
type Props = {
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
children: React.ReactNode;
|
|
27
|
+
className?: string;
|
|
28
|
+
constrainHeight?: boolean;
|
|
29
|
+
allowFullBleed?: boolean;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type DefaultProps = {
|
|
33
|
+
className: Props["className"];
|
|
34
|
+
constrainHeight: Props["constrainHeight"];
|
|
35
|
+
allowFullBleed: Props["allowFullBleed"];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type State = {
|
|
39
|
+
viewportHeight: number | null;
|
|
40
|
+
viewportWidth: number | null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
class FixedToResponsive extends React.Component<Props, State> {
|
|
44
|
+
_isMounted = false;
|
|
45
|
+
|
|
46
|
+
static defaultProps: DefaultProps = {
|
|
47
|
+
className: "",
|
|
48
|
+
constrainHeight: false,
|
|
49
|
+
allowFullBleed: false,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
state: State = {
|
|
53
|
+
viewportHeight: null,
|
|
54
|
+
viewportWidth: null,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
componentDidMount() {
|
|
53
58
|
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
54
59
|
// this.isMounted() but is still considered an anti-pattern.
|
|
55
60
|
this._isMounted = true;
|
|
@@ -70,13 +75,13 @@ const FixedToResponsive: any = createReactClass({
|
|
|
70
75
|
} else {
|
|
71
76
|
this._cacheViewportSize();
|
|
72
77
|
}
|
|
73
|
-
}
|
|
78
|
+
}
|
|
74
79
|
|
|
75
|
-
componentWillUnmount
|
|
80
|
+
componentWillUnmount() {
|
|
76
81
|
this._isMounted = false;
|
|
77
|
-
}
|
|
82
|
+
}
|
|
78
83
|
|
|
79
|
-
_cacheViewportSize:
|
|
84
|
+
_cacheViewportSize: () => void = (): void => {
|
|
80
85
|
if (this._isMounted) {
|
|
81
86
|
this.setState({
|
|
82
87
|
viewportHeight: Math.max(
|
|
@@ -86,9 +91,9 @@ const FixedToResponsive: any = createReactClass({
|
|
|
86
91
|
viewportWidth: window.innerWidth,
|
|
87
92
|
});
|
|
88
93
|
}
|
|
89
|
-
}
|
|
94
|
+
};
|
|
90
95
|
|
|
91
|
-
render
|
|
96
|
+
render() {
|
|
92
97
|
// The ideal behavior for responsified, fixed size child components is
|
|
93
98
|
// that they shrink when they need to (while preserving aspect ratio)
|
|
94
99
|
// but never grow larger than their original dimensions. We accomplish
|
|
@@ -158,7 +163,7 @@ const FixedToResponsive: any = createReactClass({
|
|
|
158
163
|
);
|
|
159
164
|
}
|
|
160
165
|
return container;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
163
168
|
|
|
164
169
|
export default FixedToResponsive;
|
package/src/components/graph.tsx
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
/* eslint-disable react/
|
|
1
|
+
/* eslint-disable react/no-unsafe */
|
|
2
2
|
import $ from "jquery";
|
|
3
|
-
import PropTypes from "prop-types";
|
|
4
3
|
import * as React from "react";
|
|
5
4
|
import ReactDOM from "react-dom";
|
|
6
5
|
import _ from "underscore";
|
|
7
6
|
|
|
7
|
+
import {Coord} from "../interactive2/types";
|
|
8
|
+
import {PerseusImageBackground} from "../perseus-types";
|
|
8
9
|
import {interactiveSizes} from "../styles/constants";
|
|
9
10
|
import Util from "../util";
|
|
10
11
|
import GraphUtils from "../util/graph-utils";
|
|
@@ -13,7 +14,7 @@ import SvgImage from "./svg-image";
|
|
|
13
14
|
|
|
14
15
|
const defaultBackgroundImage = {
|
|
15
16
|
url: null,
|
|
16
|
-
}
|
|
17
|
+
};
|
|
17
18
|
|
|
18
19
|
/* Style objects */
|
|
19
20
|
const defaultInstructionsStyle = {
|
|
@@ -38,7 +39,46 @@ function numSteps(range: any, step: any) {
|
|
|
38
39
|
return Math.floor((range[1] - range[0]) / step);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
type Props = {
|
|
43
|
+
box: Readonly<[number, number]>;
|
|
44
|
+
labels: ReadonlyArray<string>;
|
|
45
|
+
range: Readonly<[Coord, Coord]>;
|
|
46
|
+
step: Readonly<[number, number]>;
|
|
47
|
+
gridStep: Readonly<[number, number]>;
|
|
48
|
+
snapStep: Readonly<[number, number]>;
|
|
49
|
+
markings: string;
|
|
50
|
+
backgroundImage: PerseusImageBackground;
|
|
51
|
+
showProtractor: boolean;
|
|
52
|
+
showRuler: boolean;
|
|
53
|
+
rulerLabel: string;
|
|
54
|
+
rulerTicks: number;
|
|
55
|
+
instructions?: string;
|
|
56
|
+
isMobile: boolean;
|
|
57
|
+
|
|
58
|
+
onGraphieUpdated?: (graphie: any) => void;
|
|
59
|
+
onClick?: (Coord) => void;
|
|
60
|
+
onMouseDown?: (Coord) => void;
|
|
61
|
+
onMouseUp?: (Coord) => void;
|
|
62
|
+
onMouseMove?: (Coord) => void;
|
|
63
|
+
setDrawingAreaAvailable?: (boolean) => void;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
type DefaultProps = {
|
|
67
|
+
labels: Props["labels"];
|
|
68
|
+
range: Props["range"];
|
|
69
|
+
step: Props["step"];
|
|
70
|
+
gridStep: Props["gridStep"];
|
|
71
|
+
snapStep: Props["snapStep"];
|
|
72
|
+
markings: Props["markings"];
|
|
73
|
+
backgroundImage: Props["backgroundImage"];
|
|
74
|
+
showProtractor: Props["showProtractor"];
|
|
75
|
+
showRuler: Props["showRuler"];
|
|
76
|
+
rulerLabel: Props["rulerLabel"];
|
|
77
|
+
rulerTicks: Props["rulerTicks"];
|
|
78
|
+
isMobile: Props["isMobile"];
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
class Graph extends React.Component<Props> {
|
|
42
82
|
protractor: any;
|
|
43
83
|
ruler: any;
|
|
44
84
|
_graphie: any;
|
|
@@ -47,29 +87,7 @@ class Graph extends React.Component<any> {
|
|
|
47
87
|
// @ts-expect-error [FEI-5003] - TS2564 - Property '_shouldSetupGraphie' has no initializer and is not definitely assigned in the constructor.
|
|
48
88
|
_shouldSetupGraphie: boolean;
|
|
49
89
|
|
|
50
|
-
static
|
|
51
|
-
box: PropTypes.array.isRequired,
|
|
52
|
-
labels: PropTypes.arrayOf(PropTypes.string),
|
|
53
|
-
range: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),
|
|
54
|
-
step: PropTypes.arrayOf(PropTypes.number),
|
|
55
|
-
gridStep: PropTypes.arrayOf(PropTypes.number),
|
|
56
|
-
snapStep: PropTypes.arrayOf(PropTypes.number),
|
|
57
|
-
markings: PropTypes.string,
|
|
58
|
-
backgroundImage: PropTypes.shape({
|
|
59
|
-
url: PropTypes.string,
|
|
60
|
-
}),
|
|
61
|
-
showProtractor: PropTypes.bool,
|
|
62
|
-
showRuler: PropTypes.bool,
|
|
63
|
-
rulerLabel: PropTypes.string,
|
|
64
|
-
rulerTicks: PropTypes.number,
|
|
65
|
-
onGraphieUpdated: PropTypes.func,
|
|
66
|
-
instructions: PropTypes.string,
|
|
67
|
-
onClick: PropTypes.func,
|
|
68
|
-
setDrawingAreaAvailable: PropTypes.func,
|
|
69
|
-
isMobile: PropTypes.bool,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
static defaultProps: any = {
|
|
90
|
+
static defaultProps: DefaultProps = {
|
|
73
91
|
labels: ["x", "y"],
|
|
74
92
|
range: [
|
|
75
93
|
[-10, 10],
|
|
@@ -84,67 +102,13 @@ class Graph extends React.Component<any> {
|
|
|
84
102
|
showRuler: false,
|
|
85
103
|
rulerLabel: "",
|
|
86
104
|
rulerTicks: 10,
|
|
87
|
-
instructions: null,
|
|
88
|
-
onGraphieUpdated: null,
|
|
89
|
-
onClick: null,
|
|
90
|
-
onMouseDown: null,
|
|
91
105
|
isMobile: false,
|
|
92
106
|
};
|
|
93
107
|
|
|
94
|
-
render(): React.ReactNode {
|
|
95
|
-
let image;
|
|
96
|
-
const imageData = this.props.backgroundImage;
|
|
97
|
-
if (imageData.url) {
|
|
98
|
-
const scale = this.props.box[0] / interactiveSizes.defaultBoxSize;
|
|
99
|
-
image = (
|
|
100
|
-
// @ts-expect-error [FEI-5003] - TS2741 - Property 'alt' is missing in type '{ src: any; width: any; height: any; scale: number; responsive: false; }' but required in type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "height" | "width" | "title" | "alt" | "trackInteraction" | "preloader" | "allowFullBleed" | "extraGraphie" | "overrideAriaHidden">'.
|
|
101
|
-
<SvgImage
|
|
102
|
-
src={imageData.url}
|
|
103
|
-
width={imageData.width}
|
|
104
|
-
height={imageData.height}
|
|
105
|
-
scale={scale}
|
|
106
|
-
responsive={false}
|
|
107
|
-
/>
|
|
108
|
-
);
|
|
109
|
-
} else {
|
|
110
|
-
image = null;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return (
|
|
114
|
-
<div
|
|
115
|
-
className="graphie-container above-scratchpad"
|
|
116
|
-
style={{
|
|
117
|
-
width: this.props.box[0],
|
|
118
|
-
height: this.props.box[1],
|
|
119
|
-
}}
|
|
120
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'onMouseOut' does not exist on type 'Graph'.
|
|
121
|
-
onMouseOut={this.onMouseOut}
|
|
122
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'onMouseOver' does not exist on type 'Graph'.
|
|
123
|
-
onMouseOver={this.onMouseOver}
|
|
124
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'onClick' does not exist on type 'Graph'.
|
|
125
|
-
onClick={this.onClick}
|
|
126
|
-
>
|
|
127
|
-
{image}
|
|
128
|
-
{/* eslint-disable-next-line react/no-string-refs */}
|
|
129
|
-
<div className="graphie" ref="graphieDiv" />
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
108
|
componentDidMount() {
|
|
135
109
|
this._setupGraphie(true);
|
|
136
110
|
}
|
|
137
111
|
|
|
138
|
-
componentDidUpdate() {
|
|
139
|
-
// Only setupGraphie once per componentDidUpdate().
|
|
140
|
-
// See explanation in setupGraphie().
|
|
141
|
-
this._hasSetupGraphieThisUpdate = false;
|
|
142
|
-
if (this._shouldSetupGraphie) {
|
|
143
|
-
this._setupGraphie(false);
|
|
144
|
-
this._shouldSetupGraphie = false;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
112
|
UNSAFE_componentWillReceiveProps(nextProps: any) {
|
|
149
113
|
const potentialChanges = [
|
|
150
114
|
"labels",
|
|
@@ -166,6 +130,16 @@ class Graph extends React.Component<any> {
|
|
|
166
130
|
});
|
|
167
131
|
}
|
|
168
132
|
|
|
133
|
+
componentDidUpdate() {
|
|
134
|
+
// Only setupGraphie once per componentDidUpdate().
|
|
135
|
+
// See explanation in setupGraphie().
|
|
136
|
+
this._hasSetupGraphieThisUpdate = false;
|
|
137
|
+
if (this._shouldSetupGraphie) {
|
|
138
|
+
this._setupGraphie(false);
|
|
139
|
+
this._shouldSetupGraphie = false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
169
143
|
/* Reset the graphie canvas to its initial state
|
|
170
144
|
*
|
|
171
145
|
* Use when re-rendering the parent component and you need a blank
|
|
@@ -412,6 +386,46 @@ class Graph extends React.Component<any> {
|
|
|
412
386
|
"snapStep",
|
|
413
387
|
);
|
|
414
388
|
};
|
|
389
|
+
|
|
390
|
+
render(): React.ReactNode {
|
|
391
|
+
let image;
|
|
392
|
+
const imageData = this.props.backgroundImage;
|
|
393
|
+
if (imageData.url) {
|
|
394
|
+
const scale = this.props.box[0] / interactiveSizes.defaultBoxSize;
|
|
395
|
+
image = (
|
|
396
|
+
// @ts-expect-error [FEI-5003] - TS2741 - Property 'alt' is missing in type '{ src: any; width: any; height: any; scale: number; responsive: false; }' but required in type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "height" | "width" | "title" | "alt" | "trackInteraction" | "preloader" | "allowFullBleed" | "extraGraphie" | "overrideAriaHidden">'.
|
|
397
|
+
<SvgImage
|
|
398
|
+
src={imageData.url}
|
|
399
|
+
width={imageData.width}
|
|
400
|
+
height={imageData.height}
|
|
401
|
+
scale={scale}
|
|
402
|
+
responsive={false}
|
|
403
|
+
/>
|
|
404
|
+
);
|
|
405
|
+
} else {
|
|
406
|
+
image = null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return (
|
|
410
|
+
<div
|
|
411
|
+
className="graphie-container above-scratchpad"
|
|
412
|
+
style={{
|
|
413
|
+
width: this.props.box[0],
|
|
414
|
+
height: this.props.box[1],
|
|
415
|
+
}}
|
|
416
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'onMouseOut' does not exist on type 'Graph'.
|
|
417
|
+
onMouseOut={this.onMouseOut}
|
|
418
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'onMouseOver' does not exist on type 'Graph'.
|
|
419
|
+
onMouseOver={this.onMouseOver}
|
|
420
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'onClick' does not exist on type 'Graph'.
|
|
421
|
+
onClick={this.onClick}
|
|
422
|
+
>
|
|
423
|
+
{image}
|
|
424
|
+
{/* eslint-disable-next-line react/no-string-refs */}
|
|
425
|
+
<div className="graphie" ref="graphieDiv" />
|
|
426
|
+
</div>
|
|
427
|
+
);
|
|
428
|
+
}
|
|
415
429
|
}
|
|
416
430
|
|
|
417
431
|
export default Graph;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import $ from "jquery";
|
|
2
|
-
import PropTypes from "prop-types";
|
|
3
2
|
import * as React from "react";
|
|
4
3
|
import ReactDOM from "react-dom";
|
|
5
4
|
import _ from "underscore";
|
|
@@ -12,34 +11,58 @@ import GraphUtils from "../util/graph-utils";
|
|
|
12
11
|
import GraphieClasses from "./graphie-classes";
|
|
13
12
|
import Movables from "./graphie-movables";
|
|
14
13
|
|
|
14
|
+
import type {Coord} from "../interactive2/types";
|
|
15
|
+
import type {Range, Size} from "../perseus-types";
|
|
16
|
+
|
|
15
17
|
const GraphieMovable = GraphieClasses.GraphieMovable;
|
|
16
18
|
|
|
17
19
|
const createGraphie = GraphUtils.createGraphie;
|
|
18
20
|
const {deepEq, nestedMap} = Util;
|
|
19
21
|
const {assert} = InteractiveUtil;
|
|
20
22
|
|
|
21
|
-
type Props =
|
|
23
|
+
type Props = {
|
|
24
|
+
addMouseLayer?: boolean;
|
|
25
|
+
box: Size;
|
|
26
|
+
range: [Coord, Coord];
|
|
27
|
+
ranges?: [Range, Range];
|
|
28
|
+
gridStep?: [number, number];
|
|
29
|
+
step?: [number, number];
|
|
30
|
+
scale?: [number, number];
|
|
31
|
+
|
|
32
|
+
isMobile?: boolean;
|
|
33
|
+
responsive?: boolean;
|
|
34
|
+
|
|
35
|
+
children?: React.ReactNode;
|
|
36
|
+
|
|
37
|
+
// TODO(LC-772) - type this prop!
|
|
38
|
+
options: any;
|
|
39
|
+
|
|
40
|
+
setDrawingAreaAvailable?: (boolean) => void;
|
|
41
|
+
setup: (
|
|
42
|
+
graphie: any,
|
|
43
|
+
options: {
|
|
44
|
+
range: [Coord, Coord];
|
|
45
|
+
scale: [number, number];
|
|
46
|
+
},
|
|
47
|
+
) => void;
|
|
48
|
+
|
|
49
|
+
onClick?: (at: Coord) => void;
|
|
50
|
+
onMouseDown?: (at: Coord) => void;
|
|
51
|
+
onMouseMove?: (at: Coord) => void;
|
|
52
|
+
onMouseUp?: (at: Coord) => void;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
type DefaultProps = {
|
|
56
|
+
range: Props["range"];
|
|
57
|
+
options: Props["options"];
|
|
58
|
+
responsive: Props["responsive"];
|
|
59
|
+
addMouseLayer: Props["addMouseLayer"];
|
|
60
|
+
};
|
|
22
61
|
|
|
23
62
|
class Graphie extends React.Component<Props> {
|
|
24
|
-
|
|
25
|
-
addMouseLayer: PropTypes.bool,
|
|
26
|
-
box: PropTypes.arrayOf(PropTypes.number).isRequired,
|
|
27
|
-
children: PropTypes.node,
|
|
28
|
-
isMobile: PropTypes.bool,
|
|
29
|
-
onClick: PropTypes.func,
|
|
30
|
-
onMouseDown: PropTypes.func,
|
|
31
|
-
onMouseMove: PropTypes.func,
|
|
32
|
-
onMouseUp: PropTypes.func,
|
|
33
|
-
options: PropTypes.shape({
|
|
34
|
-
snapStep: PropTypes.arrayOf(PropTypes.number),
|
|
35
|
-
}),
|
|
36
|
-
range: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),
|
|
37
|
-
responsive: PropTypes.bool,
|
|
38
|
-
setDrawingAreaAvailable: PropTypes.func,
|
|
39
|
-
setup: PropTypes.func.isRequired,
|
|
40
|
-
};
|
|
63
|
+
graphieDivRef = React.createRef<HTMLDivElement>();
|
|
41
64
|
|
|
42
|
-
static defaultProps:
|
|
65
|
+
static defaultProps: DefaultProps = {
|
|
43
66
|
range: [
|
|
44
67
|
[-10, 10],
|
|
45
68
|
[-10, 10],
|
|
@@ -102,21 +125,30 @@ class Graphie extends React.Component<Props> {
|
|
|
102
125
|
};
|
|
103
126
|
|
|
104
127
|
// bounds-checked range
|
|
105
|
-
_range: () =>
|
|
106
|
-
|
|
107
|
-
if (
|
|
128
|
+
_range: () => [Coord, Coord] = () => {
|
|
129
|
+
const boundsCheckRange = (range: Coord): Coord => {
|
|
130
|
+
if (range[0] >= range[1]) {
|
|
108
131
|
return [-10, 10];
|
|
109
132
|
}
|
|
110
|
-
return
|
|
111
|
-
}
|
|
133
|
+
return range;
|
|
134
|
+
};
|
|
135
|
+
return [
|
|
136
|
+
boundsCheckRange(this.props.range[0]),
|
|
137
|
+
boundsCheckRange(this.props.range[1]),
|
|
138
|
+
];
|
|
112
139
|
};
|
|
113
140
|
|
|
114
|
-
_box: () =>
|
|
115
|
-
|
|
141
|
+
_box: () => Size = () => {
|
|
142
|
+
const ensureMinSize = (pixelDim: number): number => {
|
|
116
143
|
// 340 = default size in the editor. exact value
|
|
117
144
|
// is arbitrary; this is just a safety check.
|
|
118
145
|
return pixelDim > 0 ? pixelDim : 340;
|
|
119
|
-
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
return [
|
|
149
|
+
ensureMinSize(this.props.box[0]),
|
|
150
|
+
ensureMinSize(this.props.box[1]),
|
|
151
|
+
];
|
|
120
152
|
};
|
|
121
153
|
|
|
122
154
|
_scale: () => ReadonlyArray<number> = () => {
|
|
@@ -131,8 +163,7 @@ class Graphie extends React.Component<Props> {
|
|
|
131
163
|
_setupGraphie: () => void = () => {
|
|
132
164
|
this._removeMovables();
|
|
133
165
|
|
|
134
|
-
|
|
135
|
-
const graphieDiv = ReactDOM.findDOMNode(this.refs.graphieDiv);
|
|
166
|
+
const graphieDiv = ReactDOM.findDOMNode(this.graphieDivRef.current);
|
|
136
167
|
// @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call. | TS2339 - Property 'empty' does not exist on type 'JQueryStatic'.
|
|
137
168
|
$(graphieDiv).empty();
|
|
138
169
|
// @ts-expect-error [FEI-5003] - TS2339 - Property '_graphie' does not exist on type 'Graphie'.
|
|
@@ -342,8 +373,7 @@ class Graphie extends React.Component<Props> {
|
|
|
342
373
|
render(): React.ReactNode {
|
|
343
374
|
return (
|
|
344
375
|
<div className="graphie-container">
|
|
345
|
-
|
|
346
|
-
<div className="graphie" ref="graphieDiv" />
|
|
376
|
+
<div className="graphie" ref={this.graphieDivRef} />
|
|
347
377
|
</div>
|
|
348
378
|
);
|
|
349
379
|
}
|