Skip to content

[DS 2.0] Rebuild the form fields against the design system - #90

Open
librowski wants to merge 8 commits into
ds2-buttonsfrom
ds2-form-fields
Open

[DS 2.0] Rebuild the form fields against the design system#90
librowski wants to merge 8 commits into
ds2-buttonsfrom
ds2-form-fields

Conversation

@librowski

@librowski librowski commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Rebuilds Input and TextArea against the design system's field states.

State instead of a booleanstate?: 'default' | 'critical' | 'success' | 'read-only' replaces error?: boolean. Hover, focus and filled stay visual states rather than props. read-only applies the native attribute, so the value stays focusable and copyable, while disabled stays out of the tab order — the distinction the design guidelines call for.

SlotsprefixIcon, suffixIcon and an optional onClear affordance. Icon slots accept interactive content: clicks on buttons or links inside a slot pass through, anywhere else on the frame focuses the input.

Sizes — letter-scaled l m s xs. Input row heights 42/36/32/28 with padding 11/10/8/6 vertical and 12 horizontal, gap 8, radius 8/6/6/6; the field composes a label row, the input row and a helper row that wrap without painting over the control. TextArea minimum heights 120/100/80.

Colours — every surface, border and text colour binds to a field token. The hover border is deliberately lighter than the default one; that is what the design paints. The field composition (label and helper) exposes its own public variables, and disabled now dims the whole composition, muting the critical helper.

NumberField was pulled out of this PR by maintainer decision; it ships as a standalone component after the DS 2.0 migration.

Call sites migrated in this PR (error={…}state, word sizes → letters).

Verified: ui/sdk lint + typecheck, build:ui, build:lib, stylelint, all test suites, docs build, demo build — re-run after extracting NumberField and rebasing onto the Button layer.

@librowski
librowski force-pushed the ds2-form-fields branch 3 times, most recently from 2b6bf2a to 1ea85e4 Compare August 25, 2026 23:45
@librowski
librowski marked this pull request as ready for review August 26, 2026 07:56
@librowski librowski changed the title Rebuild the form fields and add NumberField Rebuild the form fields against the design system Aug 26, 2026
@librowski librowski changed the title Rebuild the form fields against the design system [DS 2.0] Rebuild the form fields against the design system Aug 26, 2026
Fields take an explicit state - default, critical, success or
read-only - in place of the error boolean, and sizes are letter-scaled.
Hover, focus and filled stay visual states rather than props. Read-only
keeps the field focusable and copyable through the native attribute,
while disabled stays out of the tab order.

Icons arrive as prefix and suffix slots with an optional clear
affordance. Heights, padding, gap, radius and the label roles come from
the design component set, and every surface, border and text colour
binds to its field token.

NumberField is new: an input with an always-visible stepper that
honours min, max and step from both the buttons and the arrow keys.
Fields render the measured composition again: a label row, the control
row and a helper row. The label is associated with the control, the
helper joins its accessible description, and the critical state marks
the control invalid, so validation text is announced instead of being
merely visible.

Focus is visible in every state, not only the default one.

Interactive adornments no longer go into the decorative icon slot,
which does not take pointer events - the datetime field renders its
variable-picker button beside the input, the way its sibling branches
already do.

NumberField now has a value contract: clearing is representable and
reported, a clamped value is emitted once, a controlled parent that
refuses an update wins, non-finite input never reaches a callback,
step=any keeps working, off-grid boundaries stay submittable, and
malformed paste is rejected rather than reinterpreted. Fifteen tests
pin those paths.
return (
<ComponentPreview>
<Input placeholder="Type something" value={value} onChange={(event) => setValue(event.target.value)} />
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--wb-space-100)' }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why inline styles instead of css class?

return (
<ComponentPreview>
<TextArea placeholder="Multi-line input" value={value} onChange={(event) => setValue(event.target.value)} />
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--wb-space-100)' }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants