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:
@@ -1,9 +1,12 @@
|
||||
import clsx from "clsx";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Check, ChevronDown, X } from "lucide-react";
|
||||
import { PopoverSurface, PopoverItem } from "./AnchoredPopover";
|
||||
import { useAnchoredPopover } from "./anchoredPopoverHooks";
|
||||
import { useScrollFade } from "../../lib/useScrollFade";
|
||||
import { InnerInput } from "./Input";
|
||||
import { fieldClass } from "./fieldStyles";
|
||||
|
||||
// The universal combobox: a react-select / Overseerr-style "combi input" — selected values are
|
||||
// removable chips that live INSIDE a text field you type into, and a checklist of options opens below.
|
||||
@@ -176,7 +179,10 @@ export default function Combobox({
|
||||
setOpenAnd(true);
|
||||
}
|
||||
}}
|
||||
className="glass-card flex min-h-9 w-full cursor-text flex-wrap items-center gap-1 rounded-lg border border-border px-1.5 py-1 transition focus-within:border-accent focus-within:ring-2 focus-within:ring-accent/30"
|
||||
className={clsx(
|
||||
fieldClass({ size: "free" }),
|
||||
"flex min-h-8 w-full cursor-text flex-wrap items-center gap-1 px-1.5 py-0.5 text-sm",
|
||||
)}
|
||||
>
|
||||
{selected.map((v) => (
|
||||
<span key={v} className="chip inline-flex items-center gap-1 px-2 py-0.5 text-sm">
|
||||
@@ -196,7 +202,8 @@ export default function Combobox({
|
||||
</button>
|
||||
</span>
|
||||
))}
|
||||
<input
|
||||
<InnerInput
|
||||
className="min-w-8 px-1 py-0.5"
|
||||
ref={setInputRef}
|
||||
{...pop.getReferenceProps({
|
||||
onChange: (e) => {
|
||||
@@ -226,7 +233,6 @@ export default function Combobox({
|
||||
// made a single chip + the reserved input + the chevron overflow a narrow rail field — wrapping
|
||||
// the chevron to a second line while the (empty) input filled the first. A small floor keeps the
|
||||
// chip + input + chevron on one line; flex-1 still grows the input to fill whatever room is left.
|
||||
className="min-w-8 flex-1 bg-transparent px-1 py-0.5 text-sm outline-hidden placeholder:text-muted/60"
|
||||
/>
|
||||
<ChevronDown className="pointer-events-none mr-0.5 h-3.5 w-3.5 shrink-0 text-muted" />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user