From 1c94c6db2c8eddbadff301b8a14cbdb87f5b850a Mon Sep 17 00:00:00 2001 From: Cat Johnson Date: Mon, 22 Dec 2025 16:37:54 -0800 Subject: [PATCH 1/6] [catjohnson/type-component-files] Moving storybook pages and adding a few types. --- .../blur-input.stories.tsx | 2 +- .../color-select.stories.tsx | 2 +- .../color-swatch.stories.tsx | 2 +- .../device-framer.stories.tsx | 2 +- .../graph-settings.argtypes.ts | 0 .../graph-settings.stories.tsx | 2 +- .../interactive-graph-settings.argtypes.ts | 0 .../interactive-graph-settings.stories.tsx | 2 +- .../locked-ellipse-settings.stories.tsx | 2 +- .../locked-figures-section.stories.tsx | 2 +- .../locked-function-settings.stories.tsx | 2 +- .../locked-label-settings.stories.tsx | 2 +- .../locked-line-settings.stories.tsx | 2 +- .../locked-point-settings.stories.tsx | 2 +- .../locked-polygon-settings.stories.tsx | 2 +- .../locked-vector-settings.stories.tsx | 2 +- .../scrollless-number-text-field.stories.tsx | 2 +- .../section-control-button.stories.tsx | 2 +- .../toggleable-caret.stories.tsx | 2 +- .../viewport-resizer.stories.tsx | 2 +- .../src/components/blur-input.tsx | 8 ++++---- .../src/components/drag-target.tsx | 2 +- .../src/components/form-wrapped-text-field.tsx | 17 +++++++---------- 23 files changed, 30 insertions(+), 33 deletions(-) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/blur-input.stories.tsx (90%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/color-select.stories.tsx (95%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/color-swatch.stories.tsx (91%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/device-framer.stories.tsx (96%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/graph-settings.argtypes.ts (100%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/graph-settings.stories.tsx (91%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/interactive-graph-settings.argtypes.ts (100%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/interactive-graph-settings.stories.tsx (95%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-ellipse-settings.stories.tsx (97%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-figures-section.stories.tsx (97%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-function-settings.stories.tsx (95%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-label-settings.stories.tsx (95%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-line-settings.stories.tsx (98%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-point-settings.stories.tsx (97%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-polygon-settings.stories.tsx (97%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/locked-vector-settings.stories.tsx (97%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/scrollless-number-text-field.stories.tsx (97%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/section-control-button.stories.tsx (90%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/toggleable-caret.stories.tsx (93%) rename packages/perseus-editor/src/components/{__stories__ => __docs__}/viewport-resizer.stories.tsx (93%) 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 c1043a8f3e7..f20180f1201 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 3935e631c9f..d6037acdff9 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 f410296a404..628da0280f9 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 90% 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..26849bfe1d4 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 @@ -10,7 +10,7 @@ type Story = { }; 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/blur-input.tsx b/packages/perseus-editor/src/components/blur-input.tsx index e7a71a98c45..956cf5de669 100644 --- a/packages/perseus-editor/src/components/blur-input.tsx +++ b/packages/perseus-editor/src/components/blur-input.tsx @@ -39,13 +39,13 @@ 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); - }; + } focus() { this.input.current?.focus(); diff --git a/packages/perseus-editor/src/components/drag-target.tsx b/packages/perseus-editor/src/components/drag-target.tsx index 6319ccbcb41..4144ebba0a0 100644 --- a/packages/perseus-editor/src/components/drag-target.tsx +++ b/packages/perseus-editor/src/components/drag-target.tsx @@ -29,7 +29,7 @@ type Props = { component?: any; shouldDragHighlight: (any) => boolean; style?: any; - children?: any; + children?: React.ReactNode | React.ReactNode[]; className?: string; }; 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 28faa74024c..4b40129f119 100644 --- a/packages/perseus-editor/src/components/form-wrapped-text-field.tsx +++ b/packages/perseus-editor/src/components/form-wrapped-text-field.tsx @@ -47,8 +47,8 @@ type Props = { style?: React.CSSProperties | undefined; className?: string; width?: number | string; - grow?: boolean | number; - shrink?: boolean | number; + grow?: number; + shrink?: number; // HACK(mattmorgan) to enforce WB LabelMedium-like styles on this older // component. labelMediumInputText?: boolean; @@ -123,22 +123,19 @@ 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 - if (width) { + if (width !== undefined) { extraStyles.width = width; } - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if (grow) { - extraStyles.flexGrow = grow === true ? 1 : grow; + if (grow !== undefined) { + extraStyles.flexGrow = grow === undefined ? 1 : grow; } - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (shrink || shrink === 0) { - extraStyles.flexShrink = shrink === true ? 0 : shrink; + extraStyles.flexShrink = shrink === undefined ? 0 : shrink; } if (backgroundColor) { From fea2208793f168d99579e4f72d921485e4adbcf3 Mon Sep 17 00:00:00 2001 From: Cat Johnson Date: Tue, 23 Dec 2025 09:36:43 -0800 Subject: [PATCH 2/6] [catjohnson/type-component-files] Cleaning up old storybook pages. --- .../__docs__/blur-input.stories.tsx | 25 +++++++++---------- .../__docs__/viewport-resizer.stories.tsx | 1 + 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/perseus-editor/src/components/__docs__/blur-input.stories.tsx b/packages/perseus-editor/src/components/__docs__/blur-input.stories.tsx index 1595accd283..0b944f2e49e 100644 --- a/packages/perseus-editor/src/components/__docs__/blur-input.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/blur-input.stories.tsx @@ -1,22 +1,21 @@ -import * as React from "react"; import {action} from "storybook/actions"; import BlurInput from "../blur-input"; -export default { +import type {Meta, StoryObj} from "@storybook/react-vite"; + +const meta: Meta = { title: "Editors/Components/Blur Input", + component: BlurInput, + args: { + onChange: action("onChange"), + }, }; -export const Default = (): React.ReactElement => { - const [value, setValue] = React.useState(""); +export default meta; + +type Story = StoryObj; - return ( - { - action("onChange")(newValue); - setValue(newValue); - }} - /> - ); +export const Example: Story = { + args: {value: "Test input"}, }; diff --git a/packages/perseus-editor/src/components/__docs__/viewport-resizer.stories.tsx b/packages/perseus-editor/src/components/__docs__/viewport-resizer.stories.tsx index c901b4268d8..d542f52271e 100644 --- a/packages/perseus-editor/src/components/__docs__/viewport-resizer.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/viewport-resizer.stories.tsx @@ -12,6 +12,7 @@ const meta: Meta = { }; export default meta; + type Story = StoryFn; export const Controlled: Story = () => { From e21d42827badb70dcadf098aec804b07525723c8 Mon Sep 17 00:00:00 2001 From: Cat Johnson Date: Tue, 23 Dec 2025 14:34:57 -0800 Subject: [PATCH 3/6] [catjohnson/type-component-files] Fixing more stories! --- .../__docs__/color-swatch.stories.tsx | 22 ++--- .../__docs__/graph-settings.argtypes.ts | 51 +++++----- .../__docs__/graph-settings.stories.tsx | 28 +++--- .../interactive-graph-settings.argtypes.ts | 98 ++++--------------- .../interactive-graph-settings.stories.tsx | 65 ++++-------- .../section-control-button.stories.tsx | 32 +++--- .../components/interactive-graph-settings.tsx | 18 +++- 7 files changed, 122 insertions(+), 192 deletions(-) diff --git a/packages/perseus-editor/src/components/__docs__/color-swatch.stories.tsx b/packages/perseus-editor/src/components/__docs__/color-swatch.stories.tsx index c674445bb9e..6a43284630b 100644 --- a/packages/perseus-editor/src/components/__docs__/color-swatch.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/color-swatch.stories.tsx @@ -1,21 +1,21 @@ import {getDefaultFigureForType} from "@khanacademy/perseus-core"; -import * as React from "react"; import ColorSwatch from "../../widgets/interactive-graph-editor/locked-figures/color-swatch"; -import type {Meta} from "@storybook/react-vite"; +import type {Meta, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Color Swatch", component: ColorSwatch, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; -// Set the default values in the control panel. -Default.args = { - color: getDefaultFigureForType("point").color, - filled: true, +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + color: getDefaultFigureForType("point").color, + filled: true, + }, }; diff --git a/packages/perseus-editor/src/components/__docs__/graph-settings.argtypes.ts b/packages/perseus-editor/src/components/__docs__/graph-settings.argtypes.ts index 9ca08e807c2..97254befba2 100644 --- a/packages/perseus-editor/src/components/__docs__/graph-settings.argtypes.ts +++ b/packages/perseus-editor/src/components/__docs__/graph-settings.argtypes.ts @@ -1,83 +1,82 @@ export default { editableSettings: { control: { - type: "array", + type: "multi-select" as const, options: ["canvas", "graph", "snap", "image", "measure"], }, }, box: { control: { - type: "array", + type: "object" as const, }, }, range: { control: { - type: "object", + type: "object" as const, }, }, labels: { control: { - type: "object", + type: "object" as const, }, }, step: { control: { - type: "object", + type: "object" as const, }, }, gridStep: { control: { - type: "object", + type: "object" as const, }, }, snapStep: { control: { - type: "object", + type: "object" as const, }, }, valid: { control: { - type: "text", + type: "boolean" as const, }, }, backgroundImage: { control: { - type: "object", + type: "object" as const, }, }, markings: { control: { - type: "select", - }, - table: { - type: { - summary: '"axes" | "graph" | "grid" | "none"', - }, - }, - type: { - name: "enum", - value: ["graph", "grid", "none"], - required: false, + type: "select" as const, }, + options: ["axes", "graph", "grid", "none"], }, rulerLabel: { control: { - type: "text", + type: "text" as const, }, }, rulerTicks: { control: { - type: "number", + type: "number" as const, }, }, - showTooltips: { + showProtractor: { control: { - type: "boolean", + type: "boolean" as const, }, }, - onChange: { + showRuler: { + control: { + type: "boolean" as const, + }, + }, + showTooltips: { control: { - type: "function", + type: "boolean" as const, }, }, + onChange: { + control: false as const, + }, }; diff --git a/packages/perseus-editor/src/components/__docs__/graph-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/graph-settings.stories.tsx index 2a741507297..1f48ccf9852 100644 --- a/packages/perseus-editor/src/components/__docs__/graph-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/graph-settings.stories.tsx @@ -1,24 +1,26 @@ -import * as React from "react"; - import GraphSettings from "../graph-settings"; import GraphSettingsArgTypes from "./graph-settings.argtypes"; -export default { +import type {Meta, StoryObj} from "@storybook/react-vite"; + +const meta: Meta = { title: "Editors/Components/Graph Settings", component: GraphSettings, argTypes: GraphSettingsArgTypes, }; -export const Default = (args): React.ReactElement => { - return ; -}; +export default meta; + +type Story = StoryObj; -Default.args = { - // Separating the array props out because trying to editing them in - // the controls panel without a default value causes the story to crash. - range: [ - [-10, 10], - [-10, 10], - ], +export const Default: Story = { + args: { + // Separating the array props out because trying to editing them in + // the controls panel without a default value causes the story to crash. + range: [ + [-10, 10], + [-10, 10], + ], + }, }; diff --git a/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.argtypes.ts b/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.argtypes.ts index 42d9c22e67f..ebf3346d6c7 100644 --- a/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.argtypes.ts +++ b/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.argtypes.ts @@ -1,149 +1,91 @@ export default { box: { control: { - type: "array", + type: "object" as const, }, }, labels: { control: { - type: "array", - }, - type: { - name: "ReadonlyArray", - required: false, + type: "object" as const, }, }, range: { control: { - type: "array", - }, - type: { - name: "[Range, Range]", - required: false, + type: "object" as const, }, }, step: { control: { - type: "array", - }, - type: { - name: "[number, number]", - required: false, + type: "object" as const, }, }, gridStep: { control: { - type: "array", - }, - type: { - name: "[number, number]", - required: true, + type: "object" as const, }, }, snapStep: { control: { - type: "array", - }, - type: { - name: "[number, number]", - required: true, + type: "object" as const, }, }, valid: { control: { - type: "text", - }, - type: { - name: "string", - required: false, + type: "text" as const, }, }, backgroundImage: { control: { - type: "object", - }, - type: { - name: "PerseusImageBackground", - required: false, + type: "object" as const, }, }, markings: { control: { - type: "select", - }, - table: { - type: { - summary: '"graph" | "grid" | "none"', - }, - }, - type: { - name: "enum", - value: ["graph", "grid", "none"], - required: false, + type: "select" as const, }, + options: ["axes", "graph", "grid", "none"], }, showProtractor: { control: { - type: "boolean", - }, - type: { - name: "boolean", - required: false, + type: "boolean" as const, }, }, showRuler: { control: { - type: "boolean", - }, - type: { - name: "boolean", - required: false, + type: "boolean" as const, }, }, showTooltips: { control: { - type: "boolean", - }, - type: { - name: "boolean", - required: false, + type: "boolean" as const, }, }, rulerLabel: { control: { - type: "select", - }, - table: { - type: { - summary: '"mm", "cm", "m", "km", "in", "ft", "yd", "mi"', - }, - }, - type: { - name: "enum", - value: ["mm", "cm", "m", "km", "in", "ft", "yd", "mi"], - required: false, + type: "select" as const, }, + options: ["", "mm", "cm", "m", "km", "in", "ft", "yd", "mi"], }, rulerTicks: { control: { - type: "number", - }, - type: { - name: "number", - required: false, + type: "number" as const, }, }, + + onChange: { + control: false as const, + }, }; diff --git a/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.stories.tsx index 4150cc166c1..3474c929dce 100644 --- a/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/interactive-graph-settings.stories.tsx @@ -1,57 +1,32 @@ -import * as React from "react"; - import InteractiveGraphSettings from "../../widgets/interactive-graph-editor/components/interactive-graph-settings"; import InteractiveGraphSettingsArgTypes from "./interactive-graph-settings.argtypes"; -import type {StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Interactive Graph Settings", component: InteractiveGraphSettings, argTypes: InteractiveGraphSettingsArgTypes, }; -export const Default = (args): React.ReactElement => { - return ; -}; - -type StoryComponentType = StoryObj; - -// Set the default values in the control panel. -Default.args = { - box: [288, 288], - gridStep: [1, 1], - labels: ["x", "y"], - markings: "graph", - range: [ - [-10, 10], - [-10, 10], - ], - rulerLabel: "", - rulerTicks: 10, - showProtractor: false, - showRuler: false, - showTooltips: false, - snapStep: [1, 1], - step: [1, 1], -}; - -/** - * Example of what the InteractiveGraphEditor experience is when all - * props are controlled by the parent. (Checkboxes update when clicked, etc.) - */ -export const Controlled: StoryComponentType = { - render: function Render() { - const reducer = (state, newState) => { - return { - ...state, - ...newState, - }; - }; - - const [state, dispatch] = React.useReducer(reducer, {}); - - return ; +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + box: [288, 288] as const, + gridStep: [1, 1], + labels: ["x", "y"], + markings: "graph", + range: [ + [-10, 10], + [-10, 10], + ], + showProtractor: false, + showTooltips: false, + snapStep: [1, 1], + step: [1, 1], }, }; diff --git a/packages/perseus-editor/src/components/__docs__/section-control-button.stories.tsx b/packages/perseus-editor/src/components/__docs__/section-control-button.stories.tsx index 26849bfe1d4..46575dc3c36 100644 --- a/packages/perseus-editor/src/components/__docs__/section-control-button.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/section-control-button.stories.tsx @@ -1,27 +1,23 @@ import trashIcon from "@phosphor-icons/core/bold/trash-bold.svg"; -import * as React from "react"; import SectionControlButton from "../section-control-button"; -type StoryArgs = Record; +import type {Meta, StoryObj} from "@storybook/react-vite"; -type Story = { - title: string; +const meta: Meta = { + title: "Editors/Components/Section Control Button", + component: SectionControlButton, }; -export default { - title: "Editors/Components/Section Control Button", -} as Story; +export default meta; + +type Story = StoryObj; -export const ButtonForEditingSectionsOfContentWithInArticleEditor = ( - args: StoryArgs, -): React.ReactElement => { - return ( - {}} - title="Remove image widget" - /> - ); +export const Example: Story = { + args: { + icon: trashIcon, + disabled: false, + onClick: () => {}, + title: "Remove image widget", + }, }; diff --git a/packages/perseus-editor/src/widgets/interactive-graph-editor/components/interactive-graph-settings.tsx b/packages/perseus-editor/src/widgets/interactive-graph-editor/components/interactive-graph-settings.tsx index b52e96edba2..49baac87ac6 100644 --- a/packages/perseus-editor/src/widgets/interactive-graph-editor/components/interactive-graph-settings.tsx +++ b/packages/perseus-editor/src/widgets/interactive-graph-editor/components/interactive-graph-settings.tsx @@ -127,6 +127,22 @@ type State = { backgroundImage: PerseusImageBackground; }; +type DefaultProps = { + box: Props["box"]; + labels: Props["labels"]; + labelLocation: Props["labelLocation"]; + range: Props["range"]; + step: Props["step"]; + gridStep: Props["gridStep"]; + snapStep: Props["snapStep"]; + valid: Props["valid"]; + backgroundImage: Props["backgroundImage"]; + markings: Props["markings"]; + showProtractor: Props["showProtractor"]; + showTooltips: Props["showTooltips"]; + showAxisArrows: Props["showAxisArrows"]; +}; + class InteractiveGraphSettings extends React.Component { _isMounted = false; @@ -156,7 +172,7 @@ class InteractiveGraphSettings extends React.Component { }; } - static defaultProps = { + static defaultProps: DefaultProps = { box: [ interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall, From baa81cc4c4d3ba3a376d6a8a1bff241ea1b0e093 Mon Sep 17 00:00:00 2001 From: Cat Johnson Date: Tue, 23 Dec 2025 15:08:13 -0800 Subject: [PATCH 4/6] [catjohnson/type-component-files] Updating storybook pages. --- .../locked-ellipse-settings.stories.tsx | 80 ++++---- .../locked-figures-section.stories.tsx | 76 ++++---- .../locked-function-settings.stories.tsx | 60 +++--- .../locked-label-settings.stories.tsx | 60 +++--- .../__docs__/locked-line-settings.stories.tsx | 175 ++++++++---------- .../locked-point-settings.stories.tsx | 130 ++++++------- .../locked-polygon-settings.stories.tsx | 93 ++++------ 7 files changed, 314 insertions(+), 360 deletions(-) diff --git a/packages/perseus-editor/src/components/__docs__/locked-ellipse-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-ellipse-settings.stories.tsx index 5aafd2bfff6..917beded60e 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-ellipse-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-ellipse-settings.stories.tsx @@ -3,17 +3,15 @@ import * as React from "react"; import LockedEllipseSettings from "../../widgets/interactive-graph-editor/locked-figures/locked-ellipse-settings"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Ellipse Settings", component: LockedEllipseSettings, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { ...getDefaultFigureForType("ellipse"), onChangeProps: () => {}, @@ -21,29 +19,25 @@ const defaultProps = { onRemove: () => {}, }; -type StoryComponentType = StoryObj; +type Story = StoryFn; -// Set the default values in the control panel. -Default.args = defaultProps; +export const Default: StoryObj = { + args: defaultProps, +}; -export const Controlled: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); +export const Controlled: Story = () => { + const [props, setProps] = React.useState(defaultProps); - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; - return ( - - ); - }, + return ( + + ); }; Controlled.parameters = { @@ -54,25 +48,23 @@ Controlled.parameters = { }; // Fully expanded view of the locked ellipse settings to allow snapshot testing. -export const Expanded: StoryComponentType = { - render: function Render() { - const [expanded, setExpanded] = React.useState(true); - const [props, setProps] = React.useState(defaultProps); +export const Expanded: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; - return ( - - ); - }, + return ( + + ); }; diff --git a/packages/perseus-editor/src/components/__docs__/locked-figures-section.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-figures-section.stories.tsx index d6037acdff9..3b0ef48fa49 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-figures-section.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-figures-section.stories.tsx @@ -4,64 +4,60 @@ import {View} from "@khanacademy/wonder-blocks-core"; import {color, spacing} from "@khanacademy/wonder-blocks-tokens"; import {StyleSheet} from "aphrodite"; import * as React from "react"; +import {useState} from "react"; import LockedFiguresSection from "../../widgets/interactive-graph-editor/locked-figures/locked-figures-section"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Figures Section", component: LockedFiguresSection, -} as Meta; +}; + +export default meta; -export const Default = (args): React.ReactElement => { - return ; +export const Default: StoryObj = { + args: {}, }; -type StoryComponentType = StoryObj; +type Story = StoryFn; + +export const Controlled: Story = () => { + const [figures, setFigures] = useState([]); -// Set the default values in the control panel. -Default.args = {}; + const handlePropsUpdate = (newProps) => { + setFigures(newProps.lockedFigures); + }; -export const Controlled: StoryComponentType = { - render: function Render() { - const [figures, setFigures] = React.useState([]); + return ( + + ); +}; + +export const WithProdWidth: Story = () => { + const [figures, setFigures] = useState([ + getDefaultFigureForType("point"), + getDefaultFigureForType("line"), + ]); - const handlePropsUpdate = (newProps) => { - setFigures(newProps.lockedFigures); - }; + const handlePropsUpdate = (newProps) => { + setFigures(newProps.lockedFigures); + }; - return ( + return ( + - ); - }, -}; - -export const WithProdWidth: StoryComponentType = { - render: function Render() { - const [figures, setFigures] = React.useState([ - getDefaultFigureForType("point"), - getDefaultFigureForType("line"), - ]); - - const handlePropsUpdate = (newProps) => { - setFigures(newProps.lockedFigures); - }; - - return ( - - - - ); - }, + + ); }; const contentSize = 310; diff --git a/packages/perseus-editor/src/components/__docs__/locked-function-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-function-settings.stories.tsx index 19c3d0f321f..28416f2b2b2 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-function-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-function-settings.stories.tsx @@ -3,17 +3,15 @@ import * as React from "react"; import LockedFunctionSettings from "../../widgets/interactive-graph-editor/locked-figures/locked-function-settings"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Function Settings", component: LockedFunctionSettings, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { ...getDefaultFigureForType("function"), onChangeProps: () => {}, @@ -21,28 +19,30 @@ const defaultProps = { onRemove: () => {}, }; -type StoryComponentType = StoryObj; - -// Set the default values in the control panel. -Default.args = defaultProps; - -export const Expanded: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); - - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, +type Story = StoryFn; + +export const Default: StoryObj = { + args: defaultProps, +}; + +// Fully expanded view of the locked function settings to allow snapshot testing. +export const Expanded: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ( + + ); }; diff --git a/packages/perseus-editor/src/components/__docs__/locked-label-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-label-settings.stories.tsx index 7af97e456fe..8da97fbdb35 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-label-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-label-settings.stories.tsx @@ -3,17 +3,15 @@ import * as React from "react"; import LockedLabelSettings from "../../widgets/interactive-graph-editor/locked-figures/locked-label-settings"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Label Settings", component: LockedLabelSettings, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { ...getDefaultFigureForType("label"), onChangeProps: () => {}, @@ -21,28 +19,30 @@ const defaultProps = { onRemove: () => {}, }; -type StoryComponentType = StoryObj; - -// Set the default values in the control panel. -Default.args = defaultProps; - -export const Expanded: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); - - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, +type Story = StoryFn; + +export const Default: StoryObj = { + args: defaultProps, +}; + +// Fully expanded view of the locked label settings to allow snapshot testing. +export const Expanded: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ( + + ); }; diff --git a/packages/perseus-editor/src/components/__docs__/locked-line-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-line-settings.stories.tsx index f94f16484b7..9eed8039ea3 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-line-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-line-settings.stories.tsx @@ -3,17 +3,15 @@ import * as React from "react"; import LockedLineSettings from "../../widgets/interactive-graph-editor/locked-figures/locked-line-settings"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Line Settings", component: LockedLineSettings, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { ...getDefaultFigureForType("line"), onChangeProps: () => {}, @@ -21,26 +19,23 @@ const defaultProps = { onRemove: () => {}, }; -type StoryComponentType = StoryObj; +type Story = StoryFn; -// Set the default values in the control panel. -Default.args = defaultProps; +export const Default: StoryObj = { + args: defaultProps, +}; -export const Controlled: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); +export const Controlled: Story = () => { + const [props, setProps] = React.useState(defaultProps); - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; - return ( - - ); - }, + return ; }; Controlled.parameters = { @@ -55,80 +50,74 @@ Controlled.parameters = { * as that would give it a length of 0. An error message is displayed * in this case. */ -export const WithInvalidPoints: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); - - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, -}; +export const WithInvalidPoints: Story = () => { + const [props, setProps] = React.useState(defaultProps); -// Fully expanded view of the locked point settings to allow snapshot testing. -export const Expanded: StoryComponentType = { - render: function Render() { - const [expanded, setExpanded] = React.useState(true); - const [props, setProps] = React.useState(defaultProps); - - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ( + + ); }; -// Fully expanded view of the locked point settings to allow snapshot testing. -export const ExpandedNondefaultProps: StoryComponentType = { - render: function Render() { - const [expanded, setExpanded] = React.useState(true); - const [props, setProps] = React.useState({ - ...defaultProps, - kind: "segment" as const, - color: "green" as const, - lineStyle: "dashed" as const, +// Fully expanded view of the locked line settings to allow snapshot testing. +export const Expanded: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, }); + }; + + return ( + + ); +}; - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, +// Fully expanded view of the locked line settings to allow snapshot testing. +export const ExpandedNondefaultProps: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState({ + ...defaultProps, + kind: "segment" as const, + color: "green" as const, + lineStyle: "dashed" as const, + }); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ( + + ); }; diff --git a/packages/perseus-editor/src/components/__docs__/locked-point-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-point-settings.stories.tsx index ad98b9f2a71..34646ea0318 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-point-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-point-settings.stories.tsx @@ -3,17 +3,15 @@ import * as React from "react"; import LockedPointSettings from "../../widgets/interactive-graph-editor/locked-figures/locked-point-settings"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Point Settings", component: LockedPointSettings, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { ...getDefaultFigureForType("point"), onChangeProps: () => {}, @@ -21,79 +19,69 @@ const defaultProps = { onRemove: () => {}, }; -type StoryComponentType = StoryObj; - -// Set the default values in the control panel. -Default.args = defaultProps; - -export const Controlled: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); +type Story = StoryFn; - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, +export const Default: StoryObj = { + args: defaultProps, }; -Controlled.parameters = { - chromatic: { +export const Controlled: Story = () => { + const [props, setProps] = React.useState({ + ...defaultProps, // Disabling because this doesn't test anything visual, just behavior. - disableSnapshot: true, - }, + chromatic: {disableSnapshot: true}, + }); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ; }; // Fully expanded view of the locked point settings to allow snapshot testing. -export const Expanded: StoryComponentType = { - render: function Render() { - const [expanded, setExpanded] = React.useState(true); - const [props, setProps] = React.useState(defaultProps); - - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, +export const Expanded: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ( + + ); }; // Fully expanded view of the locked point settings to allow snapshot testing. -export const ExpandedNondefaultProps: StoryComponentType = { - render: function Render() { - const [expanded, setExpanded] = React.useState(true); - const [props, setProps] = React.useState(defaultProps); - - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, +export const ExpandedNondefaultProps: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ( + + ); }; diff --git a/packages/perseus-editor/src/components/__docs__/locked-polygon-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-polygon-settings.stories.tsx index b1f016f0d16..f180898b070 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-polygon-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-polygon-settings.stories.tsx @@ -3,17 +3,15 @@ import * as React from "react"; import LockedPolygonSettings from "../../widgets/interactive-graph-editor/locked-figures/locked-polygon-settings"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Polygon Settings", component: LockedPolygonSettings, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { ...getDefaultFigureForType("polygon"), onChangeProps: () => {}, @@ -21,58 +19,49 @@ const defaultProps = { onRemove: () => {}, }; -type StoryComponentType = StoryObj; - -// Set the default values in the control panel. -Default.args = defaultProps; - -export const Controlled: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); +type Story = StoryFn; - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; - - return ( - - ); - }, +export const Default: StoryObj = { + args: defaultProps, }; -Controlled.parameters = { - chromatic: { +export const Controlled: Story = () => { + const [props, setProps] = React.useState({ + ...defaultProps, // Disabling because this is testing behavior, not visuals. - disableSnapshot: true, - }, + chromatic: {disableSnapshot: true}, + }); + + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; + + return ( + + ); }; -// Fully expanded view of the locked ellipse settings to allow snapshot testing. -export const Expanded: StoryComponentType = { - render: function Render() { - const [expanded, setExpanded] = React.useState(true); - const [props, setProps] = React.useState(defaultProps); +// Fully expanded view of the locked polygon settings to allow snapshot testing. +export const Expanded: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; - return ( - - ); - }, + return ( + + ); }; From 95205b61ebec3197d43fbd02de789ea631bca9e0 Mon Sep 17 00:00:00 2001 From: Cat Johnson Date: Tue, 23 Dec 2025 15:24:43 -0800 Subject: [PATCH 5/6] [catjohnson/type-component-files] More Storybook pages updated. --- .../locked-vector-settings.stories.tsx | 92 +++++++++---------- .../scrollless-number-text-field.stories.tsx | 81 ++++++---------- .../__docs__/toggleable-caret.stories.tsx | 6 +- 3 files changed, 78 insertions(+), 101 deletions(-) diff --git a/packages/perseus-editor/src/components/__docs__/locked-vector-settings.stories.tsx b/packages/perseus-editor/src/components/__docs__/locked-vector-settings.stories.tsx index 05fd90a8a8d..742cacbad77 100644 --- a/packages/perseus-editor/src/components/__docs__/locked-vector-settings.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/locked-vector-settings.stories.tsx @@ -3,17 +3,15 @@ import * as React from "react"; import LockedVectorSettings from "../../widgets/interactive-graph-editor/locked-figures/locked-vector-settings"; -import type {Meta, StoryObj} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Locked Vector Settings", component: LockedVectorSettings, -} as Meta; - -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { ...getDefaultFigureForType("vector"), onChangeProps: () => {}, @@ -21,30 +19,32 @@ const defaultProps = { onRemove: () => {}, }; -type StoryComponentType = StoryObj; +type Story = StoryFn; -// Set the default values in the control panel. -Default.args = defaultProps; +export const Default: StoryObj = { + args: defaultProps, +}; -export const Expanded: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); +// Fully expanded view of the locked vector settings to allow snapshot testing. +export const Expanded: Story = () => { + const [expanded, setExpanded] = React.useState(true); + const [props, setProps] = React.useState(defaultProps); - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; - return ( - - ); - }, + return ( + + ); }; /** @@ -52,27 +52,25 @@ export const Expanded: StoryComponentType = { * as that would give it a length of 0. An error message is displayed * in this case. */ -export const WithInvalidPoints: StoryComponentType = { - render: function Render() { - const [props, setProps] = React.useState(defaultProps); +export const WithInvalidPoints: Story = () => { + const [props, setProps] = React.useState(defaultProps); - const handlePropsUpdate = (newProps) => { - setProps({ - ...props, - ...newProps, - }); - }; + const handlePropsUpdate = (newProps) => { + setProps({ + ...props, + ...newProps, + }); + }; - return ( - - ); - }, + return ( + + ); }; diff --git a/packages/perseus-editor/src/components/__docs__/scrollless-number-text-field.stories.tsx b/packages/perseus-editor/src/components/__docs__/scrollless-number-text-field.stories.tsx index 628da0280f9..195f56254ee 100644 --- a/packages/perseus-editor/src/components/__docs__/scrollless-number-text-field.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/scrollless-number-text-field.stories.tsx @@ -4,49 +4,38 @@ import * as React from "react"; import ScrolllessNumberTextField from "../scrollless-number-text-field"; -import type {StoryObj, Meta} from "@storybook/react-vite"; +import type {Meta, StoryFn, StoryObj} from "@storybook/react-vite"; -export default { +const meta: Meta = { title: "Editors/Components/Scrollless Number Text Field", component: ScrolllessNumberTextField, -} as Meta; - -/** - * Uncontrolled story. Interact with the control panel to see the component - * reflect the props. - */ -export const Default = (args): React.ReactElement => { - return ; }; +export default meta; + const defaultProps = { value: "", onChange: () => {}, }; -type StoryComponentType = StoryObj; +type Story = StoryFn; -// Set the default values in the control panel. -Default.args = defaultProps; +/** + * Uncontrolled story. Interact with the control panel to see the component + * reflect the props. + */ +export const Default: StoryObj = { + args: defaultProps, +}; /** * Controlled story. The text field's state is managed by its parent. * Typing in the input field should work as expected. */ -export const Controlled: StoryComponentType = { - render: function Render() { - const [value, setValue] = React.useState(""); - - return ; - }, -}; +export const Controlled: Story = () => { + const [value, setValue] = React.useState(""); -Controlled.parameters = { - chromatic: { - // Disable the snapshot for this story because it's testing - // behavior, not visuals. - disableSnapshot: true, - }, + return ; }; /** @@ -54,29 +43,19 @@ Controlled.parameters = { * in a long page. Scrolling on the input field with a mouse wheel or trackpad * changes the number, but does not scroll the page. */ -export const LongPageScroll: StoryComponentType = { - render: function Render() { - const [value, setValue] = React.useState(""); - - return ( - <> - Scroll down to see the input. - - - Observe that scrolling on the input field with a mouse wheel - changes the number, but does not scroll the page. - - - - - ); - }, -}; - -LongPageScroll.parameters = { - chromatic: { - // Disable the snapshot for this story because it's testing - // behavior, not visuals. - disableSnapshot: true, - }, +export const LongPageScroll: Story = () => { + const [value, setValue] = React.useState(""); + + return ( + <> + Scroll down to see the input. + + + Observe that scrolling on the input field with a mouse wheel + changes the number, but does not scroll the page. + + + + + ); }; diff --git a/packages/perseus-editor/src/components/__docs__/toggleable-caret.stories.tsx b/packages/perseus-editor/src/components/__docs__/toggleable-caret.stories.tsx index c5bc966857c..de5c0dd8dbc 100644 --- a/packages/perseus-editor/src/components/__docs__/toggleable-caret.stories.tsx +++ b/packages/perseus-editor/src/components/__docs__/toggleable-caret.stories.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import ToggleableCaret from "../toggleable-caret"; -import type {StoryObj, Meta} from "@storybook/react-vite"; +import type {StoryObj, Meta, StoryFn} from "@storybook/react-vite"; type Story = StoryObj; @@ -12,7 +12,7 @@ export default { component: ToggleableCaret, } satisfies Meta; -export function Transitions() { +export const Transitions: StoryFn = () => { const [expanded, setExpanded] = React.useState(false); const toggler = React.useCallback(() => { setExpanded(!expanded); @@ -20,7 +20,7 @@ export function Transitions() { useInterval(toggler, 500, {schedulePolicy: SchedulePolicy.Immediately}); return ; -} +}; export const Expanded: Story = { args: {isExpanded: true}, From db3ec24442ee116fa46fc22fefa5f9f5804d670c Mon Sep 17 00:00:00 2001 From: Cat Johnson Date: Fri, 23 Jan 2026 16:32:32 -0800 Subject: [PATCH 6/6] [catjohnson/type-component-files] Adding code in progress. --- .../src/components/dropdown-option.tsx | 66 +++++++++---------- .../src/components/widget-editor.tsx | 2 +- .../src/widgets/label-image-editor/marker.tsx | 2 +- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/perseus-editor/src/components/dropdown-option.tsx b/packages/perseus-editor/src/components/dropdown-option.tsx index 79ea833ccee..893adf27deb 100644 --- a/packages/perseus-editor/src/components/dropdown-option.tsx +++ b/packages/perseus-editor/src/components/dropdown-option.tsx @@ -63,18 +63,18 @@ class Option extends React.Component { // @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.target as HTMLElement; if (pressedKey === "ArrowDown" && focusedElement.nextSibling) { event.preventDefault(); - focusedElement.nextSibling.focus(); + (focusedElement.nextSibling as HTMLElement).focus(); } if (pressedKey === "ArrowUp" && focusedElement.previousSibling) { event.preventDefault(); - focusedElement.previousSibling.focus(); + (focusedElement.previousSibling as HTMLElement).focus(); } if ( pressedKey === "ArrowUp" && @@ -116,15 +116,14 @@ class Option extends React.Component { disabled && styles.cursorDefault, hideFocusState && styles.noFocus, )} - // @ts-expect-error - TS2322 - Type '(value: string) => void' is not assignable to type 'MouseEventHandler'. - onClick={(value: string) => { + onClick={() => { if (!disabled && onClick) { - // @ts-expect-error - TS2554 - Expected 0 arguments, but got 1. - onClick(value); + onClick(); } }} - // @ts-expect-error - TS2322 - Type '(event: KeyboardEvent) => void' is not assignable to type 'KeyboardEventHandler'. - onKeyDown={(event: KeyboardEvent) => this.handleKeyDown(event)} + onKeyDown={(event: React.KeyboardEvent) => + this.handleKeyDown(event) + } aria-disabled={disabled} aria-label={ariaLabel} data-testid={testId} @@ -148,11 +147,7 @@ class Option extends React.Component { } } -// TODO(kevinb): -// - keep the the option group within the page bounds -// - do we really want to dismiss this on scroll -// - how does the drop down interact with tooltips? what's the z-index order? -class OptionGroup extends React.Component<{ +type OptionGroupProps = { // An event when an option is selected onSelected: (value: string) => void; // The list of options to display @@ -167,14 +162,27 @@ class OptionGroup extends React.Component<{ // Use caution when using this - keyboard users need to know what // they're focused on in order to interact with the product! hideFocusState?: boolean; -}> { - // @ts-expect-error - TS2564 - Property 'focusedElement' has no initializer and is not definitely assigned in the constructor. - focusedElement: Element; +}; + +type OptionGroupState = { + focusedElement: Element | undefined; +}; + +// TODO(kevinb): +// - keep the the option group within the page bounds +// - do we really want to dismiss this on scroll +// - how does the drop down interact with tooltips? what's the z-index order? +class OptionGroup extends React.Component { + constructor(props: OptionGroupProps) { + super(props); + this.state = { + focusedElement: undefined, + }; + } componentDidMount() { - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if (this.focusedElement) { - findAndFocusElement(this.focusedElement); + if (this.state.focusedElement !== undefined) { + findAndFocusElement(this.state.focusedElement); } } @@ -190,31 +198,23 @@ class OptionGroup extends React.Component<{ return (
| undefined'. - style={{top}} + style={{top: 0}} className={css( styles.optionGroup, noMargin && styles.optionGroupNoMargin, )} > {React.Children.map(children, (child, index) => { - // @ts-expect-error - TS2532 - Object is possibly 'undefined'. + if (child === undefined) { + return null; + } const selected = selectedValues.includes(child.props.value); - const reference = - selected || index === 0 - ? (node: Element) => (this.focusedElement = node) - : null; - - // @ts-expect-error - TS2769 - No overload matches this call. return React.cloneElement(child, { - // @ts-expect-error - TS2532 - Object is possibly 'undefined'. ...child.props, key: index, selected: selected, - // @ts-expect-error - TS2532 - Object is possibly 'undefined'. onClick: () => onSelected(child.props.value), - ref: reference, onDropdownClose: onDropdownClose, hideFocusState: hideFocusState, }); diff --git a/packages/perseus-editor/src/components/widget-editor.tsx b/packages/perseus-editor/src/components/widget-editor.tsx index 5e32e0a4ff5..dd1350da859 100644 --- a/packages/perseus-editor/src/components/widget-editor.tsx +++ b/packages/perseus-editor/src/components/widget-editor.tsx @@ -42,7 +42,7 @@ const _upgradeWidgetInfo = (props: WidgetEditorProps): PerseusWidget => { // We can't call serialize here because this.refs.widget // doesn't exist before this component is mounted. const filteredProps = excludeDenylistKeys(props); - return applyDefaultsToWidget(filteredProps as any); + return applyDefaultsToWidget(filteredProps as PerseusWidget); }; // This component handles upgading widget editor props via prop diff --git a/packages/perseus-editor/src/widgets/label-image-editor/marker.tsx b/packages/perseus-editor/src/widgets/label-image-editor/marker.tsx index f40cb6713f2..7544e81e451 100644 --- a/packages/perseus-editor/src/widgets/label-image-editor/marker.tsx +++ b/packages/perseus-editor/src/widgets/label-image-editor/marker.tsx @@ -167,7 +167,7 @@ export default class Marker extends React.Component { styles.dropdownPositionWithArrow, )} > -