solid-suggest
Version:
Headless search suggestion dropdown UI library for SolidJS
1 lines • 9.71 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/index.tsx"],"sourcesContent":["import { createMemo, createSignal, createEffect, JSX } from 'solid-js'\n\nexport interface SuggestProps<T> {\n onQuery: (query: string) => T[] | Promise<T[]>, // Can return array or Promise\n onSelect: (suggestion: T) => void,\n renderSuggestion: (suggestion: T) => HTMLElement | JSX.Element,\n placeholder?: string,\n reverseKeyInput?: boolean,\n debounceMs?: number, // Debounce period in milliseconds\n}\n\nexport default function Suggest<T = string>(props: SuggestProps<T>) {\n // Suggestions to be rendered\n const [suggestions, setSuggestions] = createSignal<T[]>([]);\n const numSuggestions = createMemo(() => suggestions().length);\n\n // Basic signals for component state\n const [query, setQuery] = createSignal('');\n const [staged, setStaged] = createSignal<number | null>(null);\n // Internal signal for user input, separate from query to handle optional debounce\n const [debouncedQuery, setDebouncedQuery] = createSignal('');\n\n // Just a variable to store debounce timeout, if applicable\n let debounceTimeout: ReturnType<typeof setTimeout> | null = null;\n\n // Effect to update suggestions when debouncedQuery changes\n createEffect(() => {\n const result = props.onQuery(debouncedQuery());\n if (result instanceof Promise) {\n result.then(setSuggestions);\n } else {\n setSuggestions(result);\n }\n });\n\n function handleInput(e: Event) {\n const value = (e.currentTarget as HTMLInputElement).value;\n setQuery(value);\n if (typeof props.debounceMs === 'number' && props.debounceMs > 0) {\n if (debounceTimeout) clearTimeout(debounceTimeout);\n debounceTimeout = setTimeout(() => {\n setDebouncedQuery(value);\n }, props.debounceMs);\n } else {\n setDebouncedQuery(value);\n }\n }\n\n function stageSuggestion(index: number) {\n setStaged(index);\n }\n\n function stageNextSuggestion() {\n setStaged(s => {\n if (suggestions().length === 0) return null;\n const current = s ?? -1;\n return (current + 1) % numSuggestions();\n });\n };\n\n function stagePrevSuggestion() {\n setStaged(s => {\n if (numSuggestions() === 0) return null;\n const current = s ?? 0;\n return (current - 1 + numSuggestions()) % numSuggestions();\n });\n };\n\n function selectStagedSuggestion() {\n const index = staged()\n if (index !== null) {\n props.onSelect(suggestions()[index]);\n reset();\n }\n }\n\n function reset() {\n setQuery('');\n setDebouncedQuery('');\n setStaged(null);\n if (debounceTimeout) clearTimeout(debounceTimeout);\n }\n\n // Handles special input for suggestion behavior\n function handleKeyDown(e: KeyboardEvent) {\n const keyInputReversed = props.reverseKeyInput ?? false;\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (keyInputReversed) {\n stagePrevSuggestion();\n } else {\n stageNextSuggestion();\n }\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n if (keyInputReversed) {\n stageNextSuggestion();\n } else {\n stagePrevSuggestion();\n }\n } else if (e.key === 'Enter') {\n e.preventDefault();\n selectStagedSuggestion();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n reset();\n }\n // else -> propagates up to allow input\n }\n\n return <div\n class='s-sug-container'\n role='combobox'\n aria-expanded={numSuggestions() > 0}\n aria-haspopup='listbox'\n >\n <input\n type='search'\n class='s-sug-search'\n value={query()}\n placeholder={props.placeholder ?? ''}\n on:input={handleInput}\n on:keydown={handleKeyDown}\n aria-autocomplete='list'\n />\n {numSuggestions() > 0 &&\n <ul class='s-sug-suggestions' role='listbox'>\n {suggestions().map((s, i) => (\n <li\n class='s-sug-suggestion'\n data-staged={staged() === i}\n role='option'\n on:mouseenter={() => stageSuggestion(i)}\n on:click={selectStagedSuggestion}\n aria-selected={staged() === i ? 'true' : 'false'}\n >\n {props.renderSuggestion(s)}\n </li>)\n )}\n </ul>\n }\n </div>\n}\n"],"names":["Suggest","props","suggestions","setSuggestions","createSignal","numSuggestions","createMemo","length","query","setQuery","staged","setStaged","debouncedQuery","setDebouncedQuery","debounceTimeout","createEffect","result","onQuery","Promise","then","handleInput","e","value","currentTarget","debounceMs","clearTimeout","setTimeout","stageSuggestion","index","stageNextSuggestion","s","current","stagePrevSuggestion","selectStagedSuggestion","onSelect","reset","handleKeyDown","keyInputReversed","reverseKeyInput","key","preventDefault","_el$","_tmpl$","_el$2","firstChild","_$addEventListener","_$insert","_c$","_$memo","_el$3","_tmpl$2","map","i","_el$4","_tmpl$3","renderSuggestion","_$effect","_p$","_v$3","_v$4","_$setAttribute","t","undefined","_v$","_v$2","placeholder"],"mappings":"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"}