Migrate Menu, Layer and Tab to vanilla-extract - #2736
Conversation
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
🦋 Changeset detectedLatest commit: b24a936 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
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
|
…rsor/vanilla-extract-third-slice-c941 Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
…rsor/vanilla-extract-third-slice-c941 Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR continues the styled-components → vanilla-extract migration in @sanity/ui by moving three components’ fully static styles into colocated vanilla-extract modules, ensuring the components no longer depend on styled-components and instead rely on the shared @sanity/ui/styles.css stylesheet.
Changes:
- Refactored
Menu,Layer, andTabto apply static styles via vanilla-extract classes andclsx/liteclass merging. - Added new vanilla-extract style modules (
menu.css.ts,layer.css.ts,tab.css.ts) to preserve the previous static CSS. - Added a minor changeset documenting the migration and reiterating the
@sanity/ui/styles.cssimport requirement.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/ui/src/core/components/menu/menu.tsx | Replaces styled(Box) with a vanilla-extract class on Box via clsx. |
| packages/ui/src/core/components/menu/menu.css.ts | Adds static outline and overflow styles as extracted CSS. |
| packages/ui/src/core/utils/layer/layer.tsx | Replaces styled.div with a polymorphic element using a vanilla-extract class and clsx. |
| packages/ui/src/core/utils/layer/layer.css.ts | Adds static position: relative styling as extracted CSS. |
| packages/ui/src/core/components/tab/tab.tsx | Replaces styled(Button) wrapper with Button + vanilla-extract class via clsx. |
| packages/ui/src/core/components/tab/tab.css.ts | Adds static max-width: 100% styling as extracted CSS. |
| .changeset/vanilla-extract-third-slice.md | Declares a minor release and documents the styling contract (@sanity/ui/styles.css). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Stacked on #2732. Three more low-risk styled-components → vanilla-extract refactors, following the same screening: fully static CSS (no theme or prop interpolation), zero property collisions with runtime-injected styled-components rules (so cascade order between the static stylesheet and runtime styles cannot matter), and each file ends up completely off styled-components. Class name merging uses
clsx/lite, introduced on the base PR.The three refactors
Menu(packages/ui/src/core/components/menu/menu.tsx):StyledMenu = styled(Box)withoutline: none; overflow: autobecomes<Box className={clsx(menu, className)}>.boxStyle/responsive Box styles never emitoutlineoroverflowunless theoverflowprop is passed (Menu never passes it), so there is no collision.Layer(packages/ui/src/core/utils/layer/layer.tsx):styled.div({position: 'relative'})becomes a plain element with a vanilla-extract class. Theasprop previously flowed through the rest-prop spread into styled-components' polymorphism; it is now handled explicitly with the same widening pattern asSrOnly. The twostyled(Layer)wrappers keep working:StyledTooltiponly addspointer-events: none(no colliding property), andStyledDialogoverridespositionthrough a doubled-specificity&&selector that beats the vanilla class regardless of stylesheet order.Tab(packages/ui/src/core/components/tab/tab.tsx):CustomButton = styled(Button)withmax-width: 100%becomes<Button className={clsx(tab, className)}>. Nothing in the button primitive setsmax-width, so no collision.Not picked
TabList'sstyled(Inline)overrides& > divproperties thatinlineBaseStylealso sets (display,vertical-align) — the values are identical today, but the override relies on styled-components injection order, so it stays behind for now. Same for the previously rejected breadcrumbsExpandButtonand hotkeysKey.Changeset
One
minorchangeset, same wording as the second slice: no API changes, but these components now require the@sanity/ui/styles.cssimport that has been part of the v4 contract since 4.0.0.Verification
pnpm lint(includes tsgolint type checking),pnpm test(all unit tests, including the menu keyboard/spacing tests) andpnpm knipall pass.pnpm --filter @sanity/ui buildextracts the three new rule sets intodist/styles.cssalongside the second-slice ones.pnpm test:browserpasses: 245 tests across 61 story files rendered in headless Chromium with play interactions.Menuresolves tooutline-style: none; overflow: autowith Box's runtime classes still applied (padding intact).Layers (Layer Nested story) resolve toposition: relativewith their inlinez-index(1, 2); the tooltip layer keeps floating-ui's inlineposition: absolutepluspointer-events: nonefromStyledTooltip; the dialog layer resolves toposition: fixedvia the&&override — proving overrides in both directions still work.Tabresolves tomax-width: 100%with Button'sdisplay: inline-flexintact.Tab story with the Baz tab selected and its panel shown
Dialog centered over a dimmed backdrop, its Layer position fixed
menu_tab_dialog_layer_walkthrough.mp4
To show artifacts inline, enable in settings.