`commitPick()` set `value`, closed the popover, then refocused the
input — but the `onfocusin` on `<Popover.Anchor>` reopened it. Guard
the anchor's open handler with a `justCommitted` flag cleared on the
next microtask so the refocus that follows a pick is ignored.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Demo `/uix/components/search-field` wraps the SearchField in
`<Popover.Anchor>`; results render in `<Popover.Content>` (intrinsic
width, align="start") wrapped in `<PickerShell.Body>` so the panel
inherits the canonical picker chrome. Items are real `<button>`s with
`onclick` — committing a selection sets `value`, closes the popover,
and restores focus to the input.
- Forward `bind:ref` through the eidos `<SearchField.Input>` wrapper so
consumers can refocus the input from the demo's pick handler.
- Hide the browser's native `::-webkit-search-cancel-button` /
`::-webkit-search-decoration` / `::-ms-clear` so only the canonical
`<SearchField.ClearTrigger>` X is visible.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The demo only had the SearchField input by itself with a trace strip;
nothing actually demonstrated the search outcome. Added a 34-item
dataset of UIX components (name + group) and a live results grid that
filters by name or group substring as the user types.
- Empty input renders 34/34 results.
- Typing "form" filters to 17 components from the Forms group.
- "drawer" filters to 1 (Drawer).
- Empty results state renders a graceful "No matches for ..." message.
- Counter shows `results N / total` so the demo doubles as a quick
feedback loop for the debounceMs control (count + meta animate
together when the debounced onValueChange finally fires).
CSS lives inline in the demo (`.search-field-results*` selectors) since
this is demo content rather than reusable component visuals.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three components closing the 6-component audit batch.
number-field
- N1 RTL scrubber: invert horizontal delta sign when dir='rtl' so
dragging right decrements (visually backward) in RTL layouts. Vertical
unaffected. Added 2 RTL scrub tests; existing scrub test pinned to ltr.
- N2 stepper height: Increment/Decrement now use --_number-field-height
for inline-size/block-size/min-inline-size so they always match the
input row at every size token (xs/sm/md/lg/xl).
- N3 input focus ring: explicit [data-number-field-input]:focus-visible
with --_number-field-accent-border box-shadow, alongside the existing
Provider-level ring.
search-field
- S1 icon tokens: added --search-field-icon-size-{xs..xl} + icon-color +
icon-margin-inline-end + a Morfo Icon part + soma/eidos wrappers.
Demo uses <SearchField.Icon><Search /></SearchField.Icon>.
- S2 debounceMs prop: soma wraps onValueChange in a timers.schedule with
the provided delay. clear() cancels, submit() flushes synchronously.
- S3 loading slot: new LoadingIndicator part (morfo + soma + eidos) +
data-loading on Provider + CSS spinner via @keyframes search-field-spin
honoring prefers-reduced-motion.
combobox
- C1 ClearButton part: new morfo trigger + soma provider + eidos wrapper
with X icon. Hidden via [data-empty] (opacity + pointer-events:none).
Click clears value + inputValue and refocuses input.
- C2 allowsCustomValue: when true and no highlighted item, Enter commits
the current inputValue as the value. Single mode closes after commit;
multi appends + clears input + stays open.
- C4 Backspace removes last tag in multi mode when input is empty.
- C5 Sticky group headers: CSS position:sticky with content-overlay bg.
Plus: fixed search-field demo's brittle parts[1] index reference to a
named lookup (parts.find(p => p.kebab === 'input')).
Verified: svelte-check --threshold error → 0 errors / 0 warnings /
4584 files. All component tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The clear affordance is the standard search-input pattern: an X glyph
inside the input, with the localized "Clear" / "Borrar" string moved
to `aria-label`. Showing the word "Borrar" inline and then a hover
button on top read as two redundant affordances.
Replaced the visible text with `<X size="1em" decorative />` from the
icon set. The aria-label still pulls from
`'#?components.search-field.clear|Clear'` so screen readers get the
localized affordance name.
Code snippets in the API panel updated to match the new pattern
(`<SearchField.ClearTrigger aria-label="Clear"><X ... /></...>`)
instead of the text-only variant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The demo hardcoded the visible Clear button label inline:
<SearchField.ClearTrigger>Clear</SearchField.ClearTrigger>
So the toolbar's locale toggle (ES/EN) only swapped the aria-label
via the morfo's translationRef, not the visible text. With locale=ES
the panel showed a Spanish UI everywhere except the literal "Clear".
Replace with `uix.langs.ts('#?components.search-field.clear|Clear')`
so the visible button picks up the active catalog entry. Catalog
strings shortened to just `Borrar` / `Clear` (one-word action label
that fits the inline-button affordance — the previous "Borrar
búsqueda" was too long for the visible chrome and wrapped in two
lines). The full phrase still reads naturally for aria-label.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>