@khanacademy/perseus-editor 2.15.6 → 2.16.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 +23 -0
- package/dist/components/blur-input.d.ts +2 -0
- package/dist/components/widget-editor.d.ts +1 -1
- package/dist/editor-page.d.ts +4 -1
- package/dist/editor.d.ts +3 -1
- package/dist/es/index.js +170 -260
- package/dist/es/index.js.map +1 -1
- package/dist/hint-editor.d.ts +2 -0
- package/dist/iframe-content-renderer.d.ts +1 -0
- package/dist/index.js +137 -256
- package/dist/index.js.map +1 -1
- package/dist/item-editor.d.ts +6 -0
- package/dist/widgets/example-widget-editor.d.ts +1 -0
- package/dist/widgets/example-widget.d.ts +7 -0
- package/dist/widgets/graded-group-editor.d.ts +3 -0
- package/dist/widgets/group-editor.d.ts +2 -0
- package/dist/widgets/input-number-editor.d.ts +2 -0
- package/dist/widgets/simple-markdown-tester-editor.d.ts +7 -0
- package/dist/widgets/table-editor.d.ts +2 -0
- package/package.json +13 -13
- package/src/components/__tests__/blur-input.test.tsx +67 -0
- package/src/components/blur-input.tsx +7 -0
- package/src/editor-page.tsx +11 -25
- package/src/editor.tsx +37 -65
- package/src/hint-editor.tsx +15 -27
- package/src/iframe-content-renderer.tsx +19 -20
- package/src/item-editor.tsx +11 -18
- package/src/util/register-all-widgets-and-editors-for-testing.test.ts +3 -1
- package/src/widgets/example-widget-editor.tsx +4 -5
- package/src/widgets/example-widget.tsx +8 -10
- package/src/widgets/graded-group-editor.tsx +9 -19
- package/src/widgets/group-editor.tsx +5 -8
- package/src/widgets/input-number-editor.tsx +4 -5
- package/src/widgets/simple-markdown-tester-editor.tsx +4 -5
- package/src/widgets/table-editor.tsx +4 -5
- package/tsconfig-build.tsbuildinfo +1 -1
package/src/hint-editor.tsx
CHANGED
|
@@ -74,6 +74,8 @@ export class HintEditor extends React.Component<HintEditorProps> {
|
|
|
74
74
|
showRemoveButton: true,
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
+
editor = React.createRef<Editor>();
|
|
78
|
+
|
|
77
79
|
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void = (
|
|
78
80
|
e: React.ChangeEvent<HTMLInputElement>,
|
|
79
81
|
) => {
|
|
@@ -81,21 +83,15 @@ export class HintEditor extends React.Component<HintEditorProps> {
|
|
|
81
83
|
};
|
|
82
84
|
|
|
83
85
|
focus: () => void = () => {
|
|
84
|
-
|
|
85
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
86
|
-
this.refs.editor.focus();
|
|
86
|
+
this.editor.current?.focus();
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
getSaveWarnings: () => any = () => {
|
|
90
|
-
|
|
91
|
-
// @ts-expect-error - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
|
|
92
|
-
return this.refs.editor.getSaveWarnings();
|
|
90
|
+
return this.editor.current?.getSaveWarnings();
|
|
93
91
|
};
|
|
94
92
|
|
|
95
93
|
serialize: (options?: any) => any = (options: any) => {
|
|
96
|
-
|
|
97
|
-
// @ts-expect-error - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
98
|
-
return this.refs.editor.serialize(options);
|
|
94
|
+
return this.editor.current?.serialize(options);
|
|
99
95
|
};
|
|
100
96
|
|
|
101
97
|
render(): React.ReactNode {
|
|
@@ -103,8 +99,7 @@ export class HintEditor extends React.Component<HintEditorProps> {
|
|
|
103
99
|
<div className={"perseus-hint-editor " + this.props.className}>
|
|
104
100
|
{this.props.showTitle && <div className="pod-title">Hint</div>}
|
|
105
101
|
<Editor
|
|
106
|
-
|
|
107
|
-
ref="editor"
|
|
102
|
+
ref={this.editor}
|
|
108
103
|
// Using the AssessmentItem content ID as the key
|
|
109
104
|
// ensures that when the user navigates to another
|
|
110
105
|
// item in the Sidebar, the question editor is
|
|
@@ -192,6 +187,9 @@ class CombinedHintEditor extends React.Component<CombinedHintEditorProps> {
|
|
|
192
187
|
highlightLint: false,
|
|
193
188
|
};
|
|
194
189
|
|
|
190
|
+
editor = React.createRef<HintEditor>();
|
|
191
|
+
frame = React.createRef<IframeContentRenderer>();
|
|
192
|
+
|
|
195
193
|
componentDidMount() {
|
|
196
194
|
this.updatePreview();
|
|
197
195
|
}
|
|
@@ -204,9 +202,7 @@ class CombinedHintEditor extends React.Component<CombinedHintEditorProps> {
|
|
|
204
202
|
const shouldBold =
|
|
205
203
|
this.props.isLast && !/\*\*/.test(this.props.hint.content);
|
|
206
204
|
|
|
207
|
-
|
|
208
|
-
// @ts-expect-error - TS2339 - Property 'sendNewData' does not exist on type 'ReactInstance'.
|
|
209
|
-
this.refs.frame.sendNewData({
|
|
205
|
+
this.frame.current?.sendNewData({
|
|
210
206
|
type: "hint",
|
|
211
207
|
data: {
|
|
212
208
|
hint: this.props.hint,
|
|
@@ -223,21 +219,15 @@ class CombinedHintEditor extends React.Component<CombinedHintEditorProps> {
|
|
|
223
219
|
};
|
|
224
220
|
|
|
225
221
|
getSaveWarnings = () => {
|
|
226
|
-
|
|
227
|
-
// @ts-expect-error - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
|
|
228
|
-
return this.refs.editor.getSaveWarnings();
|
|
222
|
+
return this.editor.current?.getSaveWarnings();
|
|
229
223
|
};
|
|
230
224
|
|
|
231
225
|
serialize = (options: any) => {
|
|
232
|
-
|
|
233
|
-
// @ts-expect-error - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
234
|
-
return this.refs.editor.serialize(options);
|
|
226
|
+
return this.editor.current?.serialize(options);
|
|
235
227
|
};
|
|
236
228
|
|
|
237
229
|
focus = () => {
|
|
238
|
-
|
|
239
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
240
|
-
this.refs.editor.focus();
|
|
230
|
+
this.editor.current?.focus();
|
|
241
231
|
};
|
|
242
232
|
|
|
243
233
|
render(): React.ReactNode {
|
|
@@ -252,8 +242,7 @@ class CombinedHintEditor extends React.Component<CombinedHintEditorProps> {
|
|
|
252
242
|
>
|
|
253
243
|
<div className="perseus-editor-left-cell">
|
|
254
244
|
<HintEditor
|
|
255
|
-
|
|
256
|
-
ref="editor"
|
|
245
|
+
ref={this.editor}
|
|
257
246
|
itemId={this.props.itemId}
|
|
258
247
|
isFirst={this.props.isFirst}
|
|
259
248
|
isLast={this.props.isLast}
|
|
@@ -274,8 +263,7 @@ class CombinedHintEditor extends React.Component<CombinedHintEditorProps> {
|
|
|
274
263
|
nochrome={true}
|
|
275
264
|
>
|
|
276
265
|
<IframeContentRenderer
|
|
277
|
-
|
|
278
|
-
ref="frame"
|
|
266
|
+
ref={this.frame}
|
|
279
267
|
datasetKey="mobile"
|
|
280
268
|
datasetValue={isMobile}
|
|
281
269
|
seamless={true}
|
|
@@ -66,6 +66,8 @@ type Props = {
|
|
|
66
66
|
|
|
67
67
|
class IframeContentRenderer extends React.Component<Props> {
|
|
68
68
|
_frame: HTMLIFrameElement | null | undefined;
|
|
69
|
+
container = React.createRef<HTMLDivElement>();
|
|
70
|
+
|
|
69
71
|
// @ts-expect-error - TS2564 - Property '_isMounted' has no initializer and is not definitely assigned in the constructor.
|
|
70
72
|
_isMounted: boolean;
|
|
71
73
|
_lastData: any;
|
|
@@ -89,10 +91,12 @@ class IframeContentRenderer extends React.Component<Props> {
|
|
|
89
91
|
|
|
90
92
|
updateIframeHeight[this.iframeID] = (height: any) => {
|
|
91
93
|
this._lastHeight = height;
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.
|
|
94
|
+
if (
|
|
95
|
+
this._isMounted &&
|
|
96
|
+
this.props.seamless &&
|
|
97
|
+
this.container.current
|
|
98
|
+
) {
|
|
99
|
+
this.container.current.style.height = height + "px";
|
|
96
100
|
}
|
|
97
101
|
};
|
|
98
102
|
}
|
|
@@ -105,14 +109,12 @@ class IframeContentRenderer extends React.Component<Props> {
|
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
componentDidUpdate(prevProps: Props) {
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// @ts-expect-error - TS2339 - Property 'style' does not exist on type 'ReactInstance'.
|
|
115
|
-
this.refs.container.style.height = this._lastHeight + "px";
|
|
112
|
+
if (this.container.current) {
|
|
113
|
+
if (!this.props.seamless) {
|
|
114
|
+
this.container.current.style.height = "100%";
|
|
115
|
+
} else {
|
|
116
|
+
this.container.current.style.height = this._lastHeight + "px";
|
|
117
|
+
}
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
if (prevProps.datasetValue !== this.props.datasetValue) {
|
|
@@ -131,9 +133,7 @@ class IframeContentRenderer extends React.Component<Props> {
|
|
|
131
133
|
_prepareFrame() {
|
|
132
134
|
// Don't initialize the iframe until the page has loaded
|
|
133
135
|
if (this._frame) {
|
|
134
|
-
|
|
135
|
-
// @ts-expect-error - TS2339 - Property 'removeChild' does not exist on type 'ReactInstance'.
|
|
136
|
-
this.refs.container.removeChild(this._frame);
|
|
136
|
+
this.container.current?.removeChild(this._frame);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
const frame = document.createElement("iframe");
|
|
@@ -159,9 +159,7 @@ class IframeContentRenderer extends React.Component<Props> {
|
|
|
159
159
|
frame.dataset.lintGutter = "true";
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
// @ts-expect-error - TS2339 - Property 'appendChild' does not exist on type 'ReactInstance'.
|
|
164
|
-
this.refs.container.appendChild(frame);
|
|
162
|
+
this.container.current?.appendChild(frame);
|
|
165
163
|
|
|
166
164
|
this._frame = frame;
|
|
167
165
|
}
|
|
@@ -181,8 +179,9 @@ class IframeContentRenderer extends React.Component<Props> {
|
|
|
181
179
|
}
|
|
182
180
|
|
|
183
181
|
render(): React.ReactNode {
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
return (
|
|
183
|
+
<div ref={this.container} style={{width: "100%", height: "100%"}} />
|
|
184
|
+
);
|
|
186
185
|
}
|
|
187
186
|
}
|
|
188
187
|
|
package/src/item-editor.tsx
CHANGED
|
@@ -42,6 +42,10 @@ class ItemEditor extends React.Component<Props> {
|
|
|
42
42
|
answerArea: {},
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
frame = React.createRef<IframeContentRenderer>();
|
|
46
|
+
questionEditor = React.createRef<Editor>();
|
|
47
|
+
itemExtrasEditor = React.createRef<ItemExtrasEditor>();
|
|
48
|
+
|
|
45
49
|
// Notify the parent that the question or answer area has been updated.
|
|
46
50
|
updateProps: ChangeHandler = (newProps, cb, silent) => {
|
|
47
51
|
const props = _(this.props).pick("question", "answerArea");
|
|
@@ -50,9 +54,7 @@ class ItemEditor extends React.Component<Props> {
|
|
|
50
54
|
};
|
|
51
55
|
|
|
52
56
|
triggerPreviewUpdate: (newData?: any) => void = (newData: any) => {
|
|
53
|
-
|
|
54
|
-
// @ts-expect-error - TS2339 - Property 'sendNewData' does not exist on type 'ReactInstance'.
|
|
55
|
-
this.refs.frame.sendNewData(newData);
|
|
57
|
+
this.frame.current?.sendNewData(newData);
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
handleEditorChange: ChangeHandler = (newProps, cb, silent) => {
|
|
@@ -66,9 +68,7 @@ class ItemEditor extends React.Component<Props> {
|
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
getSaveWarnings: () => any = () => {
|
|
69
|
-
|
|
70
|
-
// @ts-expect-error - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
|
|
71
|
-
return this.refs.questionEditor.getSaveWarnings();
|
|
71
|
+
return this.questionEditor.current?.getSaveWarnings();
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
serialize: (options?: any) => {
|
|
@@ -80,12 +80,8 @@ class ItemEditor extends React.Component<Props> {
|
|
|
80
80
|
question: any;
|
|
81
81
|
} = (options: any) => {
|
|
82
82
|
return {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
question: this.refs.questionEditor.serialize(options),
|
|
86
|
-
// eslint-disable-next-line react/no-string-refs
|
|
87
|
-
// @ts-expect-error - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
88
|
-
answerArea: this.refs.itemExtrasEditor.serialize(options),
|
|
83
|
+
question: this.questionEditor.current?.serialize(options),
|
|
84
|
+
answerArea: this.itemExtrasEditor.current?.serialize(),
|
|
89
85
|
itemDataVersion: ITEM_DATA_VERSION,
|
|
90
86
|
};
|
|
91
87
|
};
|
|
@@ -100,8 +96,7 @@ class ItemEditor extends React.Component<Props> {
|
|
|
100
96
|
<div className="perseus-editor-left-cell">
|
|
101
97
|
<div className="pod-title">Question</div>
|
|
102
98
|
<Editor
|
|
103
|
-
|
|
104
|
-
ref="questionEditor"
|
|
99
|
+
ref={this.questionEditor}
|
|
105
100
|
// Using the AssessmentItem content ID as the key
|
|
106
101
|
// ensures that when the user navigates to another
|
|
107
102
|
// item in the Sidebar, the question editor is
|
|
@@ -124,8 +119,7 @@ class ItemEditor extends React.Component<Props> {
|
|
|
124
119
|
nochrome={true}
|
|
125
120
|
>
|
|
126
121
|
<IframeContentRenderer
|
|
127
|
-
|
|
128
|
-
ref="frame"
|
|
122
|
+
ref={this.frame}
|
|
129
123
|
key={this.props.deviceType}
|
|
130
124
|
datasetKey="mobile"
|
|
131
125
|
datasetValue={isMobile}
|
|
@@ -146,8 +140,7 @@ class ItemEditor extends React.Component<Props> {
|
|
|
146
140
|
<div className="perseus-editor-left-cell">
|
|
147
141
|
<div className="pod-title">Question extras</div>
|
|
148
142
|
<ItemExtrasEditor
|
|
149
|
-
|
|
150
|
-
ref="itemExtrasEditor"
|
|
143
|
+
ref={this.itemExtrasEditor}
|
|
151
144
|
onChange={this.handleItemExtrasChange}
|
|
152
145
|
{...this.props.answerArea}
|
|
153
146
|
/>
|
|
@@ -6,7 +6,9 @@ describe("Registering all widgets and editors", () => {
|
|
|
6
6
|
it("should have an editor for every widget", () => {
|
|
7
7
|
registerAllWidgetsAndEditorsForTesting();
|
|
8
8
|
|
|
9
|
-
const allWidgetsTypes = Widgets.getAllWidgetTypes()
|
|
9
|
+
const allWidgetsTypes = Widgets.getAllWidgetTypes()
|
|
10
|
+
// Auto correct is a special kind of widget, it DOES NOT need an editor
|
|
11
|
+
.filter((a) => a !== "deprecated-standin");
|
|
10
12
|
|
|
11
13
|
expect(allWidgetsTypes).not.toContain("undefined");
|
|
12
14
|
|
|
@@ -19,6 +19,8 @@ class ExampleWidgetEditor extends React.Component<Props> {
|
|
|
19
19
|
correct: "",
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
input = React.createRef<HTMLInputElement>();
|
|
23
|
+
|
|
22
24
|
handleAnswerChange: (arg1: React.ChangeEvent<HTMLInputElement>) => void = (
|
|
23
25
|
event,
|
|
24
26
|
) => {
|
|
@@ -36,8 +38,7 @@ class ExampleWidgetEditor extends React.Component<Props> {
|
|
|
36
38
|
<input
|
|
37
39
|
value={this.props.correct}
|
|
38
40
|
onChange={this.handleAnswerChange}
|
|
39
|
-
|
|
40
|
-
ref="input"
|
|
41
|
+
ref={this.input}
|
|
41
42
|
/>
|
|
42
43
|
</label>
|
|
43
44
|
</div>
|
|
@@ -49,9 +50,7 @@ class ExampleWidgetEditor extends React.Component<Props> {
|
|
|
49
50
|
};
|
|
50
51
|
|
|
51
52
|
focus: () => boolean = () => {
|
|
52
|
-
|
|
53
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
54
|
-
this.refs.input.focus();
|
|
53
|
+
this.input.current?.focus();
|
|
55
54
|
return true;
|
|
56
55
|
};
|
|
57
56
|
|
|
@@ -16,11 +16,12 @@ import _ from "underscore";
|
|
|
16
16
|
import type {WidgetExports} from "@khanacademy/perseus";
|
|
17
17
|
|
|
18
18
|
class TextInput extends React.Component<any> {
|
|
19
|
+
input = React.createRef<HTMLInputElement>();
|
|
20
|
+
|
|
19
21
|
render(): React.ReactNode {
|
|
20
22
|
return (
|
|
21
23
|
<input
|
|
22
|
-
|
|
23
|
-
ref="input"
|
|
24
|
+
ref={this.input}
|
|
24
25
|
value={this.props.value || ""}
|
|
25
26
|
onChange={this.changeValue}
|
|
26
27
|
/>
|
|
@@ -28,9 +29,7 @@ class TextInput extends React.Component<any> {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
focus = () => {
|
|
31
|
-
|
|
32
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
33
|
-
this.refs.input.focus();
|
|
32
|
+
this.input.current?.focus();
|
|
34
33
|
return true;
|
|
35
34
|
};
|
|
36
35
|
|
|
@@ -56,6 +55,8 @@ class ExampleWidget extends React.Component<any> {
|
|
|
56
55
|
value: "",
|
|
57
56
|
};
|
|
58
57
|
|
|
58
|
+
input = React.createRef<TextInput>();
|
|
59
|
+
|
|
59
60
|
/**
|
|
60
61
|
* This is the widget's grading function. simpleValidate generally
|
|
61
62
|
* defers to this function.
|
|
@@ -98,8 +99,7 @@ class ExampleWidget extends React.Component<any> {
|
|
|
98
99
|
render(): React.ReactNode {
|
|
99
100
|
return (
|
|
100
101
|
<TextInput
|
|
101
|
-
|
|
102
|
-
ref="input"
|
|
102
|
+
ref={this.input}
|
|
103
103
|
value={this.props.value}
|
|
104
104
|
// @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
|
|
105
105
|
onChange={this.change("value")}
|
|
@@ -117,9 +117,7 @@ class ExampleWidget extends React.Component<any> {
|
|
|
117
117
|
* focused on page load.
|
|
118
118
|
*/
|
|
119
119
|
focus: () => boolean = () => {
|
|
120
|
-
|
|
121
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
122
|
-
this.refs.input.focus();
|
|
120
|
+
this.input.current?.focus();
|
|
123
121
|
return true;
|
|
124
122
|
};
|
|
125
123
|
|
|
@@ -33,6 +33,9 @@ class GradedGroupEditor extends React.Component<Props> {
|
|
|
33
33
|
hint: null,
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
editor = React.createRef<Editor>();
|
|
37
|
+
hintEditor = React.createRef<Editor>();
|
|
38
|
+
|
|
36
39
|
change: (arg1: any, arg2: any, arg3: any) => any = (...args) => {
|
|
37
40
|
return Changeable.change.apply(this, args);
|
|
38
41
|
};
|
|
@@ -40,9 +43,7 @@ class GradedGroupEditor extends React.Component<Props> {
|
|
|
40
43
|
handleAddHint: () => void = () => {
|
|
41
44
|
const hint = {content: ""} as const;
|
|
42
45
|
this.props.onChange({hint}, () => {
|
|
43
|
-
|
|
44
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
45
|
-
this.refs["hint-editor"].focus();
|
|
46
|
+
this.hintEditor.current?.focus();
|
|
46
47
|
});
|
|
47
48
|
};
|
|
48
49
|
|
|
@@ -65,8 +66,7 @@ class GradedGroupEditor extends React.Component<Props> {
|
|
|
65
66
|
</label>
|
|
66
67
|
</div>
|
|
67
68
|
<Editor
|
|
68
|
-
|
|
69
|
-
ref="editor"
|
|
69
|
+
ref={this.editor}
|
|
70
70
|
content={this.props.content}
|
|
71
71
|
widgets={this.props.widgets}
|
|
72
72
|
apiOptions={this.props.apiOptions}
|
|
@@ -91,8 +91,7 @@ class GradedGroupEditor extends React.Component<Props> {
|
|
|
91
91
|
<div className="perseus-hint-editor">
|
|
92
92
|
<div className={css(styles.hintsTitle)}>Hint</div>
|
|
93
93
|
<Editor
|
|
94
|
-
|
|
95
|
-
ref="hint-editor"
|
|
94
|
+
ref={this.hintEditor}
|
|
96
95
|
content={
|
|
97
96
|
this.props.hint ? this.props.hint.content : ""
|
|
98
97
|
}
|
|
@@ -127,9 +126,7 @@ class GradedGroupEditor extends React.Component<Props> {
|
|
|
127
126
|
}
|
|
128
127
|
|
|
129
128
|
getSaveWarnings: () => any = () => {
|
|
130
|
-
|
|
131
|
-
// @ts-expect-error - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
|
|
132
|
-
return this.refs.editor.getSaveWarnings();
|
|
129
|
+
return this.editor.current?.getSaveWarnings();
|
|
133
130
|
};
|
|
134
131
|
|
|
135
132
|
serialize: () => {
|
|
@@ -138,15 +135,8 @@ class GradedGroupEditor extends React.Component<Props> {
|
|
|
138
135
|
} = () => {
|
|
139
136
|
return {
|
|
140
137
|
title: this.props.title,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
...this.refs.editor.serialize(),
|
|
144
|
-
hint:
|
|
145
|
-
// eslint-disable-next-line react/no-string-refs
|
|
146
|
-
this.refs["hint-editor"] &&
|
|
147
|
-
// eslint-disable-next-line react/no-string-refs
|
|
148
|
-
// @ts-expect-error - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
149
|
-
this.refs["hint-editor"].serialize(),
|
|
138
|
+
...this.editor.current?.serialize(),
|
|
139
|
+
hint: this.hintEditor.current?.serialize(),
|
|
150
140
|
};
|
|
151
141
|
};
|
|
152
142
|
}
|
|
@@ -30,6 +30,8 @@ class GroupEditor extends React.Component<Props> {
|
|
|
30
30
|
metadata: undefined,
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
editor = React.createRef<Editor>();
|
|
34
|
+
|
|
33
35
|
render(): React.ReactNode {
|
|
34
36
|
return (
|
|
35
37
|
<div className="perseus-group-editor">
|
|
@@ -39,8 +41,7 @@ class GroupEditor extends React.Component<Props> {
|
|
|
39
41
|
{this._renderMetadataEditor()}
|
|
40
42
|
</div>
|
|
41
43
|
<Editor
|
|
42
|
-
|
|
43
|
-
ref="editor"
|
|
44
|
+
ref={this.editor}
|
|
44
45
|
content={this.props.content}
|
|
45
46
|
widgets={this.props.widgets}
|
|
46
47
|
apiOptions={this.props.apiOptions}
|
|
@@ -69,15 +70,11 @@ class GroupEditor extends React.Component<Props> {
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
getSaveWarnings: () => ReadonlyArray<any> = () => {
|
|
72
|
-
|
|
73
|
-
// @ts-expect-error - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
|
|
74
|
-
return this.refs.editor.getSaveWarnings();
|
|
73
|
+
return this.editor.current?.getSaveWarnings();
|
|
75
74
|
};
|
|
76
75
|
|
|
77
76
|
serialize: () => any = () => {
|
|
78
|
-
|
|
79
|
-
// @ts-expect-error - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
80
|
-
return _.extend({}, this.refs.editor.serialize(), {
|
|
77
|
+
return _.extend({}, this.editor.current?.serialize(), {
|
|
81
78
|
metadata: this.props.metadata,
|
|
82
79
|
});
|
|
83
80
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable react/sort-comp */
|
|
2
2
|
import {components, Util} from "@khanacademy/perseus";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import ReactDOM from "react-dom";
|
|
5
4
|
import _ from "underscore";
|
|
6
5
|
|
|
7
6
|
import BlurInput from "../components/blur-input";
|
|
@@ -90,6 +89,8 @@ class InputNumberEditor extends React.Component<Props> {
|
|
|
90
89
|
rightAlign: false,
|
|
91
90
|
};
|
|
92
91
|
|
|
92
|
+
input = React.createRef<BlurInput>();
|
|
93
|
+
|
|
93
94
|
handleAnswerChange: (arg1: string) => void = (str) => {
|
|
94
95
|
const value = Util.firstNumericalParse(str) || 0;
|
|
95
96
|
this.props.onChange({value: value});
|
|
@@ -116,8 +117,7 @@ class InputNumberEditor extends React.Component<Props> {
|
|
|
116
117
|
<BlurInput
|
|
117
118
|
value={"" + this.props.value}
|
|
118
119
|
onChange={this.handleAnswerChange}
|
|
119
|
-
|
|
120
|
-
ref="input"
|
|
120
|
+
ref={this.input}
|
|
121
121
|
/>
|
|
122
122
|
</label>
|
|
123
123
|
</div>
|
|
@@ -262,8 +262,7 @@ class InputNumberEditor extends React.Component<Props> {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
focus: () => boolean = () => {
|
|
265
|
-
|
|
266
|
-
ReactDOM.findDOMNode(this.refs.input).focus(); // eslint-disable-line react/no-string-refs
|
|
265
|
+
this.input.current?.focus();
|
|
267
266
|
return true;
|
|
268
267
|
};
|
|
269
268
|
|
|
@@ -49,6 +49,8 @@ class SimpleMarkdownTesterEditor extends React.Component<SimpleMarkdownTesterEdi
|
|
|
49
49
|
value: "",
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
input = React.createRef<TextArea>();
|
|
53
|
+
|
|
52
54
|
render(): React.ReactNode {
|
|
53
55
|
return (
|
|
54
56
|
<div>
|
|
@@ -59,8 +61,7 @@ class SimpleMarkdownTesterEditor extends React.Component<SimpleMarkdownTesterEdi
|
|
|
59
61
|
value={this.props.value}
|
|
60
62
|
// @ts-expect-error - TS2554 - Expected 3 arguments, but got 1.
|
|
61
63
|
onChange={this.change("value")}
|
|
62
|
-
|
|
63
|
-
ref="input"
|
|
64
|
+
ref={this.input}
|
|
64
65
|
/>
|
|
65
66
|
</div>
|
|
66
67
|
</label>
|
|
@@ -73,9 +74,7 @@ class SimpleMarkdownTesterEditor extends React.Component<SimpleMarkdownTesterEdi
|
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
focus: () => boolean = () => {
|
|
76
|
-
|
|
77
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
78
|
-
this.refs.input.focus();
|
|
77
|
+
this.input.current?.focus();
|
|
79
78
|
return true;
|
|
80
79
|
};
|
|
81
80
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import {components, TableWidget, Util} from "@khanacademy/perseus";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import * as React from "react";
|
|
5
|
-
import ReactDOM from "react-dom";
|
|
6
5
|
import _ from "underscore";
|
|
7
6
|
|
|
8
7
|
import Editor from "../editor";
|
|
@@ -36,9 +35,10 @@ class TableEditor extends React.Component<Props> {
|
|
|
36
35
|
};
|
|
37
36
|
})();
|
|
38
37
|
|
|
38
|
+
numberOfColumns = React.createRef<components.NumberInput>();
|
|
39
|
+
|
|
39
40
|
focus: () => void = () => {
|
|
40
|
-
|
|
41
|
-
ReactDOM.findDOMNode(this.refs.numberOfColumns).focus(); // eslint-disable-line react/no-string-refs
|
|
41
|
+
this.numberOfColumns.current?.focus();
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
render(): React.ReactNode {
|
|
@@ -63,8 +63,7 @@ class TableEditor extends React.Component<Props> {
|
|
|
63
63
|
<label>
|
|
64
64
|
Number of columns:{" "}
|
|
65
65
|
<NumberInput
|
|
66
|
-
|
|
67
|
-
ref="numberOfColumns"
|
|
66
|
+
ref={this.numberOfColumns}
|
|
68
67
|
value={this.props.columns}
|
|
69
68
|
onChange={(val) => {
|
|
70
69
|
if (val) {
|