diff --git a/.changeset/giant-tables-impress.md b/.changeset/giant-tables-impress.md new file mode 100644 index 0000000000..32f5de4204 --- /dev/null +++ b/.changeset/giant-tables-impress.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus": patch +--- + +Remove usage of findDOMNode in text-input component diff --git a/packages/perseus/src/components/text-input.tsx b/packages/perseus/src/components/text-input.tsx index abcb259260..83ad468395 100644 --- a/packages/perseus/src/components/text-input.tsx +++ b/packages/perseus/src/components/text-input.tsx @@ -1,7 +1,7 @@ /* eslint-disable @khanacademy/ts-no-error-suppressions */ +import {Errors, PerseusError} from "@khanacademy/perseus-core"; import {TextField} from "@khanacademy/wonder-blocks-form"; import * as React from "react"; -import ReactDOM from "react-dom"; import type {StyleType} from "@khanacademy/wonder-blocks-core"; @@ -31,6 +31,7 @@ function uniqueIdForInput(prefix = "input-") { } class TextInput extends React.Component { + inputRef = React.createRef(); static defaultProps: DefaultProps = { value: "", disabled: false, @@ -47,45 +48,46 @@ class TextInput extends React.Component { } } + _getInput: () => HTMLInputElement = () => { + if (!this.inputRef.current) { + throw new PerseusError( + "Input ref accessed before set", + Errors.Internal, + ); + } + + return this.inputRef.current; + }; + focus: () => void = () => { - // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'. - ReactDOM.findDOMNode(this).focus(); + this._getInput().focus(); }; blur: () => void = () => { - // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'. - ReactDOM.findDOMNode(this).blur(); + this._getInput().blur(); }; getValue: () => string | null | undefined = () => { - // @ts-expect-error - TS2339 - Property 'value' does not exist on type 'Element | Text'. - return ReactDOM.findDOMNode(this)?.value; + return this.inputRef.current?.value; }; getStringValue: () => string | null | undefined = () => { - // @ts-expect-error - TS2339 - Property 'value' does not exist on type 'Element | Text'. - return ReactDOM.findDOMNode(this)?.value.toString(); + return this.inputRef.current?.value.toString(); }; setSelectionRange: (arg1: number, arg2: number) => void = ( selectionStart, selectionEnd, ) => { - // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'. - ReactDOM.findDOMNode(this).setSelectionRange( - selectionStart, - selectionEnd, - ); + this._getInput().setSelectionRange(selectionStart, selectionEnd); }; - getSelectionStart: () => number = () => { - // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'. - return ReactDOM.findDOMNode(this).selectionStart; + getSelectionStart: () => number | null = () => { + return this._getInput().selectionStart; }; - getSelectionEnd: () => number = () => { - // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'. - return ReactDOM.findDOMNode(this).selectionEnd; + getSelectionEnd: () => number | null = () => { + return this._getInput().selectionEnd; }; render(): React.ReactNode { @@ -104,6 +106,7 @@ class TextInput extends React.Component { return (