docs(search-field demo): add live filterable results panel

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>
active-uix
dev 5 months ago
parent 9fbf8e48b5
commit 8aa6086976

@ -38,6 +38,53 @@
const partsList = $derived([...compiled.parts.byKebab.values()]);
const events = $derived([...compiled.actions.byName.values()]);
const isEmpty = $derived(value.length === 0);
// Demo dataset for the live search panel.
const components: { name: string; group: string }[] = [
{ name: 'Accordion', group: 'Disclosure' },
{ name: 'Avatar', group: 'Media' },
{ name: 'Breadcrumb', group: 'Navigation' },
{ name: 'Button', group: 'Action' },
{ name: 'Calendar', group: 'Forms' },
{ name: 'Checkbox', group: 'Forms' },
{ name: 'Collapsible', group: 'Disclosure' },
{ name: 'Color picker', group: 'Forms' },
{ name: 'Combobox', group: 'Forms' },
{ name: 'Date picker', group: 'Forms' },
{ name: 'Dialog', group: 'Overlay' },
{ name: 'Drawer', group: 'Overlay' },
{ name: 'Editable', group: 'Forms' },
{ name: 'Field', group: 'Forms' },
{ name: 'File upload', group: 'Forms' },
{ name: 'Icon', group: 'Media' },
{ name: 'Meter', group: 'Status' },
{ name: 'Number field', group: 'Forms' },
{ name: 'Pagination', group: 'Navigation' },
{ name: 'Popover', group: 'Overlay' },
{ name: 'Progress', group: 'Status' },
{ name: 'Radio group', group: 'Forms' },
{ name: 'Rating group', group: 'Forms' },
{ name: 'Search field', group: 'Forms' },
{ name: 'Select', group: 'Forms' },
{ name: 'Slider', group: 'Forms' },
{ name: 'Switch', group: 'Forms' },
{ name: 'Tabs', group: 'Disclosure' },
{ name: 'Tag group', group: 'Forms' },
{ name: 'Time picker', group: 'Forms' },
{ name: 'Toast', group: 'Overlay' },
{ name: 'Toggle', group: 'Action' },
{ name: 'Toolbar', group: 'Action' },
{ name: 'Tooltip', group: 'Overlay' }
];
// Filter matches name OR group, case-insensitive.
const results = $derived.by(() => {
const q = value.trim().toLowerCase();
if (!q) return components;
return components.filter(
(c) => c.name.toLowerCase().includes(q) || c.group.toLowerCase().includes(q)
);
});
const variants: SearchFieldVariant[] = ['surface', 'outline', 'ghost'];
const colors: SearchFieldColor[] = [
'primary',
@ -170,6 +217,31 @@
<X size="1em" decorative />
</SearchField.ClearTrigger>
</SearchField>
<!-- Live result panel — filters the demo dataset by name/group. -->
<ul
class="search-field-results"
role="listbox"
aria-label="Filtered components"
aria-live="polite"
>
{#if results.length === 0}
<li class="search-field-results-empty">
No matches for <strong>"{value}"</strong>
</li>
{:else}
{#each results as item (item.name)}
<li class="search-field-result" role="option" aria-selected="false">
<span class="search-field-result-name">{item.name}</span>
<span class="search-field-result-group">{item.group}</span>
</li>
{/each}
{/if}
</ul>
<div class="search-field-results-meta">
<span data-uix-stage-trace-key>results</span>
{results.length} / {components.length}
</div>
</div>
</div>
<div data-uix-stage-trace>
@ -561,3 +633,51 @@
</section>
{/if}
</div>
<style>
.search-field-results {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
gap: var(--uix-space-1);
margin-block-start: var(--uix-space-3);
padding: 0;
list-style: none;
max-block-size: 14rem;
overflow-y: auto;
}
.search-field-result {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--uix-space-2);
padding: var(--uix-space-1-5) var(--uix-space-2);
border: 1px solid var(--color-border-subtle);
border-radius: var(--radius-md);
background: var(--color-surface-default);
font-size: var(--uix-text-sm);
}
.search-field-result-name {
color: var(--color-content-primary);
font-weight: 500;
}
.search-field-result-group {
color: var(--color-content-muted);
font-size: var(--uix-text-xs);
}
.search-field-results-empty {
grid-column: 1 / -1;
padding: var(--uix-space-3);
color: var(--color-content-muted);
text-align: center;
font-size: var(--uix-text-sm);
}
.search-field-results-meta {
display: flex;
align-items: center;
gap: var(--uix-space-2);
margin-block-start: var(--uix-space-2);
color: var(--uix-text-muted);
font-family: var(--uix-font-mono);
font-size: var(--uix-text-xs);
}
</style>

Loading…
Cancel
Save

Powered by TurnKey Linux.