v0.9.0
A search UI release. The copy-paste templates behind searchsocket add are now a
polished, themeable command palette that needs no CSS framework.
Existing integrations are unaffected. Components you have already copied are
never modified, and createSearch() keeps its published interface, defaults and
request payload. Only what searchsocket add generates from now on has changed.
Added
- Redesigned search UI templates.
searchsocket addnow generates a polished,
self-contained command palette instead of a minimal Tailwind sketch. Each
template directory ships the component plusSearchResultRow.svelte,
search-ui.tsandsearch-theme.css, and nothing imports back into
node_modules— the generated code is entirely yours. - No CSS framework required. Styling is plain CSS driven by semantic
--ss-search-*variables, so the default works in any SvelteKit project.
Tailwind still works if you want it; the templates simply no longer depend
on it. - Explicit theme modes. A
themeprop acceptsinherit(default, follows
the host app's.dark/[data-theme="dark"]convention),system,light
anddark, and setscolor-schemeto match. Plus adensityprop,class
andstyleforwarding, and stable.ss-search__*part classes documented as
the styling escape hatch. - Richer results. Rows now show the best matching section and a URL
breadcrumb alongside the title and snippet, so a result explains why it
matched.SearchResultscan list matching sections as their own
scroll-to-text links, and supportslistandcardsvariants. - Search options as props.
topK,scope,pathPrefix,tags,filters,
groupBy,maxSubResults,debounce,cacheandminQueryLengthare props
onSearchDialogandSearchInputrather than hard-coded internals. Changing
a scope or filter re-runs the current query without recreating the store. searchsocket add search-trigger— the visible button that opens the
dialog. A keyboard shortcut alone is not discoverable.createSearch()gainsstatus,resolvedQuery,hasSearched,clear()
andretry(), plusminQueryLengthandkeepPreviousResultsoptions. All
additive: existingquery/results/loading/error/destroy()behaviour
and defaults are unchanged, the request body is unchanged, and the cache is
still keyed on the query exactly as typed. The publishedSearchState
interface is untouched — the new members live on aSearchStoreinterface
that extends it, so code annotating or implementingSearchStatestill
compiles.onSelectErroronSearchDialogandSearchInput, so a rejectedonSelect
ornavigatesurfaces instead of becoming an unhandled rejection.
Fixed
- Template components no longer use fixed DOM ids (
ss-listbox,ss-option-0),
which collided when a page had two search inputs, or a dialog and an inline
input together. Ids are derived per instance and can be pinned withid. - The dialog now traps
Tabinside itself, restores focus to the element that
opened it, and restores the previousbodyoverflow value instead of clearing
it — a page setting its ownoverflowno longer loses it on close. - The active result is scrolled into view during arrow navigation instead of
moving out of the visible list. Enteris ignored while an IME composition is active, so committing CJK and
other composed text no longer navigates away mid-word.- Inline results are selected on
pointerdownwith the default prevented, so
the popup can no longer close before a click is processed. - The first
Escapein the inline input closes the popup while keeping the
query and focus, rather than immediately blurring. aria-expandedon the inline input now reflects popup visibility, including
the loading, empty and error popups, instead of whether results happen to exist.- Inputs have real accessible names via a visually hidden
<label>rather than
relying on the placeholder. - Results retained while the next query loads are highlighted against the query
that produced them (resolvedQuery), not the query being typed. Enterpressed on the dialog's Clear or Retry button activates that button.
Result-navigation keys were previously handled for the whole dialog, so Enter
anywhere inside it opened the active result instead.- Focus is pulled back into the dialog if something outside it takes focus; a
Tab pressed after focus escaped never reached the dialog's own handler. - The body scroll lock is reference counted, so two open dialogs no longer
unlock the page early or leaveoverflow: hiddenbehind, and an existing
!importantpriority is preserved. - Inline results are selected on
clickrather than on anypointerdown, so a
right-click no longer navigates and a touch drag can still scroll. - While the inline popup is closed,
aria-controlsandaria-activedescendant
are omitted instead of referencing elements that are not in the DOM, and the
popup no longer opens belowminQueryLengthwith nothing to show. - Live regions announce settled outcomes only. Announcing each debounced change
queued one utterance per keystroke, and the error state was read twice —
once by the status region and once by itsrole="alert"panel. searchsocket addrefuses to write through a symlink or over a directory, so
--overwritecannot follow a link out of the target directory.- Breadcrumbs use only the path of an absolute result URL, rather than turning
the scheme and host into segments. - A response that resolves after its request was aborted no longer overwrites
newer state. This is reachable only through a customfetchImplthat ignores
itsAbortSignal; with the platformfetch, an aborted request rejects and
never reached this path. Previously a superseded request could replace the
results of the query that succeeded it.
Changed
searchsocket addprints the entry component explicitly (with the$lib
alias where applicable) plus theme and customization hints, instead of
guessing from the first file written. It says so when existing files were
kept, and does not describe a template it did not write.- The template copier handles
.ts,.cssand.svgassets and nested
directories, not just top-level.sveltefiles. Existing files are still
skipped unless--overwriteis passed, per file — so adding a second
component preserves any edits made to the shared files.