@khanacademy/perseus-editor 4.1.4 → 4.1.6
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/dist/es/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +9 -6
- package/.babelrc.js +0 -8
- package/.eslintrc.js +0 -12
- package/CHANGELOG.md +0 -1146
- package/src/README.md +0 -7
- package/src/__stories__/editor-page.stories.tsx +0 -65
- package/src/__stories__/editor.stories.tsx +0 -134
- package/src/__stories__/item-editor.stories.tsx +0 -41
- package/src/__stories__/tex-error-view.stories.tsx +0 -26
- package/src/__testdata__/input-number.testdata.ts +0 -27
- package/src/__tests__/editor.test.tsx +0 -142
- package/src/__tests__/hint-editor.test.tsx +0 -83
- package/src/__tests__/i18n.test.ts +0 -501
- package/src/__tests__/integration.test.ts +0 -5
- package/src/__tests__/item-extras-editor.test.tsx +0 -85
- package/src/__tests__/traversal.test.ts +0 -377
- package/src/all-editors.test.ts +0 -16
- package/src/all-editors.ts +0 -83
- package/src/all-widgets.ts +0 -7
- package/src/article-editor.tsx +0 -438
- package/src/components/__stories__/blur-input.stories.tsx +0 -22
- package/src/components/__stories__/section-control-button.stories.tsx +0 -26
- package/src/components/__tests__/blur-input.test.tsx +0 -67
- package/src/components/blur-input.tsx +0 -69
- package/src/components/checkbox.tsx +0 -194
- package/src/components/device-framer.tsx +0 -90
- package/src/components/drag-target.tsx +0 -87
- package/src/components/dropdown-option.tsx +0 -311
- package/src/components/form-wrapped-text-field.tsx +0 -245
- package/src/components/graph-points-count-selector.tsx +0 -31
- package/src/components/graph-settings.tsx +0 -627
- package/src/components/graph-type-selector.tsx +0 -31
- package/src/components/hover-behavior.ts +0 -177
- package/src/components/json-editor.tsx +0 -121
- package/src/components/link.ts +0 -173
- package/src/components/section-control-button.tsx +0 -53
- package/src/components/segment-count-selector.tsx +0 -27
- package/src/components/simple-button.tsx +0 -85
- package/src/components/sortable.tsx +0 -187
- package/src/components/util.ts +0 -38
- package/src/components/viewport-resizer.tsx +0 -72
- package/src/components/widget-editor.tsx +0 -222
- package/src/components/widget-select.tsx +0 -48
- package/src/diffs/__stories__/perseus-diff-wrapper.tsx +0 -11
- package/src/diffs/__stories__/structured-item-diff.stories.tsx +0 -855
- package/src/diffs/__stories__/tags-diff.stories.tsx +0 -36
- package/src/diffs/__stories__/text-diff.stories.tsx +0 -35
- package/src/diffs/__tests__/split-diff.test.ts +0 -33
- package/src/diffs/__tests__/string-array-diff.test.ts +0 -73
- package/src/diffs/__tests__/structured-item-diff.test.ts +0 -433
- package/src/diffs/__tests__/widget-diff-performer.test.ts +0 -43
- package/src/diffs/article-diff.tsx +0 -69
- package/src/diffs/item-diff.tsx +0 -76
- package/src/diffs/renderer-diff.tsx +0 -137
- package/src/diffs/split-diff.ts +0 -31
- package/src/diffs/string-array-diff.ts +0 -74
- package/src/diffs/structured-item-diff.tsx +0 -275
- package/src/diffs/tags-diff.tsx +0 -49
- package/src/diffs/text-diff.tsx +0 -193
- package/src/diffs/widget-diff-performer.ts +0 -69
- package/src/diffs/widget-diff.tsx +0 -290
- package/src/editor-page.tsx +0 -325
- package/src/editor.tsx +0 -1099
- package/src/hint-editor.tsx +0 -469
- package/src/i18n.ts +0 -140
- package/src/iframe-content-renderer.tsx +0 -188
- package/src/index.ts +0 -30
- package/src/item-editor.tsx +0 -158
- package/src/item-extras-editor.tsx +0 -230
- package/src/katex-mhchem/index.js +0 -73
- package/src/katex-mhchem/parser.js +0 -2659
- package/src/multirenderer-editor.tsx +0 -1061
- package/src/stateful-article-editor.tsx +0 -173
- package/src/stateful-editor-page.tsx +0 -88
- package/src/styles/perseus-editor.less +0 -1321
- package/src/testing-widgets.ts +0 -11
- package/src/tex-error-view.tsx +0 -90
- package/src/util/points.test.ts +0 -24
- package/src/util/points.ts +0 -13
- package/src/util/register-all-widgets-and-editors-for-testing.test.ts +0 -17
- package/src/util/register-all-widgets-and-editors-for-testing.ts +0 -17
- package/src/version.ts +0 -10
- package/src/widgets/__stories__/categorizer-editor.stories.tsx +0 -24
- package/src/widgets/__stories__/definition-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/dropdown-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/explanation-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/expression-editor.stories.tsx +0 -122
- package/src/widgets/__stories__/image-editor.stories.tsx +0 -72
- package/src/widgets/__stories__/input-number-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/interaction-editor.stories.tsx +0 -37
- package/src/widgets/__stories__/label-image-editor.stories.tsx +0 -99
- package/src/widgets/__stories__/matcher-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/number-line-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/numeric-input-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/radio-editor.stories.tsx +0 -116
- package/src/widgets/__stories__/sorter-editor.stories.tsx +0 -18
- package/src/widgets/__tests__/categorizer-editor.test.tsx +0 -51
- package/src/widgets/__tests__/definition-editor.test.tsx +0 -41
- package/src/widgets/__tests__/dropdown-editor.test.tsx +0 -57
- package/src/widgets/__tests__/explanation-editor.test.tsx +0 -59
- package/src/widgets/__tests__/expression-editor.test.tsx +0 -403
- package/src/widgets/__tests__/input-number-editor.test.tsx +0 -128
- package/src/widgets/__tests__/matcher-editor.test.tsx +0 -47
- package/src/widgets/__tests__/number-line-editor.test.tsx +0 -144
- package/src/widgets/__tests__/numeric-input-editor.test.tsx +0 -177
- package/src/widgets/__tests__/radio-editor.test.tsx +0 -118
- package/src/widgets/__tests__/sorter-editor.test.tsx +0 -55
- package/src/widgets/categorizer-editor.tsx +0 -104
- package/src/widgets/cs-program-editor.tsx +0 -256
- package/src/widgets/definition-editor.tsx +0 -77
- package/src/widgets/deprecated-standin-editor.tsx +0 -29
- package/src/widgets/dropdown-editor.tsx +0 -211
- package/src/widgets/example-graphie-widget-editor.tsx +0 -70
- package/src/widgets/example-graphie-widget.tsx +0 -172
- package/src/widgets/example-widget-editor.tsx +0 -62
- package/src/widgets/example-widget.tsx +0 -154
- package/src/widgets/explanation-editor.tsx +0 -92
- package/src/widgets/expression-editor.tsx +0 -557
- package/src/widgets/graded-group-editor.tsx +0 -161
- package/src/widgets/graded-group-set-editor.tsx +0 -104
- package/src/widgets/grapher-editor.tsx +0 -155
- package/src/widgets/group-editor.tsx +0 -83
- package/src/widgets/iframe-editor.tsx +0 -202
- package/src/widgets/image-editor.tsx +0 -367
- package/src/widgets/input-number-editor.tsx +0 -288
- package/src/widgets/interaction-editor/constraint-editor.tsx +0 -134
- package/src/widgets/interaction-editor/function-editor.tsx +0 -108
- package/src/widgets/interaction-editor/index.ts +0 -3
- package/src/widgets/interaction-editor/interaction-editor.tsx +0 -749
- package/src/widgets/interaction-editor/label-editor.tsx +0 -87
- package/src/widgets/interaction-editor/line-editor.tsx +0 -125
- package/src/widgets/interaction-editor/mathquill-input.tsx +0 -81
- package/src/widgets/interaction-editor/movable-line-editor.tsx +0 -121
- package/src/widgets/interaction-editor/movable-point-editor.tsx +0 -89
- package/src/widgets/interaction-editor/parametric-editor.tsx +0 -117
- package/src/widgets/interaction-editor/point-editor.tsx +0 -72
- package/src/widgets/interaction-editor/rectangle-editor.tsx +0 -96
- package/src/widgets/interactive-graph-editor.tsx +0 -571
- package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -82
- package/src/widgets/label-image/__stories__/behavior.stories.tsx +0 -31
- package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -75
- package/src/widgets/label-image/__stories__/question-markers.stories.tsx +0 -107
- package/src/widgets/label-image/__stories__/select-image.stories.tsx +0 -59
- package/src/widgets/label-image/answer-choices.tsx +0 -231
- package/src/widgets/label-image/behavior.tsx +0 -122
- package/src/widgets/label-image/marker.tsx +0 -290
- package/src/widgets/label-image/question-markers.tsx +0 -176
- package/src/widgets/label-image/select-image.tsx +0 -81
- package/src/widgets/label-image-editor.tsx +0 -252
- package/src/widgets/lights-puzzle-editor.tsx +0 -278
- package/src/widgets/matcher-editor.tsx +0 -149
- package/src/widgets/matrix-editor.tsx +0 -156
- package/src/widgets/measurer-editor.tsx +0 -253
- package/src/widgets/molecule-editor.tsx +0 -64
- package/src/widgets/number-line-editor.tsx +0 -512
- package/src/widgets/numeric-input-editor.tsx +0 -536
- package/src/widgets/orderer-editor.tsx +0 -172
- package/src/widgets/passage-editor.tsx +0 -117
- package/src/widgets/passage-ref-editor.tsx +0 -80
- package/src/widgets/passage-ref-target-editor.tsx +0 -49
- package/src/widgets/plotter-editor.tsx +0 -542
- package/src/widgets/radio/editor.tsx +0 -398
- package/src/widgets/reaction-diagram-editor.tsx +0 -131
- package/src/widgets/sequence-editor.tsx +0 -205
- package/src/widgets/simple-markdown-tester-editor.tsx +0 -86
- package/src/widgets/simple-markdown-tester.tsx +0 -92
- package/src/widgets/simulator-editor.tsx +0 -146
- package/src/widgets/sorter-editor.tsx +0 -103
- package/src/widgets/table-editor.tsx +0 -164
- package/src/widgets/unit-editor.tsx +0 -299
- package/src/widgets/video-editor.tsx +0 -73
- package/tsconfig-build.json +0 -22
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react/sort-comp */
|
|
2
|
-
/**
|
|
3
|
-
* Add hover behavior to another component.
|
|
4
|
-
*
|
|
5
|
-
* This component provides hover and focus status updates in a consistent way
|
|
6
|
-
* across desktop and mobile.
|
|
7
|
-
*
|
|
8
|
-
* For advice on when to use this component instead of Button, see README.md.
|
|
9
|
-
*
|
|
10
|
-
* Many mobile browsers treat :hover as sticky which results in buttons looking
|
|
11
|
-
* pressed even when the user has lifted their finger. This component ensures
|
|
12
|
-
* that when user lifts their finger the hover state is removed.
|
|
13
|
-
*
|
|
14
|
-
* We also chnage how the focus state works. Browsers immediately set the
|
|
15
|
-
* focus state as soon as you click on a button. This component only sets the
|
|
16
|
-
* focus state when a user starts navigating between elements via keybaord.
|
|
17
|
-
*
|
|
18
|
-
* HoverBehavior accepts a function as 'children' which is passed state and
|
|
19
|
-
* an object containing event handlers. The 'children' function should return
|
|
20
|
-
* an React Element of some sort.
|
|
21
|
-
*
|
|
22
|
-
* Example:
|
|
23
|
-
*
|
|
24
|
-
* class MyButtonLikeComponent extends React.Component {
|
|
25
|
-
* render(): React.Node {
|
|
26
|
-
* return <HoverBehavior
|
|
27
|
-
* disabled={this.props.disabled}
|
|
28
|
-
* onClick={this.handleClick}
|
|
29
|
-
* >
|
|
30
|
-
* {({hovered}, handlers) =>
|
|
31
|
-
* <RoundRect
|
|
32
|
-
* textcolor='white'
|
|
33
|
-
* backgroundColor={hovered ? 'red' : 'blue'}/>}
|
|
34
|
-
* {...handlers}
|
|
35
|
-
* >
|
|
36
|
-
* {this.props.children}
|
|
37
|
-
* </RoundRect>
|
|
38
|
-
* }
|
|
39
|
-
* </HoverBehavior>
|
|
40
|
-
* }
|
|
41
|
-
* }
|
|
42
|
-
*
|
|
43
|
-
* This follows a pattern call 'Function as Child Components':
|
|
44
|
-
* https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9#.sw0jiio8b
|
|
45
|
-
*/
|
|
46
|
-
import * as React from "react";
|
|
47
|
-
|
|
48
|
-
type Handlers = {
|
|
49
|
-
onBlur: () => unknown;
|
|
50
|
-
onClick: (e: React.MouseEvent) => unknown;
|
|
51
|
-
onFocus: () => unknown;
|
|
52
|
-
onMouseDown: () => unknown;
|
|
53
|
-
onMouseEnter: () => unknown;
|
|
54
|
-
onMouseLeave: () => unknown;
|
|
55
|
-
onTouchStart: () => unknown;
|
|
56
|
-
onTouchEnd: () => unknown;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
type State = {
|
|
60
|
-
focused: boolean;
|
|
61
|
-
hovered: boolean;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
type Props = {
|
|
65
|
-
children?: (state: State, handlers: Handlers) => React.ReactElement;
|
|
66
|
-
disabled?: boolean;
|
|
67
|
-
onClick?: (e: React.MouseEvent) => unknown;
|
|
68
|
-
startHovered: boolean;
|
|
69
|
-
shouldUpdate: () => boolean;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export default class HoverBehavior extends React.Component<Props, State> {
|
|
73
|
-
static defaultProps: {
|
|
74
|
-
shouldUpdate: () => boolean;
|
|
75
|
-
startHovered: boolean;
|
|
76
|
-
} = {
|
|
77
|
-
startHovered: false,
|
|
78
|
-
shouldUpdate: () => true,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
constructor(props: Props) {
|
|
82
|
-
super(props);
|
|
83
|
-
|
|
84
|
-
this.state = {
|
|
85
|
-
focused: false,
|
|
86
|
-
hovered: props.startHovered,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// @ts-expect-error - TS2564 - Property 'focusFlag' has no initializer and is not definitely assigned in the constructor.
|
|
91
|
-
focusFlag: boolean;
|
|
92
|
-
// @ts-expect-error - TS2564 - Property 'waitingForClick' has no initializer and is not definitely assigned in the constructor.
|
|
93
|
-
waitingForClick: boolean;
|
|
94
|
-
|
|
95
|
-
handleClick: (e: React.MouseEvent) => void = (e: React.MouseEvent) => {
|
|
96
|
-
if (!this.props.disabled) {
|
|
97
|
-
if (this.props.shouldUpdate()) {
|
|
98
|
-
this.waitingForClick = false;
|
|
99
|
-
}
|
|
100
|
-
if (this.props.onClick && !this.props.disabled) {
|
|
101
|
-
this.props.onClick(e);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
handleMouseEnter: () => void = () => {
|
|
107
|
-
if (
|
|
108
|
-
!this.props.disabled &&
|
|
109
|
-
this.props.shouldUpdate() &&
|
|
110
|
-
!this.waitingForClick
|
|
111
|
-
) {
|
|
112
|
-
this.setState({hovered: true});
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
handleMouseLeave: () => void = () => {
|
|
117
|
-
if (
|
|
118
|
-
!this.props.disabled &&
|
|
119
|
-
this.props.shouldUpdate() &&
|
|
120
|
-
!this.waitingForClick
|
|
121
|
-
) {
|
|
122
|
-
this.setState({hovered: false});
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
handleTouchStart: () => void = () => {
|
|
127
|
-
if (!this.props.disabled && this.props.shouldUpdate()) {
|
|
128
|
-
this.setState({hovered: true});
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
handleTouchEnd: () => void = () => {
|
|
133
|
-
if (!this.props.disabled && this.props.shouldUpdate()) {
|
|
134
|
-
this.setState({hovered: false});
|
|
135
|
-
this.waitingForClick = true;
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
handleMouseDown: () => void = () => {
|
|
140
|
-
if (!this.props.disabled && this.props.shouldUpdate()) {
|
|
141
|
-
this.setState({focused: false});
|
|
142
|
-
this.focusFlag = true;
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
handleBlur: () => void = () => {
|
|
147
|
-
if (!this.props.disabled && this.props.shouldUpdate()) {
|
|
148
|
-
this.setState({focused: false});
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
handleFocus: () => void = () => {
|
|
153
|
-
if (!this.props.disabled && this.props.shouldUpdate()) {
|
|
154
|
-
if (this.focusFlag) {
|
|
155
|
-
this.focusFlag = false;
|
|
156
|
-
} else {
|
|
157
|
-
this.setState({focused: true});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
render(): React.ReactNode {
|
|
163
|
-
const handlers = {
|
|
164
|
-
onBlur: this.handleBlur,
|
|
165
|
-
onClick: this.handleClick,
|
|
166
|
-
onFocus: this.handleFocus,
|
|
167
|
-
onMouseDown: this.handleMouseDown,
|
|
168
|
-
onMouseEnter: this.handleMouseEnter,
|
|
169
|
-
onMouseLeave: this.handleMouseLeave,
|
|
170
|
-
onTouchStart: this.handleTouchStart,
|
|
171
|
-
onTouchEnd: this.handleTouchEnd,
|
|
172
|
-
} as const;
|
|
173
|
-
|
|
174
|
-
const {children} = this.props;
|
|
175
|
-
return children?.(this.state, handlers) || null;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @babel/no-invalid-this */
|
|
2
|
-
/* eslint-disable react/no-unsafe */
|
|
3
|
-
/* eslint-disable react/sort-comp */
|
|
4
|
-
import createReactClass from "create-react-class";
|
|
5
|
-
import * as React from "react";
|
|
6
|
-
import _ from "underscore";
|
|
7
|
-
|
|
8
|
-
const JsonEditor: any = createReactClass({
|
|
9
|
-
displayName: "JsonEditor",
|
|
10
|
-
|
|
11
|
-
getInitialState: function () {
|
|
12
|
-
return {
|
|
13
|
-
currentValue: JSON.stringify(this.props.value, null, 4),
|
|
14
|
-
valid: true,
|
|
15
|
-
};
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
UNSAFE_componentWillReceiveProps: function (nextProps) {
|
|
19
|
-
const shouldReplaceContent =
|
|
20
|
-
!this.state.valid ||
|
|
21
|
-
!_.isEqual(nextProps.value, JSON.parse(this.state.currentValue));
|
|
22
|
-
|
|
23
|
-
if (shouldReplaceContent) {
|
|
24
|
-
this.setState(this.getInitialState());
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
render: function () {
|
|
29
|
-
const classes =
|
|
30
|
-
"perseus-json-editor " + (this.state.valid ? "valid" : "invalid");
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<textarea
|
|
34
|
-
className={classes}
|
|
35
|
-
value={this.state.currentValue}
|
|
36
|
-
onChange={this.handleChange}
|
|
37
|
-
onKeyDown={this.handleKeyDown}
|
|
38
|
-
onBlur={this.handleBlur}
|
|
39
|
-
/>
|
|
40
|
-
);
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
handleKeyDown: function (e) {
|
|
44
|
-
// This handler allows the tab character to be entered by pressing
|
|
45
|
-
// tab, instead of jumping to the next (non-existant) field
|
|
46
|
-
if (e.key === "Tab") {
|
|
47
|
-
const cursorPos = e.target.selectionStart;
|
|
48
|
-
const v = e.target.value;
|
|
49
|
-
const textBefore = v.substring(0, cursorPos);
|
|
50
|
-
const textAfter = v.substring(cursorPos, v.length);
|
|
51
|
-
e.target.value = textBefore + " " + textAfter;
|
|
52
|
-
e.target.selectionStart = textBefore.length + 4;
|
|
53
|
-
e.target.selectionEnd = textBefore.length + 4;
|
|
54
|
-
|
|
55
|
-
e.preventDefault();
|
|
56
|
-
this.handleChange(e);
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
handleChange: function (e) {
|
|
61
|
-
const nextString = e.target.value;
|
|
62
|
-
try {
|
|
63
|
-
let json = JSON.parse(nextString);
|
|
64
|
-
// Some extra handling to allow copy-pasting from /api/vi
|
|
65
|
-
if (_.isString(json)) {
|
|
66
|
-
json = JSON.parse(json);
|
|
67
|
-
}
|
|
68
|
-
// This callback unfortunately causes multiple renders,
|
|
69
|
-
// but seems to be necessary to avoid componentWillReceiveProps
|
|
70
|
-
// being called before setState has gone through
|
|
71
|
-
this.setState(
|
|
72
|
-
{
|
|
73
|
-
currentValue: nextString,
|
|
74
|
-
valid: true,
|
|
75
|
-
},
|
|
76
|
-
function () {
|
|
77
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
78
|
-
this.props.onChange(json);
|
|
79
|
-
},
|
|
80
|
-
);
|
|
81
|
-
} catch (ex: any) {
|
|
82
|
-
this.setState({
|
|
83
|
-
currentValue: nextString,
|
|
84
|
-
valid: false,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
// You can type whatever you want as you're typing, but if it's not valid
|
|
90
|
-
// when you blur, it will revert to the last valid value.
|
|
91
|
-
handleBlur: function (e) {
|
|
92
|
-
const nextString = e.target.value;
|
|
93
|
-
try {
|
|
94
|
-
let json = JSON.parse(nextString);
|
|
95
|
-
// Some extra handling to allow copy-pasting from /api/vi
|
|
96
|
-
if (_.isString(json)) {
|
|
97
|
-
json = JSON.parse(json);
|
|
98
|
-
}
|
|
99
|
-
// This callback unfortunately causes multiple renders,
|
|
100
|
-
// but seems to be necessary to avoid componentWillReceiveProps
|
|
101
|
-
// being called before setState has gone through
|
|
102
|
-
this.setState(
|
|
103
|
-
{
|
|
104
|
-
currentValue: JSON.stringify(json, null, 4),
|
|
105
|
-
valid: true,
|
|
106
|
-
},
|
|
107
|
-
function () {
|
|
108
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
109
|
-
this.props.onChange(json);
|
|
110
|
-
},
|
|
111
|
-
);
|
|
112
|
-
} catch (ex: any) {
|
|
113
|
-
this.setState({
|
|
114
|
-
currentValue: JSON.stringify(this.props.value, null, 4),
|
|
115
|
-
valid: true,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
export default JsonEditor;
|
package/src/components/link.ts
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A generic link that removes common link styles.
|
|
3
|
-
*
|
|
4
|
-
* This is useful for wrapping many child components in a link and making sure
|
|
5
|
-
* that "link" styles don't get applied to all you content.
|
|
6
|
-
*/
|
|
7
|
-
import {StyleSheet, css} from "aphrodite";
|
|
8
|
-
import * as React from "react";
|
|
9
|
-
|
|
10
|
-
import type {CSSProperties} from "aphrodite";
|
|
11
|
-
|
|
12
|
-
// TODO(diedra): This is terrible! If we don't have a href for a link, it should
|
|
13
|
-
// be a button instead. We just need to make sure we override the default browser
|
|
14
|
-
// button styling (backgroundColor, border, and padding).
|
|
15
|
-
const DEFAULT_HREF = "javascript:void(0)";
|
|
16
|
-
|
|
17
|
-
type DefaultProps = {
|
|
18
|
-
element: React.ElementType;
|
|
19
|
-
// Whether the link should appear in a 'highlighted' state. In
|
|
20
|
-
// practice, this will apply the same styles that are applied on-hover.
|
|
21
|
-
highlighted: boolean;
|
|
22
|
-
href: string;
|
|
23
|
-
// Pass through styles but also add our own to normalize
|
|
24
|
-
style: CSSProperties | Array<CSSProperties>;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type Props = DefaultProps & {
|
|
28
|
-
children?: React.ReactNode;
|
|
29
|
-
// An additional class name to add. This is supported so-as to allow
|
|
30
|
-
// Perseus to add class-based styles to links when using this
|
|
31
|
-
// component as its base link class.
|
|
32
|
-
className?: string;
|
|
33
|
-
// Additional direct styles to add.
|
|
34
|
-
inlineStyles?: {
|
|
35
|
-
[key: string]: any;
|
|
36
|
-
};
|
|
37
|
-
// Optional referrer query parameter to add to the end of the URL, used
|
|
38
|
-
// for analytics purposes.
|
|
39
|
-
referrer?: string;
|
|
40
|
-
// A target window to open a link in
|
|
41
|
-
target?: string;
|
|
42
|
-
// The relationship between the linked page and the current page.
|
|
43
|
-
// Mostly used to prevent abuse from linked sites.
|
|
44
|
-
rel?: string;
|
|
45
|
-
// The data-test-id attribute
|
|
46
|
-
testId?: string;
|
|
47
|
-
// Specify either an HTML tag (like "a") or a React component (like
|
|
48
|
-
// React Router's `Link`) to be used as the underlying element.
|
|
49
|
-
|
|
50
|
-
onClick?: (e: React.MouseEvent) => unknown;
|
|
51
|
-
onMouseOver?: (e: React.MouseEvent) => unknown;
|
|
52
|
-
onMouseLeave?: (e: React.MouseEvent) => unknown;
|
|
53
|
-
onMouseEnter?: (e: React.MouseEvent) => unknown;
|
|
54
|
-
onBlur?: (e: React.SyntheticEvent) => unknown;
|
|
55
|
-
onFocus?: (e: React.SyntheticEvent) => unknown;
|
|
56
|
-
onKeyDown?: (e: React.KeyboardEvent) => unknown;
|
|
57
|
-
["aria-label"]?: string;
|
|
58
|
-
["aria-selected"]?: boolean;
|
|
59
|
-
["aria-current"]?: boolean;
|
|
60
|
-
role?: "tab";
|
|
61
|
-
title?: string;
|
|
62
|
-
id?: string;
|
|
63
|
-
tabIndex?: number;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* A wrapper that creates an anchor tag with normalized styles
|
|
68
|
-
*/
|
|
69
|
-
class Link extends React.Component<Props> {
|
|
70
|
-
static defaultProps: DefaultProps = {
|
|
71
|
-
highlighted: false,
|
|
72
|
-
href: DEFAULT_HREF,
|
|
73
|
-
style: [] as Array<CSSProperties>,
|
|
74
|
-
element: "a",
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
render(): React.ReactNode {
|
|
78
|
-
const {
|
|
79
|
-
children,
|
|
80
|
-
className,
|
|
81
|
-
highlighted,
|
|
82
|
-
href,
|
|
83
|
-
inlineStyles,
|
|
84
|
-
referrer,
|
|
85
|
-
style,
|
|
86
|
-
target,
|
|
87
|
-
testId,
|
|
88
|
-
element,
|
|
89
|
-
...otherProps
|
|
90
|
-
} = this.props;
|
|
91
|
-
|
|
92
|
-
// We need to make sure the hash goes at the end of the <a>'s href, so
|
|
93
|
-
// we'll split for now and re-add after potentially adding ?ref=
|
|
94
|
-
// Even though we have defined a default prop for href, if href is
|
|
95
|
-
// set to null, we will still get the null, so we need to handle that.
|
|
96
|
-
const [hrefWithoutHash, hash] = href ? href.split("#") : [DEFAULT_HREF];
|
|
97
|
-
let url = hrefWithoutHash;
|
|
98
|
-
|
|
99
|
-
if (referrer) {
|
|
100
|
-
if (url.indexOf("?") > -1) {
|
|
101
|
-
url += "&ref=" + referrer;
|
|
102
|
-
} else {
|
|
103
|
-
url += "?ref=" + referrer;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (hash) {
|
|
108
|
-
url += "#" + hash;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const delegatedStyles = [
|
|
112
|
-
styles.link,
|
|
113
|
-
highlighted && styles.highlighted,
|
|
114
|
-
];
|
|
115
|
-
|
|
116
|
-
if (Array.isArray(style)) {
|
|
117
|
-
delegatedStyles.push(...style);
|
|
118
|
-
} else {
|
|
119
|
-
delegatedStyles.push(style);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const delegatedClassName = className ? " " + className : "";
|
|
123
|
-
|
|
124
|
-
// When passing an anchor tag, we want to use the native `href`.
|
|
125
|
-
// ReactRouter links, though, need a special `to` prop instead.
|
|
126
|
-
const urlProp = element === "a" ? {href: url} : {to: url};
|
|
127
|
-
|
|
128
|
-
// When the link is set to open in a new window, we want to append
|
|
129
|
-
// some `rel` attributes. This is to ensure that the links we're
|
|
130
|
-
// sending folks to can't hijack the existing page.
|
|
131
|
-
// More info: https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/
|
|
132
|
-
//
|
|
133
|
-
// If `rel` is already defined, we assume the caller knows what they're
|
|
134
|
-
// doing. In the future, we may wish to check what keywords are passed,
|
|
135
|
-
// and add in `noopener` and `noreferrer`.
|
|
136
|
-
let rel = otherProps.rel;
|
|
137
|
-
if (target === "_blank" && !rel) {
|
|
138
|
-
rel = "noopener noreferrer";
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return React.createElement(
|
|
142
|
-
element,
|
|
143
|
-
{
|
|
144
|
-
"data-test-id": testId,
|
|
145
|
-
...otherProps,
|
|
146
|
-
...urlProp,
|
|
147
|
-
className: css(...delegatedStyles) + delegatedClassName,
|
|
148
|
-
style: inlineStyles,
|
|
149
|
-
target,
|
|
150
|
-
rel,
|
|
151
|
-
},
|
|
152
|
-
children,
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const styles = StyleSheet.create({
|
|
158
|
-
link: {
|
|
159
|
-
// Remove the gray background color from active links in IE 10
|
|
160
|
-
// https://necolas.github.io/normalize.css/3.0.2/normalize.css
|
|
161
|
-
backgroundColor: "transparent",
|
|
162
|
-
color: "inherit",
|
|
163
|
-
textDecoration: "none",
|
|
164
|
-
":hover": {
|
|
165
|
-
textDecoration: "underline",
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
highlighted: {
|
|
169
|
-
textDecoration: "underline",
|
|
170
|
-
},
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
export default Link;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import {components} from "@khanacademy/perseus";
|
|
2
|
-
import Clickable from "@khanacademy/wonder-blocks-clickable";
|
|
3
|
-
import Color from "@khanacademy/wonder-blocks-color";
|
|
4
|
-
import {StyleSheet} from "aphrodite";
|
|
5
|
-
import * as React from "react";
|
|
6
|
-
|
|
7
|
-
import type {PropsFor} from "@khanacademy/wonder-blocks-core";
|
|
8
|
-
|
|
9
|
-
const {InlineIcon} = components;
|
|
10
|
-
|
|
11
|
-
type InlineIconProps = PropsFor<typeof InlineIcon>;
|
|
12
|
-
|
|
13
|
-
type SectionControlButtonProps = {
|
|
14
|
-
icon: InlineIconProps;
|
|
15
|
-
onClick: () => unknown;
|
|
16
|
-
title: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export default class SectionControlButton extends React.Component<SectionControlButtonProps> {
|
|
20
|
-
render(): React.ReactNode {
|
|
21
|
-
const {icon, onClick, title} = this.props;
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<Clickable
|
|
25
|
-
className={
|
|
26
|
-
"section-control-button " +
|
|
27
|
-
"simple-button " +
|
|
28
|
-
"simple-button--small "
|
|
29
|
-
}
|
|
30
|
-
onClick={(e) => {
|
|
31
|
-
e.preventDefault();
|
|
32
|
-
onClick();
|
|
33
|
-
}}
|
|
34
|
-
role="button"
|
|
35
|
-
hideDefaultFocusRing={true}
|
|
36
|
-
aria-label={title}
|
|
37
|
-
style={styles.button}
|
|
38
|
-
>
|
|
39
|
-
{({hovered, focused, pressed}) => <InlineIcon {...icon} />}
|
|
40
|
-
</Clickable>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const styles = StyleSheet.create({
|
|
46
|
-
button: {
|
|
47
|
-
backgroundColor: Color.gold,
|
|
48
|
-
margin: 2,
|
|
49
|
-
paddingRight: 10,
|
|
50
|
-
paddingLeft: 10,
|
|
51
|
-
paddingBottom: 2,
|
|
52
|
-
},
|
|
53
|
-
});
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import _ from "underscore";
|
|
3
|
-
|
|
4
|
-
const SegmentCountSelector = ({
|
|
5
|
-
numSegments = 1,
|
|
6
|
-
onChange,
|
|
7
|
-
}: {
|
|
8
|
-
numSegments?: number;
|
|
9
|
-
onChange: (numSegments: number) => void;
|
|
10
|
-
}) => (
|
|
11
|
-
<select
|
|
12
|
-
key="segment-select"
|
|
13
|
-
value={numSegments}
|
|
14
|
-
onChange={(e) => {
|
|
15
|
-
const num = +e.target.value;
|
|
16
|
-
onChange(num);
|
|
17
|
-
}}
|
|
18
|
-
>
|
|
19
|
-
{_.range(1, 7).map((n) => (
|
|
20
|
-
<option key={n} value={n}>
|
|
21
|
-
{`${n} segment${n > 1 ? "s" : ""}`}
|
|
22
|
-
</option>
|
|
23
|
-
))}
|
|
24
|
-
</select>
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
export default SegmentCountSelector;
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provides a simple styled button
|
|
3
|
-
*
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {StyleSheet, css} from "aphrodite";
|
|
7
|
-
import PropTypes from "prop-types";
|
|
8
|
-
import * as React from "react";
|
|
9
|
-
|
|
10
|
-
class SimpleButton extends React.Component<any> {
|
|
11
|
-
static propTypes = {
|
|
12
|
-
children: PropTypes.node,
|
|
13
|
-
color: PropTypes.oneOf(["orange", "green"]),
|
|
14
|
-
onClick: PropTypes.func,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
static defaultProps: any = {
|
|
18
|
-
children: null,
|
|
19
|
-
color: "green",
|
|
20
|
-
onClick: () => {},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
render(): React.ReactNode {
|
|
24
|
-
const {children, color, onClick, ...otherProps} = this.props;
|
|
25
|
-
return (
|
|
26
|
-
<div
|
|
27
|
-
className={css(
|
|
28
|
-
styles.baseButton,
|
|
29
|
-
color === "green" && styles.green,
|
|
30
|
-
color === "orange" && styles.orange,
|
|
31
|
-
)}
|
|
32
|
-
onClick={onClick}
|
|
33
|
-
{...otherProps}
|
|
34
|
-
>
|
|
35
|
-
{children}
|
|
36
|
-
</div>
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const styles = StyleSheet.create({
|
|
42
|
-
baseButton: {
|
|
43
|
-
top: "0",
|
|
44
|
-
fontSize: "11px",
|
|
45
|
-
padding: "3px 10px",
|
|
46
|
-
backgroundRepeat: "repeat-x",
|
|
47
|
-
borderColor: `
|
|
48
|
-
rgba(0, 0, 0, 0.1)
|
|
49
|
-
rgba(0, 0, 0, 0.1)
|
|
50
|
-
rgba(0, 0, 0, 0.25)
|
|
51
|
-
`,
|
|
52
|
-
color: "#ffffff",
|
|
53
|
-
borderRadius: "3px",
|
|
54
|
-
lineHeight: "15px",
|
|
55
|
-
cursor: "pointer",
|
|
56
|
-
transition: "box-shadow ease-in-out 0.15s",
|
|
57
|
-
appearance: "none",
|
|
58
|
-
textDecoration: "none",
|
|
59
|
-
textAlign: "center",
|
|
60
|
-
":hover": {
|
|
61
|
-
boxShadow: `0 1px 1px rgba(0, 0, 0, 0.35),
|
|
62
|
-
inset 0 0 50px 5px rgba(255, 255, 255, 0.2)`,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
green: {
|
|
66
|
-
border: "1px solid #7fab07",
|
|
67
|
-
backgroundColor: "#80ac07",
|
|
68
|
-
backgroundImage: "linear-gradient(to bottom, #8aba08, #719807)",
|
|
69
|
-
":hover": {
|
|
70
|
-
borderBottomColor: "#547105",
|
|
71
|
-
backgroundColor: "#719807",
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
orange: {
|
|
75
|
-
border: "1px solid #d45704",
|
|
76
|
-
backgroundColor: "#d55704",
|
|
77
|
-
backgroundImage: "linear-gradient(to bottom, #e35d04, #c04f03)",
|
|
78
|
-
":hover": {
|
|
79
|
-
borderBottomColor: "#983e03",
|
|
80
|
-
backgroundColor: "#c04f03",
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
export default SimpleButton;
|