Migrate sanity-plugin-media styling from styled-components to vanilla-extract - #1847
Migrate sanity-plugin-media styling from styled-components to vanilla-extract#1847stipsan wants to merge 4 commits into
Conversation
…-extract - Replace every styled(Component)/styled.div/createGlobalStyle usage with colocated .css.ts files (style(), createVar()/assignInlineVars() for theme/scheme-dependent values, globalStyle() for descendant/global selectors, and keyframe-free variants for boolean-driven styles) - Read theme tokens via @sanity/ui's useTheme_v2() instead of the styled-components theme prop; drop the ambient styled-components theme augmentation (src/types/sanity-ui.d.ts) - Rename the Image component's $scheme/$showCheckerboard transient props to scheme/showCheckerboard and update all call sites - Switch tsdown.config.ts from styledComponents to vanillaExtract, register the vanilla-extract Vite plugin in vitest.config.ts, and update package.json dependencies (drop styled-components peer/devDependency, add @vanilla-extract/css, @vanilla-extract/dynamic, @sanity/vanilla-extract-vite-plugin, clsx) - Add a patch changeset
🦋 Changeset detectedLatest commit: 7f6175b The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
✅ E2E Tests🟢 25 passed • 🟡 1 flaky • view full report • view run Studio: https://plugins-e2e-test-studio-c7uobuh0l.sanity.dev Datasets: |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Migrates sanity-plugin-media off styled-components and onto vanilla-extract (zero-runtime CSS), aligning the plugin with the monorepo’s styling approach and build/test tooling for extracted CSS.
Changes:
- Replaced
styled-componentsusage across UI components with colocated vanilla-extract*.css.tsfiles plus theme-drivencreateVar()/assignInlineVars()patterns. - Updated plugin build/test config to enable vanilla-extract (tsdown + Vitest plugin + runtime-style disabling).
- Updated dependencies/exports to support extracted CSS (
./bundle.css) and addedclsxfor class composition.
Reviewed changes
Copilot reviewed 39 out of 41 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Adds clsx to the shared catalog for workspace-wide reuse. |
| pnpm-lock.yaml | Adds new deps for the migration and updates lock resolutions (including sanity@next tag resolution). |
| plugins/sanity-plugin-media/vitest.config.ts | Registers vanilla-extract Vitest plugin and disables runtime styles in tests. |
| plugins/sanity-plugin-media/tsdown.config.ts | Switches build from styled-components mode to vanilla-extract extraction. |
| plugins/sanity-plugin-media/src/types/sanity-ui.d.ts | Removes styled-components theme augmentation (no longer needed). |
| plugins/sanity-plugin-media/src/styled/GlobalStyles/index.tsx | Removes createGlobalStyle-based global styling component. |
| plugins/sanity-plugin-media/src/styled/GlobalStyles/GlobalStyles.css.ts | Replaces prior global styles with vanilla-extract globalStyle() side effects. |
| plugins/sanity-plugin-media/src/components/UploadDropzone/UploadDropzone.css.ts | Adds vanilla-extract styles for the dropzone containers. |
| plugins/sanity-plugin-media/src/components/UploadDropzone/index.tsx | Replaces styled wrappers with vanilla-extract classes for the upload dropzone. |
| plugins/sanity-plugin-media/src/components/Tag/Tag.css.ts | Ports Tag layout/hover visibility styling to vanilla-extract. |
| plugins/sanity-plugin-media/src/components/Tag/index.tsx | Replaces styled wrappers with class-based wrappers using clsx. |
| plugins/sanity-plugin-media/src/components/TableRowUpload/index.tsx | Renames transient styled-components props to regular props for Image. |
| plugins/sanity-plugin-media/src/components/TableRowFolder/TableRowFolder.css.ts | Adds vanilla-extract styles/vars for folder row hover and glyph colors. |
| plugins/sanity-plugin-media/src/components/TableRowFolder/index.tsx | Replaces styled components with wrapper functions + theme-driven vars. |
| plugins/sanity-plugin-media/src/components/TableRowAsset/TableRowAsset.css.ts | Adds vanilla-extract styles/vars for row state, hover, and icon color. |
| plugins/sanity-plugin-media/src/components/TableRowAsset/index.tsx | Replaces styled components with wrapper functions + theme/scheme-driven vars. |
| plugins/sanity-plugin-media/src/components/TableHeader/TableHeader.css.ts | Adds vanilla-extract hover styling for the header context action. |
| plugins/sanity-plugin-media/src/components/TableHeader/index.tsx | Replaces styled header wrapper with a class-based wrapper using vars. |
| plugins/sanity-plugin-media/src/components/SearchFacets/SearchFacets.css.ts | Ports child spacing behavior using globalStyle() + a CSS var. |
| plugins/sanity-plugin-media/src/components/SearchFacets/index.tsx | Replaces styled StackContainer with wrapper + theme-driven spacing var. |
| plugins/sanity-plugin-media/src/components/SearchFacet/SearchFacet.css.ts | Adds vanilla-extract vars for scheme-driven background and radius. |
| plugins/sanity-plugin-media/src/components/SearchFacet/index.tsx | Replaces styled container with wrapper + inline vars for bg/radius. |
| plugins/sanity-plugin-media/src/components/Image/index.tsx | Converts Image from styled-components to a real <img> with VE classes/vars. |
| plugins/sanity-plugin-media/src/components/Image/Image.css.ts | Implements base + checkerboard image styles via vanilla-extract. |
| plugins/sanity-plugin-media/src/components/FormFieldInputLabel/index.tsx | Replaces styled icon color with vanilla-extract + theme-driven var. |
| plugins/sanity-plugin-media/src/components/FormFieldInputLabel/FormFieldInputLabel.css.ts | Adds vanilla-extract var-backed styling for the error icon. |
| plugins/sanity-plugin-media/src/components/FileIcon/index.tsx | Moves forced SVG text styling to VE + theme-driven font var. |
| plugins/sanity-plugin-media/src/components/FileIcon/FileIcon.css.ts | Uses globalStyle() to force react-file-icon SVG text styles. |
| plugins/sanity-plugin-media/src/components/EditAssetTool/index.tsx | Imports global styles via side-effect VE module instead of rendering <GlobalStyle />. |
| plugins/sanity-plugin-media/src/components/DialogAssetEdit/index.tsx | Updates Image usage to new prop names (scheme, showCheckerboard). |
| plugins/sanity-plugin-media/src/components/CardUpload/index.tsx | Replaces styled wrapper with VE class wrapper and updates Image props. |
| plugins/sanity-plugin-media/src/components/CardUpload/CardUpload.css.ts | Adds vanilla-extract styling for upload card wrapper. |
| plugins/sanity-plugin-media/src/components/CardFolder/index.tsx | Replaces styled wrappers/glyph with VE + theme var for yellow. |
| plugins/sanity-plugin-media/src/components/CardFolder/CardFolder.css.ts | Adds vanilla-extract styles/vars for folder card + glyph. |
| plugins/sanity-plugin-media/src/components/CardAsset/index.tsx | Replaces styled card containers/icons with VE + inline vars. |
| plugins/sanity-plugin-media/src/components/CardAsset/CardAsset.css.ts | Adds vanilla-extract styles/vars for picked/updating/hover states. |
| plugins/sanity-plugin-media/src/components/Browser/index.tsx | Imports global styles via side-effect VE module instead of rendering <GlobalStyle />. |
| plugins/sanity-plugin-media/src/components/AssetGridVirtualized/index.tsx | Removes styled wrappers in Virtuoso grid components in favor of VE classes. |
| plugins/sanity-plugin-media/src/components/AssetGridVirtualized/AssetGridVirtualized.css.ts | Adds vanilla-extract grid sizing/layout for the virtualized grid. |
| plugins/sanity-plugin-media/package.json | Drops styled-components deps, adds vanilla-extract deps, and exports ./bundle.css. |
| .changeset/media-vanilla-extract.md | Adds a patch changeset documenting the migration for consumers. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
sanity-plugin-media's styling now ships as vanilla-extract .css.ts files. dev/e2e-studio bundles plugin source directly and didn't have the @sanity/vanilla-extract-vite-plugin registered (unlike dev/test-studio), so the deployed e2e studio failed at runtime with "Styles were unable to be assigned to a file", breaking every e2e test (not just media's).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 43 changed files in this pull request and generated no new comments.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Suppressed comments (1)
plugins/sanity-plugin-media/src/components/TableRowFolder/index.tsx:40
FolderBadgesets its ownstyleprop after spreading...props, which will drop anystylepassed by callers (and differs fromContainerGrid, which merges styles). Merging keeps the wrapper component safer and consistent ifstyleis ever provided.
- Scope the GlobalStyles.css.ts rules (custom scrollbar, dark Dialog background) under a class toggled on document.body only while the media Browser/Edit tool is mounted, restoring the old createGlobalStyle mount/unmount lifecycle instead of applying them Studio-wide forever. Reference-counted so overlapping instances don't disable each other early. - Merge the incoming `style` prop in TableRowFolder's FolderBadge wrapper instead of overwriting it, matching every other wrapper in the plugin. Addresses Cursor Bugbot and Copilot review feedback on PR #1847.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 39 out of 41 changed files in this pull request and generated no new comments.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Suppressed comments (1)
plugins/sanity-plugin-media/src/components/Image/index.tsx:13
Propsnow derives fromComponentProps<'img'>, which makessrcoptional. The previous styled-component version requiredsrc: string, and keeping it required helps prevent accidentally rendering a broken<img>(especially since this is an internal wrapper that assumes a real asset URL).
type Props = Omit<ComponentProps<'img'>, 'crossOrigin'> & {
scheme?: ThemeColorSchemeKey
showCheckerboard?: boolean
}
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7f6175b. Configure here.
| backgroundClip: 'padding-box', | ||
| }) | ||
|
|
||
| globalStyle(`.${globalStylesActive} ${selector}::-webkit-scrollbar-thumb:hover`, { |
There was a problem hiding this comment.
Scoped global selectors gain duplicate class dots
Medium Severity
Manually prefixing globalStylesActive with a dot produces invalid double-dot selectors after vanilla-extract scopes the registered class. Consequently, the dialog background and custom scrollbar rules never match.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7f6175b. Configure here.
| '&::before': { | ||
| background: spotYellowVar, | ||
| borderRadius: '8px 8px 0 0', | ||
| content: '', |
There was a problem hiding this comment.
Folder tabs lack generated pseudo-elements
Low Severity
Using an empty JavaScript string for CSS content emits no valid generated content, so both folder ::before tabs disappear. Vanilla-extract requires a quoted CSS string such as content: '""'.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7f6175b. Configure here.


What
Migrates
sanity-plugin-media's styling fromstyled-componentsto vanilla-extract (zero-runtime CSS), following themigrate-styled-components-to-vanilla-extractskill.How
styled(Component),styled.div, andcreateGlobalStyleusage is replaced with a colocated*.css.tsfile (style()for static rules,createVar()+assignInlineVars()for theme/scheme-dependent values,globalStyle()for descendant/global selectors that vanilla-extract'sselectorsAPI doesn't allow, and plain conditional classes for boolean-driven variants like$selected/$updating/$picked).({theme}) => theme.sanity.color...) are replaced with@sanity/ui'suseTheme_v2()hook. Where the old flatcolor.spot.*had no v2 equivalent, the v2 replacement iscolor.avatar.<name>.bg;color.card.enabled.bgmaps to the contextualcolor.bg.Tag's${TagContainer}:hover &cross-component selector andFileIcon's descendanttext {...}rule both neededglobalStyle()since vanilla-extract'sselectorsonly allows selectors that resolve back to&.Image's$scheme/$showCheckerboardtransient props are renamed toscheme/showCheckerboard(no longer styled-components props) across all 5 call sites; the wrapper also picks up a defaultalt=""for accessibility now that it's a real<img>element in JSX.src/types/sanity-ui.d.ts(thestyled-componentsDefaultThemeaugmentation) is deleted along withsrc/styled/GlobalStyles/index.tsx— the global scrollbar/dialog styles now live inGlobalStyles.css.ts, imported for its side effect directly where<GlobalStyle />used to render.tsdown.config.tsswitchesstyledComponents: true→vanillaExtract: true;vitest.config.tsregistersvanillaExtractPlugin()and@vanilla-extract/css/disableRuntimeStyles.package.json: drops thestyled-componentspeer/devDependency, adds@vanilla-extract/css+@sanity/vanilla-extract-vite-plugin(devDependencies),@vanilla-extract/dynamic+clsx(dependencies).sanity/@sanity/uipeer resolution inpnpm-lock.yamlstill shares the single workspace-widestyled-components@6.4.4variant (no fork).Testing
pnpm format,pnpm lint,pnpm knip,pnpm build,pnpm test runall pass for the whole workspace (thetest-studiobuild failure encountered mid-way was a pre-existing, unrelatedsanity@nextprerelease/auto-updates-CDN timing issue, reproducible onmainwith a freshpnpm install, not something this PR introduces).pnpm dev): grid view, table view, folder cards/rows (yellow glyph + hover), the Create Folder dialog, and the Tags panel all render identically to before, with no unstyled elements or layout regressions.Media browser grid view
Media browser table view
Folder card in grid view with yellow glyph
Folder row in table view
Create Folder dialog
To show artifacts inline, enable in settings.