feat(item-themes): merge neutral/secondary into clear/outline + isSel…#1179
feat(item-themes): merge neutral/secondary into clear/outline + isSel…#1179tenphi wants to merge 17 commits into
Conversation
…ected - Drop `neutral` and `secondary` from `Button`, `ButtonSplit`, `Item`, `ItemAction`, `ItemBadge`, `ItemButton`, and `RadioGroup.buttonType`. Migrate `neutral` → `clear`, `clear` → `clear` + `isSelected`, `secondary` → `outline` + `isSelected`. - Default `type` for `ItemAction` / `ItemBadge` / `ItemButton` flips from `neutral` to `clear`. `ItemBadge` widens to `'primary' | 'outline' | 'clear' | 'link'` and supports `isSelected`. - Rename `Item.icon` / `ItemAction.icon` / `ItemBadge.icon` special value `'checkbox'` → `'checkmark'`; matching style modifier renamed too. - Realign `DEFAULT_CLEAR_STYLES` with `DEFAULT_ITEM_STYLES` so the non-selected pressed state and selected fill ramp behave consistently between the two. - Restructure state matrices in Button / ItemAction / Item / ItemButton / ButtonSplit stories to render selected variants in dedicated rows with consistent labels, switch row headers to `Title`, and fix `MenuSelectableCheckboxes` to pass `icon="checkmark"` explicitly. Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 71167b3 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 |
📦 NPM canary releaseDeployed canary version 0.0.0-canary-fca14eb. |
🏋️ Size limit report
Click here if you want to find out what is changed in this build |
🧪 Storybook is successfully deployed!
|
`outline-2` mirrors `outline` but paints over `#surface-3` instead of `#surface-2`, so it stays visually distinct when placed inside a `#surface-2` container. Wired into Button (props, ButtonVariant, Tasty variants map, button-split margin rule) with theme constants for default/danger/success/warning/note. Special theme has no `outline-2` counterpart and `theme="special" + type="outline-2"` falls back to `outline`. Button states stories now render the `outline-2` rows inside a `#surface-2` card and the special-theme matrix filters it out. Co-authored-by: Cursor <cursoragent@cursor.com>
Missed during the initial migration sweep: - Layout.stories: type="neutral" → type="clear" - RadioGroup.stories: buttonType="neutral" → "clear", argTypes updated - FilterPicker.stories: Badge type="neutral" → "disabled", argTypes updated - Select.stories: argTypes options updated - Toast.stories: type="secondary" → type="outline" Co-authored-by: Cursor <cursoragent@cursor.com>
0a19e04 to
17255c7
Compare
Group `RadioGroup type="button"` like `ButtonSplit`: zero gap, shared corner radius, overlapping borders, and the selected button bumped above siblings via z-index so its brand border reads from all four sides. Hover and focus-visible bump higher still so they always sit on top of the selected highlight. Replace the alpha-blended `#<theme>-text.15` outline border (which double-stacked at every overlap into a darker stripe) with a new opaque `#<theme>-border` token. The token re-resolves the existing neutral `border` ramp per colored theme at `saturation: 0.5` via `TINTED_SURFACE_OVERRIDE`, so each theme gets a subtly hue-tinted border without any extra palette bookkeeping. Co-authored-by: Cursor <cursoragent@cursor.com>
Each `fill` state map now uses the same 2-layer shape (opaque base + tint overlay) across non-selected, selected, and disabled states. tasty renders 1-color and 2-color fills via different CSS properties (`background-color` alone vs. `background-color` + `--tasty-second-fill-color` + `background-image: linear-gradient(...)`); transitioning between shapes caused the gradient overlay to snap on/off while `background-color` interpolated, briefly exposing the base layer and producing a visible flash (noticeable in `RadioGroup type="button"` selection toggles and in primary buttons toggling `isDisabled` on form submit). The brand-tinted overlays now composite over each variant's own base (`#surface` / `#surface-2` / `#surface-3` / `#special-surface`) instead of the body surface; the resulting visual shift is sub-1 OKHSL point and imperceptible side-by-side. Also folds `RadioGroup`'s tab-selected element into the base `RadioButtonElement` via mod-driven `selected & tabs` state rules so the button-mode grouping uses the simpler `!tabs &` selectors instead of the `@parent(radio-button-group, >)` chain. Co-authored-by: Cursor <cursoragent@cursor.com>
… to Item - Migrated every color in `src/data/item-themes.ts` to Glaze palette tokens, removing the legacy alias indirection from `src/tokens/colors.ts` (`#dark` → `#surface-text`, `#dark-02` → `#surface-text-soft`, `#primary-text` → `#primary-accent-text`, `#primary-hover` → `#primary-accent-surface-hover`, `#primary` brand fill → `#primary-accent-surface`, `#light` → `#surface-3`, `#clear` → `transparent`, plus matching ramps for danger / success / warning / note). Resolved values are unchanged. - Wired `outline-2` into `Item` (previously it only existed on `Button`), with the same `theme="special"` → `outline` fallback as `Button`. Every component that flows through `Item` (`ItemButton`, `Select`, `FilterPicker`, `Picker`, `Menu`, `RadioGroup`, etc.) now renders `type="outline-2"` correctly. Updated the corresponding `*.docs.mdx` files and `Select` / `FilterPicker` story argTypes. - Removed migration duplicates left over after `secondary → outline` / `neutral → clear` (`Button.Split` Variants story + docs example, `RadioGroup` `CustomButtonTypes` story). - `Radio.tsx`: gated the item-shadow on `tabs & selected`, gave the wrapper a focus-visible outline ring + radius so keyboard focus is visible on the radio label. Co-authored-by: Cursor <cursoragent@cursor.com>
`ItemAction` and `ItemBadge` only ship variants for `primary` / `outline` / `clear`. Without the mapping, an `Item` / `ItemButton` with `type="outline-2"` would pass `'outline-2'` through to its children, which then resolved to a non-existent `<theme>.outline-2` variant and rendered without any fill, border or color styles. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 200962d. Configure here.
Co-authored-by: Cursor <cursoragent@cursor.com>
…undant classic-wrapper ring
- Classic `RadioGroup` (`type="radio"`): the per-radio wrapper outline
was driven by `:focus-within`, so it also fired on mouse-click on the
label and duplicated the inner radio-circle focus ring. Drop the
wrapper outline entirely; the inner circle's `focused`-mod ring
remains the single, keyboard-gated indicator.
- Button / Tabs `RadioGroup` (`type="button"` / `type="tabs"`): there
was no group-level focus ring at all — the per-item `Item` themes
(`DEFAULT_OUTLINE_STYLES`, etc.) only swap the `border` color on
focus, which is easy to miss when the item is also selected. Add a
group-container outline gated on `focused & (button | tabs)`, driven
by React Aria's `useFocusRing({ within: true })` reading
`isFocusVisible` (not `isFocused`) so mouse clicks don't trigger it.
Co-authored-by: Cursor <cursoragent@cursor.com>
The `selected & tabs` override in `RadioButtonElement` forced `fill: '#surface'`, `color: '#dark'`, and `shadow: '$item-shadow'` regardless of the disabled state, so a disabled selected tab still rendered as a fully-opaque white pill with dark text and a live shadow — visually identical to an interactive one. Add `tabs & selected & disabled` branches that drop the shadow (`false`), bleed the surface (`#surface.6`) so the group's `#surface-4` chip shows through, and mute the label (`#dark.3`) to match the existing disabled unselected tabs. Co-authored-by: Cursor <cursoragent@cursor.com>
Move every non-item, non-card variant (primary, outline, outline-2, clear, link) across all themes from `border`-based focus to `outline`- based focus, using a single color per ring family: - Default / danger / success / warning / note: `#primary-accent-text` - Special: `#special-accent-text` (fixed-mode, non-inverting in dark) Item types keep their existing fill-based soft focus, and card types have no focus styling. Validation borders and selected/disabled border colors are unchanged. Theme-tinted *pressed* borders are preserved on primary variants. Co-authored-by: Cursor <cursoragent@cursor.com>
Add `outline-2` to argTypes / story variants and surrounding docs for Button, ButtonSplit, ItemButton, Item, Select, and RadioGroup, with a `#surface-2`-tinted wrapper where the contrast against the default surface ladder needs to be demonstrated. Refines existing comments to describe outline-2 as "fill base = #surface-3, designed to sit on #surface-2 containers" rather than the older "paints over" phrasing. Co-authored-by: Cursor <cursoragent@cursor.com>
`Block` lives at `src/components/Block.tsx`, not under `content/`. The wrong relative import broke the Storybook build with `Could not resolve '../../content/Block'`. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…t-fill→accent-surface Migrate DANGER/SUCCESS/WARNING/NOTE/SPECIAL primary fills to the same monotonic `accent-surface` → `-2` → `-3` ramp used by the default theme, giving press feedback and consistent contrast steps in both schemes. Add `accent-surface-2`/`-3` to the special theme palette and rename its `accent-fill*` tokens to `accent-surface*` to match the colored-theme naming convention. Co-authored-by: Cursor <cursoragent@cursor.com>

…ected
neutralandsecondaryfromButton,ButtonSplit,Item,ItemAction,ItemBadge,ItemButton, andRadioGroup.buttonType. Migrateneutral→clear,clear→clear+isSelected,secondary→outline+isSelected.typeforItemAction/ItemBadge/ItemButtonflips fromneutraltoclear.ItemBadgewidens to'primary' | 'outline' | 'clear' | 'link'and supportsisSelected.Item.icon/ItemAction.icon/ItemBadge.iconspecial value'checkbox'→'checkmark'; matching style modifier renamed too.DEFAULT_CLEAR_STYLESwithDEFAULT_ITEM_STYLESso the non-selected pressed state and selected fill ramp behave consistently between the two.Title, and fixMenuSelectableCheckboxesto passicon="checkmark"explicitly.Note
Medium Risk
Medium risk due to breaking API changes (removing
neutral/secondary, renamingicon="checkbox"tocheckmark, and special-theme token renames) plus broad updates to shareditem-themesstyles that affect many components’ visuals and interaction states.Overview
Introduces a new
outline-2type acrossButton/Item-based components (andSelect/Picker/FilterPicker/Menutriggers), using a#surface-3base so outlined controls remain distinct on#surface-2;specialtheme explicitly falls back tooutline.Breaking: removes
neutralandsecondaryfrom multipletypeAPIs (andRadioGroup.buttonType), expressing those looks viaclear/outlinecombined withisSelected, and flips default types forItemAction/ItemBadge/ItemButtontoclear. Also renames the special icon value and modifier fromcheckbox→checkmarkand updates docs/stories/tests accordingly.Refactors
src/data/item-themes.tsto use palette tokens directly, smooths fill transitions by standardizing fill layer shapes, fixesspecialtheme fill-map value collisions, and unifies theprimaryfill ramp across themes (including special palette/token renames). UpdatesRadioGroupbutton/tabs UX with ButtonSplit-like grouping, improved selected-border rendering, keyboard-only group focus ring, and correct disabled-selected tabs styling.Reviewed by Cursor Bugbot for commit 71167b3. Bugbot is set up for automated code reviews on this repo. Configure here.