diff --git a/.changeset/old-fishes-swim.md b/.changeset/old-fishes-swim.md new file mode 100644 index 00000000000..113cc67fb82 --- /dev/null +++ b/.changeset/old-fishes-swim.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus-editor": patch +--- + +Adding improved type safeguards to components folder in perseus-editor. diff --git a/packages/perseus-editor/src/components/__stories__/blur-input.stories.tsx b/packages/perseus-editor/src/components/__docs__/blur-input.stories.tsx similarity index 90% rename from packages/perseus-editor/src/components/__stories__/blur-input.stories.tsx rename to packages/perseus-editor/src/components/__docs__/blur-input.stories.tsx index 3b3d0d2ed0f..1595accd283 100644 --- a/packages/perseus-editor/src/components/__stories__/blur-input.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/blur-input.stories.tsx @@ -4,7 +4,7 @@ import {action} from "storybook/actions"; import BlurInput from "../blur-input"; export default { - title: "PerseusEditor/Components/Blur Input", + title: "Editors/Components/Blur Input", }; export const Default = (): React.ReactElement => { diff --git a/packages/perseus-editor/src/components/__stories__/color-select.stories.tsx b/packages/perseus-editor/src/components/__docs__/color-select.stories.tsx similarity index 95% rename from packages/perseus-editor/src/components/__stories__/color-select.stories.tsx rename to packages/perseus-editor/src/components/__docs__/color-select.stories.tsx index 7acd925132e..ef6b85537e1 100644 --- a/packages/perseus-editor/src/components/__stories__/color-select.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/color-select.stories.tsx @@ -7,7 +7,7 @@ import type {LockedFigureColor} from "@khanacademy/perseus-core"; import type {Meta} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Color Select", + title: "Editors/Components/Color Select", component: ColorSelect, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/color-swatch.stories.tsx b/packages/perseus-editor/src/components/__docs__/color-swatch.stories.tsx similarity index 91% rename from packages/perseus-editor/src/components/__stories__/color-swatch.stories.tsx rename to packages/perseus-editor/src/components/__docs__/color-swatch.stories.tsx index 25c06d4a4fd..c674445bb9e 100644 --- a/packages/perseus-editor/src/components/__stories__/color-swatch.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/color-swatch.stories.tsx @@ -6,7 +6,7 @@ import ColorSwatch from "../../widgets/interactive-graph-editor/locked-figures/c import type {Meta} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Color Swatch", + title: "Editors/Components/Color Swatch", component: ColorSwatch, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/device-framer.stories.tsx b/packages/perseus-editor/src/components/__docs__/device-framer.stories.tsx similarity index 96% rename from packages/perseus-editor/src/components/__stories__/device-framer.stories.tsx rename to packages/perseus-editor/src/components/__docs__/device-framer.stories.tsx index e57b656ebd4..01335e36e30 100644 --- a/packages/perseus-editor/src/components/__stories__/device-framer.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/device-framer.stories.tsx @@ -7,7 +7,7 @@ import type {Meta, StoryObj} from "@storybook/react-vite"; const meta: Meta = { component: DeviceFramer, - title: "PerseusEditor/Components/Device Framer", + title: "Editors/Components/Device Framer", }; export default meta; diff --git a/packages/perseus-editor/src/components/__stories__/graph-settings.argtypes.ts b/packages/perseus-editor/src/components/__docs__/graph-settings.argtypes.ts similarity index 100% rename from packages/perseus-editor/src/components/__stories__/graph-settings.argtypes.ts rename to packages/perseus-editor/src/components/__docs__/graph-settings.argtypes.ts diff --git a/packages/perseus-editor/src/components/__stories__/graph-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/graph-settings.stories.tsx similarity index 91% rename from packages/perseus-editor/src/components/__stories__/graph-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/graph-settings.stories.tsx index 91d5884ee39..2a741507297 100644 --- a/packages/perseus-editor/src/components/__stories__/graph-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/graph-settings.stories.tsx @@ -5,7 +5,7 @@ import GraphSettings from "../graph-settings"; import GraphSettingsArgTypes from "./graph-settings.argtypes"; export default { - title: "PerseusEditor/Components/Graph Settings", + title: "Editors/Components/Graph Settings", component: GraphSettings, argTypes: GraphSettingsArgTypes, }; diff --git a/packages/perseus-editor/src/components/__stories__/interactive-graph-settings.argtypes.ts b/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.argtypes.ts similarity index 100% rename from packages/perseus-editor/src/components/__stories__/interactive-graph-settings.argtypes.ts rename to packages/perseus-editor/src/components/__docs__/interactive-graph-settings.argtypes.ts diff --git a/packages/perseus-editor/src/components/__stories__/interactive-graph-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.stories.tsx similarity index 95% rename from packages/perseus-editor/src/components/__stories__/interactive-graph-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/interactive-graph-settings.stories.tsx index fcb0d785ba6..4150cc166c1 100644 --- a/packages/perseus-editor/src/components/__stories__/interactive-graph-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.stories.tsx @@ -7,7 +7,7 @@ import InteractiveGraphSettingsArgTypes from "./interactive-graph-settings.argty import type {StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Interactive Graph Settings", + title: "Editors/Components/Interactive Graph Settings", component: InteractiveGraphSettings, argTypes: InteractiveGraphSettingsArgTypes, }; diff --git a/packages/perseus-editor/src/components/__stories__/locked-ellipse-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-ellipse-settings.stories.tsx similarity index 97% rename from packages/perseus-editor/src/components/__stories__/locked-ellipse-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-ellipse-settings.stories.tsx index 8cbaffbe437..5aafd2bfff6 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-ellipse-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-ellipse-settings.stories.tsx @@ -6,7 +6,7 @@ import LockedEllipseSettings from "../../widgets/interactive-graph-editor/locked import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Ellipse Settings", + title: "Editors/Components/Locked Ellipse Settings", component: LockedEllipseSettings, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/locked-figures-section.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-figures-section.stories.tsx similarity index 97% rename from packages/perseus-editor/src/components/__stories__/locked-figures-section.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-figures-section.stories.tsx index e7424367bb1..eae6ee7067a 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-figures-section.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-figures-section.stories.tsx @@ -10,7 +10,7 @@ import LockedFiguresSection from "../../widgets/interactive-graph-editor/locked- import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Figures Section", + title: "Editors/Components/Locked Figures Section", component: LockedFiguresSection, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/locked-function-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-function-settings.stories.tsx similarity index 95% rename from packages/perseus-editor/src/components/__stories__/locked-function-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-function-settings.stories.tsx index c56db6d01df..19c3d0f321f 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-function-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-function-settings.stories.tsx @@ -6,7 +6,7 @@ import LockedFunctionSettings from "../../widgets/interactive-graph-editor/locke import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Function Settings", + title: "Editors/Components/Locked Function Settings", component: LockedFunctionSettings, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/locked-label-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-label-settings.stories.tsx similarity index 95% rename from packages/perseus-editor/src/components/__stories__/locked-label-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-label-settings.stories.tsx index c37141c45c7..7af97e456fe 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-label-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-label-settings.stories.tsx @@ -6,7 +6,7 @@ import LockedLabelSettings from "../../widgets/interactive-graph-editor/locked-f import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Label Settings", + title: "Editors/Components/Locked Label Settings", component: LockedLabelSettings, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/locked-line-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-line-settings.stories.tsx similarity index 98% rename from packages/perseus-editor/src/components/__stories__/locked-line-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-line-settings.stories.tsx index aa78b0e6f2e..f94f16484b7 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-line-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-line-settings.stories.tsx @@ -6,7 +6,7 @@ import LockedLineSettings from "../../widgets/interactive-graph-editor/locked-fi import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Line Settings", + title: "Editors/Components/Locked Line Settings", component: LockedLineSettings, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/locked-point-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-point-settings.stories.tsx similarity index 97% rename from packages/perseus-editor/src/components/__stories__/locked-point-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-point-settings.stories.tsx index b2f2c631175..ad98b9f2a71 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-point-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-point-settings.stories.tsx @@ -6,7 +6,7 @@ import LockedPointSettings from "../../widgets/interactive-graph-editor/locked-f import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Point Settings", + title: "Editors/Components/Locked Point Settings", component: LockedPointSettings, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/locked-polygon-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-polygon-settings.stories.tsx similarity index 97% rename from packages/perseus-editor/src/components/__stories__/locked-polygon-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-polygon-settings.stories.tsx index 83699ae3bd1..b1f016f0d16 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-polygon-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-polygon-settings.stories.tsx @@ -6,7 +6,7 @@ import LockedPolygonSettings from "../../widgets/interactive-graph-editor/locked import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Polygon Settings", + title: "Editors/Components/Locked Polygon Settings", component: LockedPolygonSettings, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/locked-vector-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-vector-settings.stories.tsx similarity index 97% rename from packages/perseus-editor/src/components/__stories__/locked-vector-settings.stories.tsx rename to packages/perseus-editor/src/components/__docs__/locked-vector-settings.stories.tsx index 9db64af36f6..05fd90a8a8d 100644 --- a/packages/perseus-editor/src/components/__stories__/locked-vector-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-vector-settings.stories.tsx @@ -6,7 +6,7 @@ import LockedVectorSettings from "../../widgets/interactive-graph-editor/locked- import type {Meta, StoryObj} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Locked Vector Settings", + title: "Editors/Components/Locked Vector Settings", component: LockedVectorSettings, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/scrollless-number-text-field.stories.tsx b/packages/perseus-editor/src/components/__docs__/scrollless-number-text-field.stories.tsx similarity index 97% rename from packages/perseus-editor/src/components/__stories__/scrollless-number-text-field.stories.tsx rename to packages/perseus-editor/src/components/__docs__/scrollless-number-text-field.stories.tsx index dd262d690ac..1223c84ccef 100644 --- a/packages/perseus-editor/src/components/__stories__/scrollless-number-text-field.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/scrollless-number-text-field.stories.tsx @@ -7,7 +7,7 @@ import ScrolllessNumberTextField from "../scrollless-number-text-field"; import type {StoryObj, Meta} from "@storybook/react-vite"; export default { - title: "PerseusEditor/Components/Scrollless Number Text Field", + title: "Editors/Components/Scrollless Number Text Field", component: ScrolllessNumberTextField, } as Meta; diff --git a/packages/perseus-editor/src/components/__stories__/section-control-button.stories.tsx b/packages/perseus-editor/src/components/__docs__/section-control-button.stories.tsx similarity index 84% rename from packages/perseus-editor/src/components/__stories__/section-control-button.stories.tsx rename to packages/perseus-editor/src/components/__docs__/section-control-button.stories.tsx index 9e628bf4ae0..2eabde1f938 100644 --- a/packages/perseus-editor/src/components/__stories__/section-control-button.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/section-control-button.stories.tsx @@ -3,14 +3,14 @@ import * as React from "react"; import SectionControlButton from "../section-control-button"; -type StoryArgs = Record; +type StoryArgs = Record; type Story = { title: string; }; export default { - title: "PerseusEditor/Components/Section Control Button", + title: "Editors/Components/Section Control Button", } as Story; export const ButtonForEditingSectionsOfContentWithInArticleEditor = ( diff --git a/packages/perseus-editor/src/components/__stories__/toggleable-caret.stories.tsx b/packages/perseus-editor/src/components/__docs__/toggleable-caret.stories.tsx similarity index 93% rename from packages/perseus-editor/src/components/__stories__/toggleable-caret.stories.tsx rename to packages/perseus-editor/src/components/__docs__/toggleable-caret.stories.tsx index 55e59b8b2c7..c5bc966857c 100644 --- a/packages/perseus-editor/src/components/__stories__/toggleable-caret.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/toggleable-caret.stories.tsx @@ -8,7 +8,7 @@ import type {StoryObj, Meta} from "@storybook/react-vite"; type Story = StoryObj; export default { - title: "PerseusEditor/Components/Toggleable Caret", + title: "Editors/Components/Toggleable Caret", component: ToggleableCaret, } satisfies Meta; diff --git a/packages/perseus-editor/src/components/__stories__/viewport-resizer.stories.tsx b/packages/perseus-editor/src/components/__docs__/viewport-resizer.stories.tsx similarity index 93% rename from packages/perseus-editor/src/components/__stories__/viewport-resizer.stories.tsx rename to packages/perseus-editor/src/components/__docs__/viewport-resizer.stories.tsx index 88ef9852425..c901b4268d8 100644 --- a/packages/perseus-editor/src/components/__stories__/viewport-resizer.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/viewport-resizer.stories.tsx @@ -8,7 +8,7 @@ import type {Meta, StoryFn} from "@storybook/react-vite"; const meta: Meta = { component: ViewportResizer, - title: "PerseusEditor/Components/Viewport Resizer", + title: "Editors/Components/Viewport Resizer", }; export default meta; diff --git a/packages/perseus-editor/src/components/__tests__/graph-settings.test.tsx b/packages/perseus-editor/src/components/__tests__/graph-settings.test.tsx index 29bf1fbbf96..26e3e651987 100644 --- a/packages/perseus-editor/src/components/__tests__/graph-settings.test.tsx +++ b/packages/perseus-editor/src/components/__tests__/graph-settings.test.tsx @@ -169,7 +169,6 @@ describe("GraphSettings", () => { // Assert expect(onChange).toHaveBeenCalledWith( expect.objectContaining({markings: "grid"}), - undefined, ); }); @@ -192,7 +191,6 @@ describe("GraphSettings", () => { // Assert expect(onChange).toHaveBeenCalledWith( expect.objectContaining({rulerLabel: "cm"}), - undefined, ); }); @@ -214,7 +212,6 @@ describe("GraphSettings", () => { // Assert expect(onChange).toHaveBeenCalledWith( expect.objectContaining({rulerTicks: 4}), - undefined, ); }); @@ -245,7 +242,6 @@ describe("GraphSettings", () => { url: "https://example.com/image.png", }), }), - undefined, ), ); }); @@ -276,7 +272,6 @@ describe("GraphSettings", () => { expect.objectContaining({ valid: "Image must be smaller than 450px x 450px.", }), - undefined, ), ); }); @@ -306,7 +301,6 @@ describe("GraphSettings", () => { url: null, }), }), - undefined, ), ); }); @@ -353,7 +347,6 @@ describe("GraphSettings", () => { // Assert expect(onChange).toHaveBeenCalledWith( expect.objectContaining({showProtractor: false}), - undefined, ); }); @@ -381,7 +374,6 @@ describe("GraphSettings", () => { ], valid: true, }), - undefined, ), ); }); @@ -410,7 +402,6 @@ describe("GraphSettings", () => { ], valid: true, }), - undefined, ), ); }); @@ -433,13 +424,8 @@ describe("GraphSettings", () => { await waitFor(() => expect(onChange).toHaveBeenCalledWith( expect.objectContaining({ - range: [ - [-10, 10], - [-10, 10], - ], valid: "Range must have a higher number on the right", }), - undefined, ), ); }); @@ -465,7 +451,6 @@ describe("GraphSettings", () => { step: [2, 1], valid: true, }), - undefined, ), ); }); @@ -488,10 +473,8 @@ describe("GraphSettings", () => { await waitFor(() => expect(onChange).toHaveBeenCalledWith( expect.objectContaining({ - step: [1, 1], valid: "Step is too large, there must be at least 3 ticks.", }), - undefined, ), ); }); @@ -521,10 +504,8 @@ describe("GraphSettings", () => { await waitFor(() => expect(onChange).toHaveBeenCalledWith( expect.objectContaining({ - step: [1, 1], valid: "Step is too small, there can be at most 20 ticks.", }), - undefined, ), ); }); @@ -554,7 +535,6 @@ describe("GraphSettings", () => { snapStep: [2, 1], valid: true, }), - undefined, ), ); }); @@ -581,10 +561,8 @@ describe("GraphSettings", () => { await waitFor(() => expect(onChange).toHaveBeenCalledWith( expect.objectContaining({ - snapStep: [1, 1], valid: "Snap step is too large, there must be at least 5 ticks.", }), - undefined, ), ); }); @@ -611,7 +589,6 @@ describe("GraphSettings", () => { gridStep: [2, 1], valid: true, }), - undefined, ), ); }); @@ -635,10 +612,8 @@ describe("GraphSettings", () => { await waitFor(() => expect(onChange).toHaveBeenCalledWith( expect.objectContaining({ - gridStep: [1, 1], valid: "Grid step is too large, there must be at least 3 ticks.", }), - undefined, ), ); }); @@ -664,7 +639,6 @@ describe("GraphSettings", () => { expect.objectContaining({ labels: ["time", "y"], }), - undefined, ), ); }); @@ -690,7 +664,6 @@ describe("GraphSettings", () => { expect.objectContaining({ labels: ["x", "count"], }), - undefined, ), ); }); @@ -719,7 +692,6 @@ describe("GraphSettings", () => { expect.objectContaining({ box: [300, 288], }), - undefined, ), ); }); diff --git a/packages/perseus-editor/src/components/blur-input.tsx b/packages/perseus-editor/src/components/blur-input.tsx index e7a71a98c45..d8603399d46 100644 --- a/packages/perseus-editor/src/components/blur-input.tsx +++ b/packages/perseus-editor/src/components/blur-input.tsx @@ -39,11 +39,11 @@ class BlurInput extends React.Component { this.setState({value: nextProps.value}); } - handleChange: (e: any) => void = (e) => { + handleChange = (e: React.ChangeEvent) => { this.setState({value: e.target.value}); }; - handleBlur: (e: any) => void = (e) => { + handleBlur = (e: React.FocusEvent) => { this.props.onChange(e.target.value); }; diff --git a/packages/perseus-editor/src/components/drag-target.tsx b/packages/perseus-editor/src/components/drag-target.tsx index 956f1aea9cd..ca4b7c10054 100644 --- a/packages/perseus-editor/src/components/drag-target.tsx +++ b/packages/perseus-editor/src/components/drag-target.tsx @@ -13,19 +13,18 @@ * it's a target. */ +import {View} from "@khanacademy/wonder-blocks-core"; import * as React from "react"; type Props = { - onDrop: (e: DragEvent) => void; - component?: any; - shouldDragHighlight: (any) => boolean; - style?: any; - children?: any; + onDrop: (e: React.MouseEvent) => unknown; + shouldDragHighlight: (e: React.MouseEvent) => boolean; + style?: React.CSSProperties; + children?: React.ReactNode; className?: string; }; type DefaultProps = { - component: Props["component"]; shouldDragHighlight: Props["shouldDragHighlight"]; }; @@ -34,11 +33,10 @@ type State = { }; class DragTarget extends React.Component { static defaultProps: DefaultProps = { - component: "div", shouldDragHighlight: () => true, }; - constructor(props) { + constructor(props: Props) { super(props); this.state = { dragHover: false, @@ -51,7 +49,7 @@ class DragTarget extends React.Component { this.handleDragEnter = this.handleDragEnter.bind(this); } - handleDrop(e: DragEvent) { + handleDrop(e: React.MouseEvent) { e.stopPropagation(); e.preventDefault(); this.setState({dragHover: false}); @@ -62,7 +60,7 @@ class DragTarget extends React.Component { this.setState({dragHover: false}); } - handleDragOver(e) { + handleDragOver(e: React.MouseEvent) { e.preventDefault(); } @@ -70,21 +68,20 @@ class DragTarget extends React.Component { this.setState({dragHover: false}); } - handleDragEnter(e) { + handleDragEnter(e: React.MouseEvent) { this.setState({dragHover: this.props.shouldDragHighlight(e)}); } render() { const opacity = this.state.dragHover ? {opacity: 0.3} : {}; const { - component: Component, // eslint-disable-next-line @typescript-eslint/no-unused-vars shouldDragHighlight, ...forwardProps } = this.props; return ( - { // @ts-expect-error - TS2564 - Property 'node' has no initializer and is not definitely assigned in the constructor. node: HTMLDivElement; - handleKeyDown(event: any): void { + handleKeyDown(event: React.KeyboardEvent): void { const {onDropdownClose} = this.props; const pressedKey = event.key; - const focusedElement = event.target; + const focusedElement = event.currentTarget; - if (pressedKey === "ArrowDown" && focusedElement.nextSibling) { + if (pressedKey === "ArrowDown" && focusedElement.nextElementSibling) { event.preventDefault(); - focusedElement.nextSibling.focus(); + (focusedElement.nextElementSibling as HTMLElement).focus(); } - if (pressedKey === "ArrowUp" && focusedElement.previousSibling) { + if (pressedKey === "ArrowUp" && focusedElement.previousElementSibling) { event.preventDefault(); - focusedElement.previousSibling.focus(); + (focusedElement.previousElementSibling as HTMLElement).focus(); } if ( pressedKey === "ArrowUp" && - !focusedElement.previousSibling && + !focusedElement.previousElementSibling && onDropdownClose ) { event.preventDefault(); diff --git a/packages/perseus-editor/src/components/form-wrapped-text-field.tsx b/packages/perseus-editor/src/components/form-wrapped-text-field.tsx index 2831f042846..2a30189f5c2 100644 --- a/packages/perseus-editor/src/components/form-wrapped-text-field.tsx +++ b/packages/perseus-editor/src/components/form-wrapped-text-field.tsx @@ -120,7 +120,7 @@ class FormWrappedTextField extends React.Component { } = this.props; const {focused} = this.state; - const extraStyles: any = {}; + const extraStyles: React.CSSProperties = {}; const spanStyle = [styles.input, styles.container]; // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions diff --git a/packages/perseus-editor/src/components/graph-settings.tsx b/packages/perseus-editor/src/components/graph-settings.tsx index 5b909b115a9..38aba435063 100644 --- a/packages/perseus-editor/src/components/graph-settings.tsx +++ b/packages/perseus-editor/src/components/graph-settings.tsx @@ -6,7 +6,6 @@ import {KhanMath} from "@khanacademy/kmath"; import { components, interactiveSizes, - Changeable, Dependencies, Util, } from "@khanacademy/perseus"; @@ -15,7 +14,11 @@ import * as React from "react"; import ReactDOM from "react-dom"; import _ from "underscore"; -import type {Coords, MarkingsType} from "@khanacademy/perseus-core"; +import type { + Coords, + MarkingsType, + PerseusImageBackground, +} from "@khanacademy/perseus-core"; const {ButtonGroup, InfoTip, RangeInput} = components; @@ -25,7 +28,7 @@ const defaultBackgroundImage = { height: 0, } as const; -function numSteps(range: any, step: any) { +function numSteps(range: [number, number], step: number) { return Math.floor((range[1] - range[0]) / step); } type Props = { @@ -39,14 +42,15 @@ type Props = { gridStep: [number, number]; snapStep: [number, number]; valid: boolean; - backgroundImage: any; + backgroundImage: PerseusImageBackground; markings: MarkingsType; showProtractor?: boolean; showRuler?: boolean; showTooltips?: boolean; rulerLabel: string; rulerTicks: number; -} & Changeable.ChangeableProps; + onChange: (values: Record) => void; +}; type DefaultProps = { editableSettings: Props["editableSettings"]; @@ -67,12 +71,12 @@ type DefaultProps = { }; type State = { - labelsTextbox: string[]; + labelsTextbox: readonly string[]; gridStepTextbox: number[]; snapStepTextbox: number[]; stepTextbox: number[]; - rangeTextbox: any[]; - backgroundImage: any; + rangeTextbox: [number, number][]; + backgroundImage: PerseusImageBackground; }; class GraphSettings extends React.Component { @@ -104,11 +108,10 @@ class GraphSettings extends React.Component { _isMounted = false; - constructor(props) { + constructor(props: Props) { super(props); this.state = this.getInitialState(); - this.change = this.change.bind(this); this.changeBackgroundUrl = this.changeBackgroundUrl.bind(this); this.changeGraph = this.changeGraph.bind(this); this.changeGridStep = this.changeGridStep.bind(this); @@ -132,7 +135,7 @@ class GraphSettings extends React.Component { this.changeGraph = _.debounce(this.changeGraph, 300); } - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { if ( !_.isEqual(this.props.labels, nextProps.labels) || !_.isEqual(this.props.gridStep, nextProps.gridStep) || @@ -149,7 +152,7 @@ class GraphSettings extends React.Component { this._isMounted = false; } - stateFromProps(props) { + stateFromProps(props: Props): State { return { labelsTextbox: props.labels, gridStepTextbox: props.gridStep, @@ -160,29 +163,25 @@ class GraphSettings extends React.Component { }; } - // TODO(benchristel): Refactor this component to be an ES6 class, so we can - // type change as ChangeFn. - change(...args) { - // TODO(LEMS-2656): remove TS suppression - // @ts-expect-error: Argument of type 'any[]' is not assignable to parameter of type '[newPropsOrSinglePropName: string | { [key: string]: any; }, propValue?: any, callback?: (() => unknown) | undefined]'. Target requires 1 element(s) but source may have fewer. - return Changeable.change.apply(this, args); - } - - changeRulerLabel(e) { - this.change({rulerLabel: e.target.value}); + changeRulerLabel(e: React.ChangeEvent) { + this.props.onChange({rulerLabel: e.target.value}); } - changeRulerTicks(e) { - this.change({rulerTicks: +e.target.value}); + changeRulerTicks(e: React.ChangeEvent) { + this.props.onChange({rulerTicks: +e.target.value}); } - changeBackgroundUrl(e) { + changeBackgroundUrl( + e: + | React.FocusEvent + | React.KeyboardEvent, + ) { // Only continue on blur or "enter" - if (e.type === "keypress" && e.key !== "Enter") { + if (e.type === "keypress" && "key" in e && e.key !== "Enter") { return; } - const setUrl = (url, width: number, height: number) => { + const setUrl = (url: string | null, width: number, height: number) => { const image = _.clone(this.props.backgroundImage); image.url = url; image.width = width; @@ -208,7 +207,7 @@ class GraphSettings extends React.Component { } } - renderLabelChoices(choices) { + renderLabelChoices(choices: ReadonlyArray<[string, string]>) { return _.map(choices, function ([name, value]) { return (