Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/rich-crabs-hunt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@khanacademy/perseus": patch
"@khanacademy/perseus-editor": patch
---

Remove some string refs (the more straightforward ones)
17 changes: 8 additions & 9 deletions packages/perseus-editor/src/components/graph-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from "@khanacademy/perseus";
import {Checkbox} from "@khanacademy/wonder-blocks-form";
import * as React from "react";
import ReactDOM from "react-dom";
import _ from "underscore";

import type {Coords, MarkingsType} from "@khanacademy/perseus-core";
Expand Down Expand Up @@ -104,6 +103,10 @@ class GraphSettings extends React.Component<Props, State> {

_isMounted = false;

bgUrlRef = React.createRef<HTMLInputElement>();
labelsXRef = React.createRef<HTMLInputElement>();
labelsYRef = React.createRef<HTMLInputElement>();

constructor(props) {
super(props);
this.state = this.getInitialState();
Expand Down Expand Up @@ -197,8 +200,7 @@ class GraphSettings extends React.Component<Props, State> {
);
};

// @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
const url = ReactDOM.findDOMNode(this.refs["bg-url"]).value; // eslint-disable-line react/no-string-refs
const url = this.bgUrlRef.current?.value;
if (url) {
Util.getImageSize(url, (width, height) => {
if (this._isMounted) {
Expand Down Expand Up @@ -481,8 +483,7 @@ class GraphSettings extends React.Component<Props, State> {
id="labels-x"
type="text"
className="graph-settings-axis-label"
// eslint-disable-next-line react/no-string-refs
ref="labels-0"
ref={this.labelsXRef}
onChange={(e) => this.changeLabel(0, e)}
value={this.state.labelsTextbox[0] || ""}
/>
Expand All @@ -493,8 +494,7 @@ class GraphSettings extends React.Component<Props, State> {
id="labels-y"
type="text"
className="graph-settings-axis-label"
// eslint-disable-next-line react/no-string-refs
ref="labels-1"
ref={this.labelsYRef}
onChange={(e) => this.changeLabel(1, e)}
value={this.state.labelsTextbox[1] || ""}
/>
Expand Down Expand Up @@ -588,8 +588,7 @@ class GraphSettings extends React.Component<Props, State> {
id="bg-url"
type="text"
className="graph-settings-background-url"
// eslint-disable-next-line react/no-string-refs
ref="bg-url"
ref={this.bgUrlRef}
value={this.state.backgroundImage.url || ""}
onChange={(e) => {
const image = _.clone(
Expand Down
4 changes: 1 addition & 3 deletions packages/perseus-editor/src/components/widget-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,7 @@ class WidgetEditor extends React.Component<
alignment: widgetInfo.alignment,
static: widgetInfo.static,
graded: widgetInfo.graded,
// eslint-disable-next-line react/no-string-refs
// @ts-expect-error - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
options: this.widget.current.serialize(),
options: this.widget.current?.serialize(),
version: widgetInfo.version,
};
};
Expand Down
7 changes: 0 additions & 7 deletions packages/perseus-editor/src/widgets/expression-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,6 @@ class ExpressionEditor extends React.Component<Props, State> {
this.props.onChange({buttonSets});
};

// called when the correct answer changes
handleTexInsert: (arg1: string) => void = (str) => {
// eslint-disable-next-line react/no-string-refs
// @ts-expect-error - TS2339 - Property 'insert' does not exist on type 'ReactInstance'.
this.refs.expression.insert(str);
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this wasn't being used anywhere.

// called when the function variables change
handleFunctions: (value: string) => void = (value) => {
this.setState({functionsInternal: value});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ class InteractiveGraphEditor extends React.Component<Props> {
lockedFigures: [],
};

graphRef = React.createRef<typeof InteractiveGraph.prototype>();

changeStartCoords = (coords) => {
if (!this.props.graph?.type) {
return;
Expand Down Expand Up @@ -202,13 +204,9 @@ class InteractiveGraphEditor extends React.Component<Props> {
"fullGraphAriaDescription",
);

// eslint-disable-next-line react/no-string-refs
const graph = this.refs.graph;
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
const graph = this.graphRef.current;
if (graph) {
// @ts-expect-error TS2339 Property 'getUserInput' does not exist on type 'ReactInstance'. Property 'getUserInput' does not exist on type 'Component<any, {}, any>'.
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
const correct = graph && graph.getUserInput();
const correct = graph.getUserInput();
_.extend(json, {
graph: {
type: correct.type,
Expand Down Expand Up @@ -292,7 +290,6 @@ class InteractiveGraphEditor extends React.Component<Props> {

// TODO(aria): send these down all at once
const graphProps = {
ref: "graph",
box: this.props.box,
range: this.props.range,
showAxisArrows: this.props.showAxisArrows,
Expand Down Expand Up @@ -338,6 +335,7 @@ class InteractiveGraphEditor extends React.Component<Props> {
// bother passing.
// @ts-expect-error - TS2769 - No overload matches this call.
<InteractiveGraph
ref={this.graphRef}
{...graphProps}
containerSizeClass={sizeClass}
apiOptions={{
Expand Down
4 changes: 0 additions & 4 deletions packages/perseus-editor/src/widgets/matrix-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ class MatrixEditor extends React.Component<Props> {
{" "}
Matrix prefix:{" "}
<Editor
// eslint-disable-next-line react/no-string-refs
ref="prefix"
apiOptions={this.props.apiOptions}
content={this.props.prefix}
widgetEnabled={false}
Expand All @@ -115,8 +113,6 @@ class MatrixEditor extends React.Component<Props> {
{" "}
Matrix suffix:{" "}
<Editor
// eslint-disable-next-line react/no-string-refs
ref="suffix"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like these weren't being used.

apiOptions={this.props.apiOptions}
content={this.props.suffix}
widgetEnabled={false}
Expand Down
2 changes: 0 additions & 2 deletions packages/perseus-editor/src/widgets/measurer-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ class MeasurerEditor extends React.Component<Props> {
<input
type="text"
className="perseus-widget-measurer-url"
// eslint-disable-next-line react/no-string-refs
ref="image-url"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this wasn't being used.

defaultValue={image.url}
onChange={this._changeUrl}
/>
Expand Down
4 changes: 0 additions & 4 deletions packages/perseus-editor/src/widgets/passage-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ class PassageEditor extends React.Component<Props> {
render(): React.ReactNode {
const passageEditor = (
<Editor
// eslint-disable-next-line react/no-string-refs
ref="passage-editor"
apiOptions={this.props.apiOptions}
content={this.props.passageText}
widgetEnabled={false}
Expand All @@ -52,8 +50,6 @@ class PassageEditor extends React.Component<Props> {
);
const footnotesEditor = (
<Editor
// eslint-disable-next-line react/no-string-refs
ref="passage-footnotes-editor"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like these weren't being used.

apiOptions={this.props.apiOptions}
content={this.props.footnotes}
widgetEnabled={false}
Expand Down
26 changes: 6 additions & 20 deletions packages/perseus-editor/src/widgets/plotter-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {number as knumber} from "@khanacademy/kmath";
import {components, PlotterWidget, Util} from "@khanacademy/perseus";
import {plotterLogic, plotterPlotTypes} from "@khanacademy/perseus-core";
import * as React from "react";
import ReactDOM from "react-dom";
import _ from "underscore";

import BlurInput from "../components/blur-input";
Expand Down Expand Up @@ -90,6 +89,8 @@ class PlotterEditor extends React.Component<Props, State> {
tickStep: null,
};

maxYRef = React.createRef<HTMLInputElement>();

// TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
UNSAFE_componentWillMount() {
this.fetchPic(this.props.picUrl);
Expand Down Expand Up @@ -157,13 +158,6 @@ class PlotterEditor extends React.Component<Props, State> {
} else {
this.props.onChange({type: type});
}

if (categories) {
// eslint-disable-next-line react/no-string-refs
const node = ReactDOM.findDOMNode(this.refs.categories);
// @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
node.value = categories.join(", ");
}
};

changeLabel: (arg1: number, arg2: any) => void = (i, e) => {
Expand Down Expand Up @@ -214,8 +208,9 @@ class PlotterEditor extends React.Component<Props, State> {
starting: _.map(this.props.starting, scale),
});

// @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
ReactDOM.findDOMNode(this.refs.maxY).value = maxY; // eslint-disable-line react/no-string-refs
if (this.maxYRef.current) {
this.maxYRef.current.value = String(maxY);
}
};

changeMax: (arg1: any) => void = (e) => {
Expand Down Expand Up @@ -254,12 +249,6 @@ class PlotterEditor extends React.Component<Props, State> {
categories = _.map(categories, formatNumber);

this.changeCategories(categories);

// eslint-disable-next-line react/no-string-refs
const node = ReactDOM.findDOMNode(this.refs.categories);

// @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
node.value = categories.join(", ");
};

serialize: () => any = () => {
Expand Down Expand Up @@ -421,8 +410,6 @@ class PlotterEditor extends React.Component<Props, State> {
<label>
Categories:{" "}
<TextListEditor
// eslint-disable-next-line react/no-string-refs
ref="categories"
layout="horizontal"
options={this.props.categories}
onChange={this.changeCategories}
Expand All @@ -444,8 +431,7 @@ class PlotterEditor extends React.Component<Props, State> {
Max y:{" "}
<input
type="text"
// eslint-disable-next-line react/no-string-refs
ref="maxY"
ref={this.maxYRef}
onChange={this.changeMax}
defaultValue={this.props.maxY}
/>
Expand Down
9 changes: 0 additions & 9 deletions packages/perseus-editor/src/widgets/table-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ class TableEditor extends React.Component<Props> {
static defaultProps: TableDefaultWidgetOptions =
tableLogic.defaultWidgetOptions;

numberOfColumns = React.createRef<components.NumberInput>();

focus: () => void = () => {
this.numberOfColumns.current?.focus();
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this focus method wasn't actually ever being used. And that also means none of the refs were being used.

onSizeInput: (arg1: number, arg2: number) => void = (
numRawRows,
numRawColumns,
Expand Down Expand Up @@ -117,7 +111,6 @@ class TableEditor extends React.Component<Props> {
<label>
Number of columns:{" "}
<NumberInput
ref={this.numberOfColumns}
value={this.props.columns}
onChange={(val) => {
if (val) {
Expand All @@ -132,8 +125,6 @@ class TableEditor extends React.Component<Props> {
<label>
Number of rows:{" "}
<NumberInput
// eslint-disable-next-line react/no-string-refs
ref="numberOfRows"
value={this.props.rows}
onChange={(val) => {
if (val) {
Expand Down
2 changes: 0 additions & 2 deletions packages/perseus/src/components/svg-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,6 @@ class SvgImage extends React.Component<Props, State> {
// documented where it came from.
graphie = (
<Graphie
// eslint-disable-next-line react/no-string-refs
ref="graphie"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this wasn't being used.

box={box}
scale={[40 * this.props.scale, 40 * this.props.scale]}
range={this.state.range}
Expand Down
50 changes: 24 additions & 26 deletions packages/perseus/src/widgets/expression/expression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export class Expression extends React.Component<Props> implements Widget {
_textareaId = `expression_textarea_${Date.now()}`;
_isMounted = false;

keypadInputRef = React.createRef<KeypadInput>();
mathInputRef = React.createRef<MathInput>();

static defaultProps: DefaultProps = {
times: false,
functions: [],
Expand Down Expand Up @@ -119,10 +122,12 @@ export class Expression extends React.Component<Props> implements Widget {
// HACK: imperatively add an ID onto the Mathquill input
// (which in mobile is a span; desktop a textarea)
// in order to associate a visual label with it
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (this.refs.input) {
const isMobile = this.props.apiOptions.customKeypad;
const container = ReactDOM.findDOMNode(this.refs.input);
const isMobile = this.props.apiOptions.customKeypad;
const inputComponent = isMobile
? this.keypadInputRef.current
: this.mathInputRef.current;
if (inputComponent) {
const container = ReactDOM.findDOMNode(inputComponent);
const selector = isMobile ? ".mq-textarea > span" : "textarea";
const inputElement = (container as Element).querySelector(selector);
inputElement?.setAttribute("id", this._textareaId);
Expand Down Expand Up @@ -166,38 +171,33 @@ export class Expression extends React.Component<Props> implements Widget {

focus: () => boolean = () => {
if (this.props.apiOptions.customKeypad) {
// eslint-disable-next-line react/no-string-refs
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
this.refs.input.focus();
// KeypadInput's focus() requires a setKeypadActive parameter,
// but we don't have access to it here, so we just don't call focus
// TODO: Investigate if this is needed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to make sure — did you get a chance to test this on mobile? Since focus() now behaves differently with the custom keypad, I want to make sure we didn't accidentally change the UX.

Also, should we create a ticket to track the TODO here so it doesn't get lost?

} else {
this.mathInputRef.current?.focus();
}
return true;
};

// TODO(LEMS-2656): remove TS suppression
// @ts-expect-error: Type 'FocusPath' is not assignable to type 'InputPath'.
focusInputPath(inputPath: InputPath) {
// eslint-disable-next-line react/no-string-refs
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
this.refs.input.focus();
this.mathInputRef.current?.focus();
}

// TODO(LEMS-2656): remove TS suppression
// @ts-expect-error: Type 'FocusPath' is not assignable to type 'InputPath'.
blurInputPath(inputPath: InputPath) {
// eslint-disable-next-line react/no-string-refs
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
if (typeof this.refs.input?.blur === "function") {
// eslint-disable-next-line react/no-string-refs
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
this.refs.input?.blur();
blurInputPath() {
if (this.props.apiOptions.customKeypad) {
this.keypadInputRef.current?.blur();
} else {
this.mathInputRef.current?.blur();
}
}

// HACK(joel)
insert(keyPressed: KeypadKey) {
// eslint-disable-next-line react/no-string-refs
// @ts-expect-error - TS2339 - Property 'insert' does not exist on type 'ReactInstance'.
this.refs.input.insert(keyPressed);
// Only the Perseus MathInput has the insert method
this.mathInputRef.current?.insert(keyPressed);
}

getInputPaths: () => ReadonlyArray<ReadonlyArray<any>> = () => {
Expand Down Expand Up @@ -240,8 +240,7 @@ export class Expression extends React.Component<Props> implements Widget {
</LabelSmall>
)}
<KeypadInput
// eslint-disable-next-line react/no-string-refs
ref="input"
ref={this.keypadInputRef}
ariaLabel={
this.props.ariaLabel ||
this.context.strings.mathInputBox
Expand Down Expand Up @@ -278,8 +277,7 @@ export class Expression extends React.Component<Props> implements Widget {
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions -- TODO(LEMS-2871): Address a11y error */}
<div className="perseus-widget-expression">
<MathInput
// eslint-disable-next-line react/no-string-refs
ref="input"
ref={this.mathInputRef}
value={this.props.userInput}
onChange={this.changeAndTrack}
convertDotToTimes={this.props.times}
Expand Down
Loading