From d3bf5065a0e68f86af65884dbe7fda7ba29119b3 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 17 Sep 2025 18:55:25 -0400 Subject: [PATCH] chore(site): convert more components from Emotion to TailwindCSS (#19719) ## Changes made - Patched React `CSSProperties` type to add support for custom CSS properties - Updated several of the components in the `components` directory to Tailwind - Updated most of the `WorkspacePageBuildView` component to Tailwind to account for CSS specificity changes - Updated `Search` to address accessibility violation and removed all MUI logic - Updated `Search` stories (added new story, decoupled all stories from single decorator) - Updated `autoFocus` behavior in `SearchField` - Updated the styling for `WorkspacePageBuildView` to make sure the tabs had enough padding - Fixed layout effect in `WorkspacePageBuildView` to fire correctly --- site/src/@types/react.d.ts | 7 + site/src/components/Filter/SelectFilter.tsx | 4 +- .../MultiSelectCombobox.tsx | 2 +- site/src/components/Search/Search.stories.tsx | 40 +++- site/src/components/Search/Search.tsx | 96 +++----- .../components/SearchField/SearchField.tsx | 38 ++- site/src/components/SelectMenu/SelectMenu.tsx | 34 +-- .../components/SignInLayout/SignInLayout.tsx | 41 +--- site/src/components/Spinner/Spinner.tsx | 44 ++-- site/src/components/StackLabel/StackLabel.tsx | 21 +- site/src/components/Stats/Stats.tsx | 88 ++----- .../components/TableLoader/TableLoader.tsx | 2 +- site/src/components/Tabs/Tabs.tsx | 20 +- .../src/components/Timeline/TimelineEntry.tsx | 47 +--- .../WorkspaceBuildPageView.tsx | 222 +++++++----------- .../pages/WorkspacesPage/WorkspacesButton.tsx | 8 +- 16 files changed, 281 insertions(+), 433 deletions(-) create mode 100644 site/src/@types/react.d.ts diff --git a/site/src/@types/react.d.ts b/site/src/@types/react.d.ts new file mode 100644 index 0000000000..553a983dc9 --- /dev/null +++ b/site/src/@types/react.d.ts @@ -0,0 +1,7 @@ +declare module "react" { + interface CSSProperties { + [key: `--${string}`]: string | number | undefined; + } +} + +export {}; diff --git a/site/src/components/Filter/SelectFilter.tsx b/site/src/components/Filter/SelectFilter.tsx index f7354e1854..a6f6ad6776 100644 --- a/site/src/components/Filter/SelectFilter.tsx +++ b/site/src/components/Filter/SelectFilter.tsx @@ -52,8 +52,8 @@ export const SelectFilter: FC = ({ {selectedOption?.label ?? placeholder} diff --git a/site/src/components/MultiSelectCombobox/MultiSelectCombobox.tsx b/site/src/components/MultiSelectCombobox/MultiSelectCombobox.tsx index 06b2660df2..ca9332e350 100644 --- a/site/src/components/MultiSelectCombobox/MultiSelectCombobox.tsx +++ b/site/src/components/MultiSelectCombobox/MultiSelectCombobox.tsx @@ -506,7 +506,7 @@ export const MultiSelectCombobox = forwardRef< = { title: "components/Search", component: SearchInput, - decorators: [ - (Story) => ( - - - - ), - ], }; export default meta; type Story = StoryObj; -export const Example: Story = {}; +export const Example: Story = { + render: (props) => ( + + + + ), +}; -export const WithPlaceholder: Story = { +export const WithCustomPlaceholder: Story = { args: { label: "uwu", placeholder: "uwu", }, + render: (props) => ( + + + + ), +}; + +export const WithSearchEmpty: Story = { + args: { + label: "I crave the certainty of steel", + placeholder: "Alas, I am empty", + }, + render: (props) => ( +
+ + + + + +
+ ), }; diff --git a/site/src/components/Search/Search.tsx b/site/src/components/Search/Search.tsx index 7fecd57df2..66a9be7ffa 100644 --- a/site/src/components/Search/Search.tsx +++ b/site/src/components/Search/Search.tsx @@ -1,12 +1,9 @@ -import type { Interpolation, Theme } from "@emotion/react"; -// biome-ignore lint/style/noRestrictedImports: use it to have the component prop -import Box, { type BoxProps } from "@mui/material/Box"; -import visuallyHidden from "@mui/utils/visuallyHidden"; import { SearchIcon } from "lucide-react"; import type { FC, HTMLAttributes, InputHTMLAttributes, Ref } from "react"; +import { cn } from "utils/cn"; -interface SearchProps extends Omit { - $$ref?: Ref; +interface SearchProps extends HTMLAttributes { + ref?: Ref; } /** @@ -18,100 +15,63 @@ interface SearchProps extends Omit { * * ``` */ -export const Search: FC = ({ children, $$ref, ...boxProps }) => { +export const Search: FC = ({ + children, + ref, + className, + ...props +}) => { return ( - - +
+ {children} - +
); }; -const SearchStyles = { - container: (theme) => ({ - display: "flex", - alignItems: "center", - paddingLeft: 16, - height: 40, - borderBottom: `1px solid ${theme.palette.divider}`, - }), - - icon: (theme) => ({ - fontSize: 14, - color: theme.palette.text.secondary, - }), -} satisfies Record>; - type SearchInputProps = InputHTMLAttributes & { label?: string; - $$ref?: Ref; + ref?: Ref; }; export const SearchInput: FC = ({ label, - $$ref, + ref, + id, ...inputProps }) => { return ( <> -