swarm-ui: shared form-field kit (TextField, SelectField, Button)
Closes #3448. New ui/ primitives: FormField (shared label+control wrapper), TextField, SelectField, Button — each with a min-height touch target (2.75em ~= 44px, WCAG 2.5.5) per mara's #3447 ask, and a max-width instead of a fixed width so the control caps on desktop without overflowing a narrow/touch viewport. CreateAgentPage's name field + submit button now come from the kit instead of page-scoped CSS; ComponentsPage gets a section for each new primitive with an editable sample.
This commit is contained in:
parent
3643eccf22
commit
ba873926fa
9 changed files with 288 additions and 57 deletions
32
frontend/packages/swarm-ui/src/ui/form-field/FormField.css
Normal file
32
frontend/packages/swarm-ui/src/ui/form-field/FormField.css
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* <FormField> — label stacked above its control, plus the shared
|
||||
`.ui-form-control` chrome every text/select input in the kit draws
|
||||
from (one class, so the two never drift). `max-width` + `width: 100%`
|
||||
rather than a fixed `width`: caps the control on a wide desktop
|
||||
viewport without forcing an overflow on a narrow/touch one.
|
||||
`min-height` is a touch-target floor (44px at the default 16px root
|
||||
font — WCAG 2.5.5's minimum), not a visual choice — it's the same on
|
||||
every control in the kit whether or not it's ever used on a touch
|
||||
device, since the alternative is a component that behaves differently
|
||||
per input method. Colours are the shared base16-derived vars
|
||||
(../../theme.css), never literal. */
|
||||
.ui-form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3em;
|
||||
}
|
||||
.ui-form-field-label {
|
||||
font-size: 0.85em;
|
||||
color: var(--muted);
|
||||
}
|
||||
.ui-form-control {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--purple-dim);
|
||||
border-radius: 0.3em;
|
||||
padding: 0.4em 0.6em;
|
||||
font: inherit;
|
||||
width: 100%;
|
||||
max-width: 16em;
|
||||
box-sizing: border-box;
|
||||
min-height: 2.75em;
|
||||
}
|
||||
27
frontend/packages/swarm-ui/src/ui/form-field/FormField.tsx
Normal file
27
frontend/packages/swarm-ui/src/ui/form-field/FormField.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// <FormField> — label + control wrapper shared by every labelled form
|
||||
// control (`TextField`, `SelectField`, …). Not exported as a standalone
|
||||
// primitive callers reach for directly — it only exists so those two
|
||||
// don't each reinvent the label/spacing chrome; a bare labelled `<div>`
|
||||
// wrapper has no independent identity worth a `/components` entry of
|
||||
// its own.
|
||||
import type { ComponentChildren } from 'preact';
|
||||
import './FormField.css';
|
||||
|
||||
export function FormField({
|
||||
label,
|
||||
htmlFor,
|
||||
children,
|
||||
}: {
|
||||
label: string;
|
||||
htmlFor: string;
|
||||
children: ComponentChildren;
|
||||
}) {
|
||||
return (
|
||||
<div class="ui-form-field">
|
||||
<label class="ui-form-field-label" for={htmlFor}>
|
||||
{label}
|
||||
</label>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue