feat(shared): fields v2 — align fields with Toggle + Button system#6118
Open
tsahimatsliah wants to merge 15 commits into
Open
feat(shared): fields v2 — align fields with Toggle + Button system#6118tsahimatsliah wants to merge 15 commits into
tsahimatsliah wants to merge 15 commits into
Conversation
Reskin the shared field primitives to the new design language shared with the redesigned Toggle and the Button system: - Swap the legacy left-edge accent bar for a crisp, even ring on focus / invalid / readonly / password-strength, with smooth surface transitions (matching the toggle's motion). Applied to BaseField so input, password, textarea and search all update across the product. - Add a button-aligned FieldSize scale (fieldSizes.ts) that mirrors ButtonSize exactly — same heights, radii, value typography and icon sizes. A field and a button of the same `size` now line up pixel-for-pixel when they sit together in one strip, including matching "medium" icon sizes. - Thread an opt-in `fieldSize` prop through TextField / BaseFieldContainer (icons are auto-sized to match); legacy `fieldType` sizing is preserved when `fieldSize` is omitted, so existing call sites are unchanged. - Add a Storybook before/after comparison page (Field.stories.tsx) with a frozen legacy snapshot, covering states, field types, password/search and a field-vs-button size-alignment section. Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…own polish - Add a faint resting border to every field (BaseField) so fields are delineated from the page, matching the Subtle/Button v2 language. - Introduce FieldVariant (Filled / Outline) on TextField + Textarea: Filled sits on the floated surface, Outline is transparent and defined by its border with a faint hover fill. - Restore the password strength left-edge indicator + colour-graded gradient on the new field (per design preference). - Polish the dropdown popover: rounded-14 card, inset items, taller rows and smooth highlight transition. - Expand the comparison story with Variants and Dropdown & textarea sections (wrapped in a QueryClientProvider for the dropdown). Co-authored-by: Cursor <cursoragent@cursor.com>
- Invalid fields now use a red 1px border (same mechanism as the focus border) instead of an inset ring, and stay red while focused — matching the design and reading as one family with focus/read-only borders. - Fix declarative validity: an externally-controlled `valid` prop is now authoritative on first render, so a field rendered already-invalid shows its error state immediately instead of waiting for interaction. - Restore the disabled dim on fields (BaseFieldContainer + SearchField). - Storybook: add comprehensive per-field state coverage — TextField states, field types, variants, sizes; PasswordField strength ladder; SearchField states/sizes/variants; Textarea states; Dropdown states/sizes. Co-authored-by: Cursor <cursoragent@cursor.com>
Consolidate the field redesign into one "Fields — before & after" page so the team can play with old vs new side by side: - Add a "What changed" summary and before/after rows for text input states, field types, password & search, textarea and dropdown (trigger + popover). - Add a LegacyTextarea snapshot of the previous multi-line look for the textarea comparison. - Keep the new-only sections (background variants, size alignment with buttons) on the same page. - Fix stale "even ring" copy now that focus uses a 1px border. Co-authored-by: Cursor <cursoragent@cursor.com>
On light theme especially, the faint grey fill plus low-contrast tertiary content made an idle field look almost identical to its dimmed disabled state. Brighten and define the resting state in both themes: - Default (empty, editable) icon, value text and placeholder now use text-secondary instead of tertiary, so the field reads as active and clearly differs from the opacity-dimmed disabled state. - Resting border steps up from border-subtlest-tertiary to border-subtlest-secondary so every field is delineated as a real input box rather than a flat grey block. Co-authored-by: Cursor <cursoragent@cursor.com>
Align the internals of every field with the button system and clean up the ad-hoc spacing/colors: - Icons now scale with the field height (one rung below the button glyph scale so they stay balanced inside an input) and auto-size even without an explicit fieldSize. - Icon-to-value spacing uses the button gap scale (fieldSizeToGap) instead of a flat 8px margin, applied as a row gap so every adornment is evenly spaced. - Char counter drops back to a muted text-quaternary (was darkened as a side effect of the placeholder colour change) since it's metadata, not a value. - Dropdown trigger text now uses text-secondary; the chevron gets an explicit size, a muted text-quaternary rest colour that brightens to primary on hover, and the no-op group-hover override is removed. - SearchField adopts the same icon size / gap scale and the defined secondary resting border. Co-authored-by: Cursor <cursoragent@cursor.com>
The Button's built-in Large horizontal padding (px-6) was overriding the dropdown's intended px-3, leaving the chevron floating 24px from the right edge. Force the inset with !pl-4/!pr-2.5 so the value aligns with the other fields' 16px text inset and the chevron sits tight to the edge, and drop the chevron from 24px to a refined 20px (shrink-0 keeps it from squishing). Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The search field's `!bg-background-default` blocks the base `.field:hover` background, so hovering produced no feedback. Give it its own hover — brighten the border to subtlest-primary and tint the surface — scoped to `:not(.focused)` so it never overrides the focus ring while active. Co-authored-by: Cursor <cursoragent@cursor.com>
The resting border was bumped to subtlest-secondary (40%) earlier, which read as a dominant outline. Drop it to the exact Button v2 Float hairline — 15% of border-subtlest-primary — centralized on `.field` so every field (and the search field, which previously hard-set its own border) shares one faint, consistent weight. Search hover now steps to 40% instead of full primary, and the story's dropdown trigger uses the same hairline. Co-authored-by: Cursor <cursoragent@cursor.com>
The textarea reserved a tight top inset (pt-1/pt-2) for the floating "title inside" caption, but that caption only exists for a primary field with a label. Without it the top sat at ~8px while the sides were 16px. Now the inner label only renders when a label exists, and any field without that caption pads every side equally (py-4). Adds Storybook coverage for both layouts. Co-authored-by: Cursor <cursoragent@cursor.com>
Add a size-aware `fieldSizeToIconLeftPadding` that mirrors the button's icon-side reduction (IconSidePaddingV2) so a leading glyph hugs the edge tighter than the value side and scales with field size. Replaces the flat pl-3 in TextField and reduces the SearchField leading-icon inset to match. Co-authored-by: Cursor <cursoragent@cursor.com>
…cale BaseFieldContainer and SearchField hardcoded their radii (rounded-14/10, rounded-12/14) which duplicated fieldSizeToRadius. Route both through the map so every field's corner radius is the single button-aligned guideline by size (16/14/12/10/8) with no divergent values. No visual change. Co-authored-by: Cursor <cursoragent@cursor.com>
The button-aligned icon-side reduction (pl-2 etc.) sat the glyph too close to the left edge. Restore the flat pl-3 inset on TextField, drop the SearchField icon-left override, and remove the now-unused fieldSizeToIconLeftPadding map. Radius consolidation is unaffected. Co-authored-by: Cursor <cursoragent@cursor.com>
… radius
- useInputFieldFunctions: only surface an external invalid state once the
field has content, so a pristine empty field with a value-derived
valid={false} (e.g. valid={!!name}, valid={value.length>0}) no longer
flashes a red border on mount. valid=true and server/submit errors (which
carry content) still apply immediately.
- fieldSizes: drop the unused fieldSizeToHorizontalPadding map and the
getFieldSizeTokens aggregator (only height/typo were consumed); TextField
now reads the height/typo maps directly.
- TextField.module.css: remove the hardcoded 14px corner on the password
strength bar; the parent's overflow-hidden clips it to the field's actual
radius, so it stays correct at any field size.
Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the fields in line with the redesigned Toggle and the Button system, so fields, buttons and toggles read as one family.
BaseFieldprimitive in place, soTextField(input),PasswordField,TextareaandSearchFieldall update across the product automatically.Dropdownis button-based and already follows the button language.fieldSizes.tsexposes aFieldSizeenum that mirrorsButtonSizeexactly — identical heights, radii, value typography and icon sizes. A field and a button of the same size line up pixel-for-pixel in a shared strip, and a "medium" icon is the same glyph size whether it lives in a field or a button.fieldSizeprop threads throughTextField/BaseFieldContainer(icons auto-size to match). When omitted, the legacyfieldType-driven dimensions are preserved, so existing call sites are unchanged.Components/Fields/Fieldrenders the previous vs new fields side-by-side (states, field types, password/search) against a frozen legacy snapshot, plus a dedicated field-vs-button size-alignment section.Notes
sizewas already taken by the native input attribute, so the new prop is namedfieldSize.scripts/typecheck-strict-changed.js) andsharedlints clean.Test plan
Components/Fields/Field→ review Comparison in light & dark; hover / focus / type each field.pnpm --filter shared testfor TextField / PasswordField / SearchField (15 passing).Made with Cursor
Preview domain
https://feat-fields-v2-redesign.preview.app.daily.dev