feat(design): the field family, the dropdown trigger, native controls, the no-raw-input lint rule (E28 S3c)
- ui/Input, Textarea, InnerInput + fieldClass (A4): the >= 3:1 edge, a 2px accent focus edge, the danger edge for invalid, md/sm/xs/heading rungs, 1rem and 44 on touch - ui/SelectTrigger (A5): SortControl, FilterSelect, the view switcher and the date filter on one trigger, a pill in a toolbar, r8 in a form - ui/NativeControls (A6): Checkbox, CheckRow, Slider, ColorInput - every raw input swept (~100 sites); inputCls retired; local/input-primitive - useReturnFocus: an in-place editor hands the focus back to its trigger on Enter/Escape (the playlist and Plex title renames, the priority number); the Plex playlist rename gains Escape and an accessible name - back to top: a round 48 FAB (owner decision); DESIGN.md A2 and the log
This commit is contained in:
@@ -25,7 +25,8 @@ import { IconButton } from "./ui/IconButton";
|
||||
import Modal from "./ui/Modal";
|
||||
import { LoadingState, StateMessage } from "./ui/QueryState";
|
||||
import SegmentedToggle from "./ui/SegmentedToggle";
|
||||
import { inputCls } from "./ui/form";
|
||||
import { Textarea, Input } from "./ui/Input";
|
||||
import { Checkbox } from "./ui/NativeControls";
|
||||
|
||||
// The issue composer (E16 S3, D4 A): one dialog — the draft on the left (title, description, the
|
||||
// steps drafted from the session, the environment), what goes with it on the right (the two logs,
|
||||
@@ -472,28 +473,28 @@ function DraftFields({
|
||||
<label htmlFor="issue-title" className="text-sm text-muted">
|
||||
{t("recorder.composer.fieldTitle")}
|
||||
</label>
|
||||
<input
|
||||
<Input
|
||||
className="w-full"
|
||||
id="issue-title"
|
||||
value={form.title}
|
||||
readOnly={readOnly}
|
||||
maxLength={200}
|
||||
placeholder={t("recorder.composer.titlePlaceholder")}
|
||||
onChange={(e) => edit((f) => ({ ...f, title: e.target.value }))}
|
||||
className={inputCls}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<label htmlFor="issue-description" className="text-sm text-muted">
|
||||
{t("recorder.composer.description")}
|
||||
</label>
|
||||
<textarea
|
||||
<Textarea
|
||||
className="w-full resize-y"
|
||||
id="issue-description"
|
||||
value={form.description}
|
||||
readOnly={readOnly}
|
||||
rows={4}
|
||||
placeholder={t("recorder.composer.descriptionPlaceholder")}
|
||||
onChange={(e) => edit((f) => ({ ...f, description: e.target.value }))}
|
||||
className={`${inputCls} resize-y`}
|
||||
/>
|
||||
</div>
|
||||
<fieldset className="flex flex-col gap-1.5 min-w-0">
|
||||
@@ -507,13 +508,14 @@ function DraftFields({
|
||||
<span className="w-6 shrink-0 text-sm font-semibold text-accent tabular-nums">
|
||||
{i + 1}.
|
||||
</span>
|
||||
<input
|
||||
<Input
|
||||
className="flex-1"
|
||||
size="sm"
|
||||
aria-label={t("recorder.composer.stepLabel", { n: i + 1 })}
|
||||
value={step.text}
|
||||
readOnly={readOnly}
|
||||
placeholder={t("recorder.composer.stepPlaceholder")}
|
||||
onChange={(e) => setStep(i, { text: e.target.value })}
|
||||
className="min-w-0 flex-1 bg-transparent text-sm outline-none focus-visible:ring-2 focus-visible:ring-accent/60 rounded px-1 py-1"
|
||||
/>
|
||||
<span className="chip shrink-0 px-2 py-0.5 text-2xs">
|
||||
{t(`recorder.composer.stepKind.${step.kind}`)}
|
||||
@@ -764,8 +766,7 @@ function ReviewList({
|
||||
off ? "opacity-50 line-through" : ""
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
<Checkbox
|
||||
checked={!off}
|
||||
disabled={readOnly}
|
||||
aria-label={t("recorder.composer.keepRow", {
|
||||
|
||||
Reference in New Issue
Block a user