@khanacademy/perseus 2.0.0 → 2.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 +17 -0
- package/dist/es/index.css +3 -67
- package/dist/es/index.js +67 -102
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +3 -67
- package/dist/index.js +67 -102
- package/dist/index.js.map +1 -1
- package/package.json +34 -34
- package/src/components/graph.jsx +0 -2
- package/src/components/math-input.jsx +163 -152
- package/src/components/tex-buttons.jsx +7 -9
- package/src/components/tooltip.jsx +0 -3
- package/src/components/zoomable.jsx +0 -10
- package/src/interactive2/movable-point.jsx +0 -4
- package/src/interactive2/wrapped-ellipse.js +0 -1
- package/src/styles/articles.less +6 -5
- package/src/styles/khan-exercise.css +1 -33
- package/src/styles/perseus-renderer.less +1 -10
- package/src/styles/widgets/expression.less +0 -2
- package/src/styles/widgets/orderer.less +1 -1
- package/src/styles/widgets/plotter.less +0 -4
- package/src/styles/widgets/sortable.less +0 -14
- package/src/widget-container.jsx +4 -0
- package/src/widgets/__stories__/definition.stories.jsx +27 -1
- package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +2 -2
- package/src/widgets/__tests__/__snapshots__/number-line_test.jsx.snap +1 -1
- package/src/widgets/__tests__/__snapshots__/video_test.jsx.snap +2 -2
- package/src/widgets/simulator.jsx +0 -2
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": "2.
|
|
6
|
+
"version": "2.1.0",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -23,30 +23,30 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@khanacademy/kas": "^0.2.7",
|
|
25
25
|
"@khanacademy/kmath": "^0.0.8",
|
|
26
|
-
"@khanacademy/math-input": "^0.6.
|
|
26
|
+
"@khanacademy/math-input": "^0.6.8",
|
|
27
27
|
"@khanacademy/perseus-linter": "^0.2.5",
|
|
28
28
|
"@khanacademy/pure-markdown": "^0.1.5",
|
|
29
29
|
"@khanacademy/simple-markdown": "^0.8.6",
|
|
30
30
|
"mathquill": "git+https://git@github.com/Khan/mathquill.git#a9ae54e057c5c1acc8244a5627acbff29901d992"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@khanacademy/wonder-blocks-button": "^
|
|
34
|
-
"@khanacademy/wonder-blocks-clickable": "^
|
|
35
|
-
"@khanacademy/wonder-blocks-color": "^
|
|
36
|
-
"@khanacademy/wonder-blocks-core": "^
|
|
37
|
-
"@khanacademy/wonder-blocks-data": "^
|
|
38
|
-
"@khanacademy/wonder-blocks-dropdown": "^
|
|
39
|
-
"@khanacademy/wonder-blocks-form": "^
|
|
40
|
-
"@khanacademy/wonder-blocks-i18n": "^
|
|
41
|
-
"@khanacademy/wonder-blocks-layout": "^
|
|
42
|
-
"@khanacademy/wonder-blocks-link": "^
|
|
43
|
-
"@khanacademy/wonder-blocks-modal": "^
|
|
44
|
-
"@khanacademy/wonder-blocks-popover": "^
|
|
45
|
-
"@khanacademy/wonder-blocks-progress-spinner": "^
|
|
33
|
+
"@khanacademy/wonder-blocks-button": "^4.0.8",
|
|
34
|
+
"@khanacademy/wonder-blocks-clickable": "^3.0.8",
|
|
35
|
+
"@khanacademy/wonder-blocks-color": "^2.0.1",
|
|
36
|
+
"@khanacademy/wonder-blocks-core": "^5.0.4",
|
|
37
|
+
"@khanacademy/wonder-blocks-data": "^11.0.8",
|
|
38
|
+
"@khanacademy/wonder-blocks-dropdown": "^3.0.8",
|
|
39
|
+
"@khanacademy/wonder-blocks-form": "^4.0.8",
|
|
40
|
+
"@khanacademy/wonder-blocks-i18n": "^2.0.2",
|
|
41
|
+
"@khanacademy/wonder-blocks-layout": "^2.0.8",
|
|
42
|
+
"@khanacademy/wonder-blocks-link": "^4.0.8",
|
|
43
|
+
"@khanacademy/wonder-blocks-modal": "^4.0.8",
|
|
44
|
+
"@khanacademy/wonder-blocks-popover": "^2.0.8",
|
|
45
|
+
"@khanacademy/wonder-blocks-progress-spinner": "^2.0.8",
|
|
46
46
|
"@khanacademy/wonder-blocks-spacing": "^3.0.5",
|
|
47
|
-
"@khanacademy/wonder-blocks-tooltip": "^
|
|
48
|
-
"@khanacademy/wonder-blocks-typography": "^
|
|
49
|
-
"@khanacademy/wonder-stuff-core": "^1.2.
|
|
47
|
+
"@khanacademy/wonder-blocks-tooltip": "^2.0.8",
|
|
48
|
+
"@khanacademy/wonder-blocks-typography": "^2.0.5",
|
|
49
|
+
"@khanacademy/wonder-stuff-core": "^1.2.2",
|
|
50
50
|
"aphrodite": "^1.2.5",
|
|
51
51
|
"classnames": "^1.1.4",
|
|
52
52
|
"create-react-class": "^15.6.3",
|
|
@@ -63,23 +63,23 @@
|
|
|
63
63
|
"underscore": "^1.4.4"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@khanacademy/wonder-blocks-button": "^
|
|
67
|
-
"@khanacademy/wonder-blocks-clickable": "^
|
|
68
|
-
"@khanacademy/wonder-blocks-color": "^
|
|
69
|
-
"@khanacademy/wonder-blocks-core": "^
|
|
70
|
-
"@khanacademy/wonder-blocks-data": "^
|
|
71
|
-
"@khanacademy/wonder-blocks-dropdown": "^
|
|
72
|
-
"@khanacademy/wonder-blocks-form": "^
|
|
73
|
-
"@khanacademy/wonder-blocks-i18n": "^
|
|
74
|
-
"@khanacademy/wonder-blocks-layout": "^
|
|
75
|
-
"@khanacademy/wonder-blocks-link": "^
|
|
76
|
-
"@khanacademy/wonder-blocks-modal": "^
|
|
77
|
-
"@khanacademy/wonder-blocks-popover": "^
|
|
78
|
-
"@khanacademy/wonder-blocks-progress-spinner": "^
|
|
66
|
+
"@khanacademy/wonder-blocks-button": "^4.0.8",
|
|
67
|
+
"@khanacademy/wonder-blocks-clickable": "^3.0.8",
|
|
68
|
+
"@khanacademy/wonder-blocks-color": "^2.0.1",
|
|
69
|
+
"@khanacademy/wonder-blocks-core": "^5.0.4",
|
|
70
|
+
"@khanacademy/wonder-blocks-data": "^11.0.8",
|
|
71
|
+
"@khanacademy/wonder-blocks-dropdown": "^3.0.8",
|
|
72
|
+
"@khanacademy/wonder-blocks-form": "^4.0.8",
|
|
73
|
+
"@khanacademy/wonder-blocks-i18n": "^2.0.2",
|
|
74
|
+
"@khanacademy/wonder-blocks-layout": "^2.0.8",
|
|
75
|
+
"@khanacademy/wonder-blocks-link": "^4.0.8",
|
|
76
|
+
"@khanacademy/wonder-blocks-modal": "^4.0.8",
|
|
77
|
+
"@khanacademy/wonder-blocks-popover": "^2.0.8",
|
|
78
|
+
"@khanacademy/wonder-blocks-progress-spinner": "^2.0.8",
|
|
79
79
|
"@khanacademy/wonder-blocks-spacing": "^3.0.5",
|
|
80
|
-
"@khanacademy/wonder-blocks-tooltip": "^
|
|
81
|
-
"@khanacademy/wonder-blocks-typography": "^
|
|
82
|
-
"@khanacademy/wonder-stuff-core": "^1.2.
|
|
80
|
+
"@khanacademy/wonder-blocks-tooltip": "^2.0.8",
|
|
81
|
+
"@khanacademy/wonder-blocks-typography": "^2.0.5",
|
|
82
|
+
"@khanacademy/wonder-stuff-core": "^1.2.2",
|
|
83
83
|
"aphrodite": "^1.2.5",
|
|
84
84
|
"classnames": "^1.1.4",
|
|
85
85
|
"create-react-class": "^15.6.3",
|
package/src/components/graph.jsx
CHANGED
|
@@ -28,8 +28,6 @@ const defaultInstructionsStyle = {
|
|
|
28
28
|
position: "absolute",
|
|
29
29
|
zIndex: 1,
|
|
30
30
|
transition: "opacity .25s ease-in-out",
|
|
31
|
-
"-moz-transition": "opacity .25s ease-in-out",
|
|
32
|
-
"-webkit-transition": "opacity .25s ease-in-out",
|
|
33
31
|
};
|
|
34
32
|
|
|
35
33
|
const instructionsTextStyle = {
|
|
@@ -1,174 +1,50 @@
|
|
|
1
|
-
/* eslint-disable react/sort-comp */
|
|
2
1
|
// @flow
|
|
3
2
|
import classNames from "classnames";
|
|
4
3
|
import $ from "jquery";
|
|
5
4
|
import MathQuill from "mathquill";
|
|
6
|
-
import PropTypes from "prop-types";
|
|
7
5
|
import * as React from "react";
|
|
8
6
|
import ReactDOM from "react-dom";
|
|
9
7
|
import _ from "underscore";
|
|
10
8
|
|
|
11
9
|
import TexButtons from "./tex-buttons.jsx";
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
import type {ButtonSetsType} from "./tex-buttons.jsx";
|
|
12
|
+
|
|
13
|
+
type ButtonsVisibleType = "always" | "never" | "focused";
|
|
14
|
+
|
|
15
|
+
type Props = {|
|
|
16
|
+
className?: string,
|
|
17
|
+
value: string,
|
|
18
|
+
onChange: $FlowFixMe,
|
|
19
|
+
convertDotToTimes: boolean,
|
|
20
|
+
buttonsVisible: ButtonsVisibleType,
|
|
21
|
+
buttonSets: ButtonSetsType,
|
|
22
|
+
labelText?: string,
|
|
23
|
+
onFocus?: () => void,
|
|
24
|
+
onBlur?: () => void,
|
|
25
|
+
|};
|
|
26
|
+
|
|
27
|
+
type DefaultProps = {|
|
|
28
|
+
value: Props["value"],
|
|
29
|
+
convertDotToTimes: Props["convertDotToTimes"],
|
|
30
|
+
buttonsVisible: Props["buttonsVisible"],
|
|
31
|
+
|};
|
|
32
|
+
|
|
33
|
+
type State = {|
|
|
34
|
+
focused: boolean,
|
|
35
|
+
|};
|
|
14
36
|
|
|
15
37
|
// A WYSIWYG math input that calls `onChange(LaTeX-string)`
|
|
16
|
-
class MathInput extends React.Component
|
|
38
|
+
class MathInput extends React.Component<Props, State> {
|
|
17
39
|
mouseDown: boolean;
|
|
18
40
|
|
|
19
|
-
static
|
|
20
|
-
value: PT.string,
|
|
21
|
-
onChange: PT.func.isRequired,
|
|
22
|
-
convertDotToTimes: PT.bool,
|
|
23
|
-
buttonsVisible: PT.oneOf(["always", "never", "focused"]),
|
|
24
|
-
buttonSets: TexButtons.buttonSetsType.isRequired,
|
|
25
|
-
labelText: PropTypes.string,
|
|
26
|
-
onFocus: PT.func,
|
|
27
|
-
onBlur: PT.func,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
static defaultProps: $FlowFixMe = {
|
|
41
|
+
static defaultProps: DefaultProps = {
|
|
31
42
|
value: "",
|
|
32
43
|
convertDotToTimes: false,
|
|
33
44
|
buttonsVisible: "focused",
|
|
34
45
|
};
|
|
35
46
|
|
|
36
|
-
state:
|
|
37
|
-
|
|
38
|
-
render(): React.Node {
|
|
39
|
-
let className = classNames({
|
|
40
|
-
"perseus-math-input": true,
|
|
41
|
-
|
|
42
|
-
// mathquill usually adds these itself but react removes them when
|
|
43
|
-
// updating the component.
|
|
44
|
-
"mq-editable-field": true,
|
|
45
|
-
"mq-math-mode": true,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
if (this.props.className) {
|
|
49
|
-
className = className + " " + this.props.className;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
let buttons = null;
|
|
53
|
-
if (this._shouldShowButtons()) {
|
|
54
|
-
buttons = (
|
|
55
|
-
<TexButtons
|
|
56
|
-
sets={this.props.buttonSets}
|
|
57
|
-
className="math-input-buttons absolute"
|
|
58
|
-
convertDotToTimes={this.props.convertDotToTimes}
|
|
59
|
-
onInsert={this.insert}
|
|
60
|
-
/>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<div style={{display: "inline-block"}}>
|
|
66
|
-
<div style={{display: "inline-block"}}>
|
|
67
|
-
<span
|
|
68
|
-
className={className}
|
|
69
|
-
// eslint-disable-next-line react/no-string-refs
|
|
70
|
-
ref="mathinput"
|
|
71
|
-
aria-label={this.props.labelText}
|
|
72
|
-
onFocus={this.handleFocus}
|
|
73
|
-
onBlur={this.handleBlur}
|
|
74
|
-
/>
|
|
75
|
-
</div>
|
|
76
|
-
<div style={{position: "relative"}} onBlur={this.handleBlur}>
|
|
77
|
-
{buttons}
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// handlers:
|
|
84
|
-
// keep track of two related bits of state:
|
|
85
|
-
// * this.state.focused - whether the buttons are currently shown
|
|
86
|
-
// * this.mouseDown - whether a mouse click is active that started in the
|
|
87
|
-
// buttons div
|
|
88
|
-
|
|
89
|
-
handleFocus: () => void = () => {
|
|
90
|
-
this.setState({focused: true});
|
|
91
|
-
// TODO(joel) fix properly - we should probably allow onFocus handlers
|
|
92
|
-
// to this property, but we need to work correctly with them.
|
|
93
|
-
// if (this.props.onFocus) {
|
|
94
|
-
// this.props.onFocus();
|
|
95
|
-
// }
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
handleMouseDown: (MouseEvent) => void = (event) => {
|
|
99
|
-
// $FlowFixMe[incompatible-use]
|
|
100
|
-
// $FlowFixMe[incompatible-call]
|
|
101
|
-
const focused = ReactDOM.findDOMNode(this).contains(event.target);
|
|
102
|
-
this.mouseDown = focused;
|
|
103
|
-
if (!focused) {
|
|
104
|
-
this.setState({focused: false});
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
handleMouseUp: (MouseEvent) => void = () => {
|
|
109
|
-
// this mouse click started in the buttons div so we should focus the
|
|
110
|
-
// input
|
|
111
|
-
if (this.mouseDown) {
|
|
112
|
-
this.focus();
|
|
113
|
-
}
|
|
114
|
-
this.mouseDown = false;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
handleBlur: (SyntheticFocusEvent<>) => void = (e) => {
|
|
118
|
-
// TODO(michaelpolyak): Consider trapping focus within the button group.
|
|
119
|
-
// Focusing back on the input when TAB out of the last button in the
|
|
120
|
-
// group. This will probably require ESCAPE key handling to enable to
|
|
121
|
-
// close (blur) the button group in order to focus on next page element.
|
|
122
|
-
if (
|
|
123
|
-
!this.mouseDown &&
|
|
124
|
-
// $FlowFixMe[incompatible-use]
|
|
125
|
-
// $FlowFixMe[incompatible-call]
|
|
126
|
-
!ReactDOM.findDOMNode(this).contains(e.relatedTarget)
|
|
127
|
-
) {
|
|
128
|
-
this.setState({focused: false});
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
_shouldShowButtons: () => boolean = () => {
|
|
133
|
-
if (this.props.buttonsVisible === "always") {
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
if (this.props.buttonsVisible === "never") {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
return this.state.focused;
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
insert: ($FlowFixMe) => void = (value) => {
|
|
143
|
-
const input = this.mathField();
|
|
144
|
-
if (_(value).isFunction()) {
|
|
145
|
-
value(input);
|
|
146
|
-
} else if (value[0] === "\\") {
|
|
147
|
-
input.cmd(value).focus();
|
|
148
|
-
} else {
|
|
149
|
-
input.write(value).focus();
|
|
150
|
-
}
|
|
151
|
-
input.focus();
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
mathField: ($FlowFixMe) => $FlowFixMe = (options) => {
|
|
155
|
-
// The MathQuill API is now "versioned" through its own "InterVer"
|
|
156
|
-
// system.
|
|
157
|
-
// See: https://github.com/mathquill/mathquill/pull/459
|
|
158
|
-
const MQ = MathQuill.getInterface(2);
|
|
159
|
-
|
|
160
|
-
// MathQuill.MathField takes a DOM node, MathQuill-ifies it if it's
|
|
161
|
-
// seeing that node for the first time, then returns the associated
|
|
162
|
-
// MathQuill object for that node. It is stable - will always return
|
|
163
|
-
// the same object when called on the same DOM node.
|
|
164
|
-
// eslint-disable-next-line react/no-string-refs
|
|
165
|
-
return MQ.MathField(ReactDOM.findDOMNode(this.refs.mathinput), options);
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
componentWillUnmount() {
|
|
169
|
-
window.removeEventListener("mousedown", this.handleMouseDown);
|
|
170
|
-
window.removeEventListener("mouseup", this.handleMouseUp);
|
|
171
|
-
}
|
|
47
|
+
state: State = {focused: false};
|
|
172
48
|
|
|
173
49
|
componentDidMount() {
|
|
174
50
|
window.addEventListener("mousedown", this.handleMouseDown);
|
|
@@ -268,6 +144,96 @@ class MathInput extends React.Component<$FlowFixMe, $FlowFixMe> {
|
|
|
268
144
|
initialized = true;
|
|
269
145
|
}
|
|
270
146
|
|
|
147
|
+
componentWillUnmount() {
|
|
148
|
+
window.removeEventListener("mousedown", this.handleMouseDown);
|
|
149
|
+
window.removeEventListener("mouseup", this.handleMouseUp);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// handlers:
|
|
153
|
+
// keep track of two related bits of state:
|
|
154
|
+
// * this.state.focused - whether the buttons are currently shown
|
|
155
|
+
// * this.mouseDown - whether a mouse click is active that started in the
|
|
156
|
+
// buttons div
|
|
157
|
+
|
|
158
|
+
handleFocus: () => void = () => {
|
|
159
|
+
this.setState({focused: true});
|
|
160
|
+
// TODO(joel) fix properly - we should probably allow onFocus handlers
|
|
161
|
+
// to this property, but we need to work correctly with them.
|
|
162
|
+
// if (this.props.onFocus) {
|
|
163
|
+
// this.props.onFocus();
|
|
164
|
+
// }
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
handleMouseDown: (MouseEvent) => void = (event) => {
|
|
168
|
+
// $FlowFixMe[incompatible-use]
|
|
169
|
+
// $FlowFixMe[incompatible-call]
|
|
170
|
+
const focused = ReactDOM.findDOMNode(this).contains(event.target);
|
|
171
|
+
this.mouseDown = focused;
|
|
172
|
+
if (!focused) {
|
|
173
|
+
this.setState({focused: false});
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
handleMouseUp: (MouseEvent) => void = () => {
|
|
178
|
+
// this mouse click started in the buttons div so we should focus the
|
|
179
|
+
// input
|
|
180
|
+
if (this.mouseDown) {
|
|
181
|
+
this.focus();
|
|
182
|
+
}
|
|
183
|
+
this.mouseDown = false;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
handleBlur: (SyntheticFocusEvent<>) => void = (e) => {
|
|
187
|
+
// TODO(michaelpolyak): Consider trapping focus within the button group.
|
|
188
|
+
// Focusing back on the input when TAB out of the last button in the
|
|
189
|
+
// group. This will probably require ESCAPE key handling to enable to
|
|
190
|
+
// close (blur) the button group in order to focus on next page element.
|
|
191
|
+
if (
|
|
192
|
+
!this.mouseDown &&
|
|
193
|
+
// $FlowFixMe[incompatible-use]
|
|
194
|
+
// $FlowFixMe[incompatible-call]
|
|
195
|
+
!ReactDOM.findDOMNode(this).contains(e.relatedTarget)
|
|
196
|
+
) {
|
|
197
|
+
this.setState({focused: false});
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
_shouldShowButtons: () => boolean = () => {
|
|
202
|
+
if (this.props.buttonsVisible === "always") {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
if (this.props.buttonsVisible === "never") {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
return this.state.focused;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
insert: ($FlowFixMe) => void = (value) => {
|
|
212
|
+
const input = this.mathField();
|
|
213
|
+
if (_(value).isFunction()) {
|
|
214
|
+
value(input);
|
|
215
|
+
} else if (value[0] === "\\") {
|
|
216
|
+
input.cmd(value).focus();
|
|
217
|
+
} else {
|
|
218
|
+
input.write(value).focus();
|
|
219
|
+
}
|
|
220
|
+
input.focus();
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
mathField: ($FlowFixMe) => $FlowFixMe = (options) => {
|
|
224
|
+
// The MathQuill API is now "versioned" through its own "InterVer"
|
|
225
|
+
// system.
|
|
226
|
+
// See: https://github.com/mathquill/mathquill/pull/459
|
|
227
|
+
const MQ = MathQuill.getInterface(2);
|
|
228
|
+
|
|
229
|
+
// MathQuill.MathField takes a DOM node, MathQuill-ifies it if it's
|
|
230
|
+
// seeing that node for the first time, then returns the associated
|
|
231
|
+
// MathQuill object for that node. It is stable - will always return
|
|
232
|
+
// the same object when called on the same DOM node.
|
|
233
|
+
// eslint-disable-next-line react/no-string-refs
|
|
234
|
+
return MQ.MathField(ReactDOM.findDOMNode(this.refs.mathinput), options);
|
|
235
|
+
};
|
|
236
|
+
|
|
271
237
|
focus: () => void = () => {
|
|
272
238
|
this.mathField().focus();
|
|
273
239
|
this.setState({focused: true});
|
|
@@ -277,6 +243,51 @@ class MathInput extends React.Component<$FlowFixMe, $FlowFixMe> {
|
|
|
277
243
|
this.mathField().blur();
|
|
278
244
|
this.setState({focused: false});
|
|
279
245
|
};
|
|
246
|
+
|
|
247
|
+
render(): React.Node {
|
|
248
|
+
let className = classNames({
|
|
249
|
+
"perseus-math-input": true,
|
|
250
|
+
|
|
251
|
+
// mathquill usually adds these itself but react removes them when
|
|
252
|
+
// updating the component.
|
|
253
|
+
"mq-editable-field": true,
|
|
254
|
+
"mq-math-mode": true,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (this.props.className) {
|
|
258
|
+
className = className + " " + this.props.className;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let buttons = null;
|
|
262
|
+
if (this._shouldShowButtons()) {
|
|
263
|
+
buttons = (
|
|
264
|
+
<TexButtons
|
|
265
|
+
sets={this.props.buttonSets}
|
|
266
|
+
className="math-input-buttons absolute"
|
|
267
|
+
convertDotToTimes={this.props.convertDotToTimes}
|
|
268
|
+
onInsert={this.insert}
|
|
269
|
+
/>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return (
|
|
274
|
+
<div style={{display: "inline-block"}}>
|
|
275
|
+
<div style={{display: "inline-block"}}>
|
|
276
|
+
<span
|
|
277
|
+
className={className}
|
|
278
|
+
// eslint-disable-next-line react/no-string-refs
|
|
279
|
+
ref="mathinput"
|
|
280
|
+
aria-label={this.props.labelText}
|
|
281
|
+
onFocus={this.handleFocus}
|
|
282
|
+
onBlur={this.handleBlur}
|
|
283
|
+
/>
|
|
284
|
+
</div>
|
|
285
|
+
<div style={{position: "relative"}} onBlur={this.handleBlur}>
|
|
286
|
+
{buttons}
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
280
291
|
}
|
|
281
292
|
|
|
282
293
|
export default MathInput;
|
|
@@ -252,24 +252,22 @@ const buttonSets: ButtonSets = {
|
|
|
252
252
|
],
|
|
253
253
|
};
|
|
254
254
|
|
|
255
|
+
export type ButtonSetsType = $ReadOnlyArray<$Keys<typeof buttonSets>>;
|
|
256
|
+
|
|
255
257
|
type TexButtonProps = {|
|
|
256
|
-
sets:
|
|
258
|
+
sets: ButtonSetsType,
|
|
257
259
|
onInsert: (Inserter) => void,
|
|
258
260
|
className?: string,
|
|
259
261
|
convertDotToTimes?: boolean,
|
|
260
262
|
|};
|
|
261
263
|
|
|
262
|
-
const
|
|
264
|
+
const buttonSetsPropType = PropTypes.arrayOf(
|
|
265
|
+
PropTypes.oneOf(_(buttonSets).keys()),
|
|
266
|
+
);
|
|
263
267
|
|
|
264
268
|
class TexButtons extends React.Component<TexButtonProps> {
|
|
265
|
-
static propTypes = {
|
|
266
|
-
sets: buttonSetsType.isRequired,
|
|
267
|
-
onInsert: PropTypes.func.isRequired,
|
|
268
|
-
className: PropTypes.string,
|
|
269
|
-
};
|
|
270
|
-
|
|
271
269
|
static buttonSets: typeof buttonSets = buttonSets;
|
|
272
|
-
static buttonSetsType: $FlowFixMe =
|
|
270
|
+
static buttonSetsType: $FlowFixMe = buttonSetsPropType;
|
|
273
271
|
|
|
274
272
|
render(): React.Node {
|
|
275
273
|
// Always show buttonSets in the same order. Note: Technically it's ok
|
|
@@ -345,9 +345,6 @@ const Tooltip = createReactClass({
|
|
|
345
345
|
top: settings["top"],
|
|
346
346
|
left: settings.tooltipLeft,
|
|
347
347
|
border: "1px solid " + this.props.borderColor,
|
|
348
|
-
WebkitBoxShadow:
|
|
349
|
-
"0 1px 3px " + this.props.borderColor,
|
|
350
|
-
MozBoxShadow: "0 1px 3px " + this.props.borderColor,
|
|
351
348
|
boxShadow: "0 1px 3px " + this.props.borderColor,
|
|
352
349
|
zIndex: zIndex - 1,
|
|
353
350
|
}}
|
|
@@ -253,14 +253,8 @@ class Zoomable extends React.Component<Props, State> {
|
|
|
253
253
|
const transitionStyle = visible
|
|
254
254
|
? {
|
|
255
255
|
transitionProperty: property,
|
|
256
|
-
WebkitTransitionProperty: property,
|
|
257
|
-
msTransitionProperty: property,
|
|
258
256
|
transitionDuration: "0.3s",
|
|
259
|
-
WebkitTransitionDuration: "0.3s",
|
|
260
|
-
msTransitionDuration: "0.3s",
|
|
261
257
|
transitionTimingFunction: "ease-out",
|
|
262
|
-
WebkitTransitionTimingfunction: "ease-out",
|
|
263
|
-
msTransitionTmingFunction: "ease-out",
|
|
264
258
|
}
|
|
265
259
|
: {};
|
|
266
260
|
|
|
@@ -276,11 +270,7 @@ class Zoomable extends React.Component<Props, State> {
|
|
|
276
270
|
width: "100%",
|
|
277
271
|
height: zoomed ? expandedHeight : compactHeight,
|
|
278
272
|
transform: transform,
|
|
279
|
-
WebkitTransform: transform,
|
|
280
|
-
msTransform: transform,
|
|
281
273
|
transformOrigin: "0 0",
|
|
282
|
-
WebkitTransformOrigin: "0 0",
|
|
283
|
-
msTransformOrigin: "0 0",
|
|
284
274
|
opacity: visible ? 1 : 0,
|
|
285
275
|
WebkitTapHighlightColor: "transparent",
|
|
286
276
|
...transitionStyle,
|
|
@@ -326,7 +326,6 @@ _.extend(MovablePoint.prototype, {
|
|
|
326
326
|
const svgElem = state.visibleShape.wrapper;
|
|
327
327
|
if (state.shadow) {
|
|
328
328
|
const filter = "none";
|
|
329
|
-
svgElem.style.webkitFilter = filter;
|
|
330
329
|
svgElem.style.filter = filter;
|
|
331
330
|
}
|
|
332
331
|
|
|
@@ -352,7 +351,6 @@ _.extend(MovablePoint.prototype, {
|
|
|
352
351
|
const filter =
|
|
353
352
|
"drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
|
|
354
353
|
|
|
355
|
-
content.style.webkitFilter = filter;
|
|
356
354
|
content.style.filter = filter;
|
|
357
355
|
}
|
|
358
356
|
}
|
|
@@ -402,7 +400,6 @@ _.extend(MovablePoint.prototype, {
|
|
|
402
400
|
if (state.shadow) {
|
|
403
401
|
const filter =
|
|
404
402
|
"drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
|
|
405
|
-
svgElem.style.webkitFilter = filter;
|
|
406
403
|
svgElem.style.filter = filter;
|
|
407
404
|
}
|
|
408
405
|
|
|
@@ -422,7 +419,6 @@ _.extend(MovablePoint.prototype, {
|
|
|
422
419
|
"tooltip-content",
|
|
423
420
|
)[0];
|
|
424
421
|
|
|
425
|
-
content.style.webkitFilter = "none";
|
|
426
422
|
content.style.filter = "none";
|
|
427
423
|
|
|
428
424
|
this._tooltip.firstChild.addEventListener(
|
|
@@ -55,7 +55,6 @@ const WrappedEllipse = function (
|
|
|
55
55
|
if (options.shadow) {
|
|
56
56
|
const filter = "drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
|
|
57
57
|
const wrapper = this.wrapper;
|
|
58
|
-
wrapper.style.webkitFilter = filter;
|
|
59
58
|
wrapper.style.filter = filter;
|
|
60
59
|
|
|
61
60
|
this.moveTo = function (point) {
|
package/src/styles/articles.less
CHANGED
|
@@ -55,7 +55,12 @@
|
|
|
55
55
|
|
|
56
56
|
@paragraphSpacing: 32px;
|
|
57
57
|
.perseus-widget-container {
|
|
58
|
-
|
|
58
|
+
// HACK(matthewc): to get around this fixed font-size
|
|
59
|
+
// since we want the definition widget to match
|
|
60
|
+
// surrounding text
|
|
61
|
+
&:not(.perseus-widget__definition) {
|
|
62
|
+
.legacy-typography;
|
|
63
|
+
}
|
|
59
64
|
|
|
60
65
|
&.widget-float-left,
|
|
61
66
|
&.widget-float-right {
|
|
@@ -699,8 +704,6 @@ img.zoom-img {
|
|
|
699
704
|
}
|
|
700
705
|
|
|
701
706
|
.zoom-transition {
|
|
702
|
-
-webkit-transition: transform @zoomAnimationDurationMs ease;
|
|
703
|
-
-ms-transition: transform @zoomAnimationDurationMs ease;
|
|
704
707
|
transition: transform @zoomAnimationDurationMs ease;
|
|
705
708
|
}
|
|
706
709
|
|
|
@@ -736,8 +739,6 @@ img.zoom-img {
|
|
|
736
739
|
bottom: 0;
|
|
737
740
|
background: white;
|
|
738
741
|
opacity: 0;
|
|
739
|
-
-webkit-transition: opacity @zoomAnimationDurationMs;
|
|
740
|
-
-ms-transition: opacity @zoomAnimationDurationMs;
|
|
741
742
|
transition: opacity @zoomAnimationDurationMs;
|
|
742
743
|
}
|
|
743
744
|
|