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
|
|
@ -16,16 +16,17 @@
|
|||
// one path segment deep — a real bug, filed separately rather than
|
||||
// fixed here, but reason enough to avoid a nested route today.
|
||||
//
|
||||
// First real form in this package — no shared form kit exists yet, so
|
||||
// the input/button styling below is scoped to `CreateAgentPage.css`
|
||||
// rather than promoted into `ui/`. Promote the day a second page needs
|
||||
// one, same "don't build ahead of a second caller" rule `Panel`'s own
|
||||
// comment states.
|
||||
// First real form in this package — its name field + submit button now
|
||||
// come from the shared `ui/` form kit (`TextField`/`Button`) rather than
|
||||
// page-scoped input/button chrome, so a hive-picker soon landing on this
|
||||
// same page has something to reuse instead of copying this page's CSS.
|
||||
import { useState } from 'preact/hooks';
|
||||
import { Link } from 'wouter-preact';
|
||||
import { ApiErrorPanel } from '@hive/shared/api-error-panel.js';
|
||||
import { readApiError, type ProblemDetails } from '@hive/shared/api-error.js';
|
||||
import { Panel } from '../ui/panel/Panel.js';
|
||||
import { TextField } from '../ui/text-field/TextField.js';
|
||||
import { Button } from '../ui/button/Button.js';
|
||||
import './CreateAgentPage.css';
|
||||
|
||||
interface CreateAgentResponse {
|
||||
|
|
@ -85,24 +86,18 @@ export function CreateAgentPage() {
|
|||
<Link href="/jobs">jobs</Link> to watch it settle.
|
||||
</p>
|
||||
<form class="create-agent-form" onSubmit={submit}>
|
||||
<div class="create-agent-field">
|
||||
<label class="create-agent-label" for="agent-name">
|
||||
agent name
|
||||
</label>
|
||||
<input
|
||||
id="agent-name"
|
||||
class="create-agent-input"
|
||||
type="text"
|
||||
value={name}
|
||||
pattern={NAME_PATTERN}
|
||||
title="1-63 chars: lowercase letters, digits, hyphens"
|
||||
required
|
||||
onInput={(e) => setName(e.currentTarget.value)}
|
||||
/>
|
||||
</div>
|
||||
<button class="create-agent-submit" type="submit" disabled={result.status === 'submitting'}>
|
||||
<TextField
|
||||
id="agent-name"
|
||||
label="agent name"
|
||||
value={name}
|
||||
pattern={NAME_PATTERN}
|
||||
title="1-63 chars: lowercase letters, digits, hyphens"
|
||||
required
|
||||
onInput={setName}
|
||||
/>
|
||||
<Button variant="primary" type="submit" disabled={result.status === 'submitting'}>
|
||||
{result.status === 'submitting' ? 'creating…' : 'create'}
|
||||
</button>
|
||||
</Button>
|
||||
</form>
|
||||
{result.status === 'done' && (
|
||||
<p class="create-agent-result create-agent-result-ok">
|
||||
|
|
|
|||
Loading…
Reference in a new issue