solid-suggest 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # solid-suggest
2
2
 
3
+ [![NPM](https://nodei.co/npm/solid-suggest.png)](https://npmjs.org/package/solid-suggest)
4
+
3
5
  solid-suggest is a UI component for SolidJS developers that renders a text input with dropdown suggestions. It can be used in scenarios such as search suggestions or results triggered by text input.
4
6
 
5
7
  It's a *super* simple library without many batteries included. See following sections for what it can and can't do for you.
package/dist/index.cjs CHANGED
@@ -7,6 +7,9 @@ var _tmpl$ = /*#__PURE__*/web.template(`<div class=s-sug-container role=combobox
7
7
  _tmpl$2 = /*#__PURE__*/web.template(`<ul class=s-sug-suggestions role=listbox>`),
8
8
  _tmpl$3 = /*#__PURE__*/web.template(`<li class=s-sug-suggestion role=option>`);
9
9
  function Suggest(props) {
10
+ // Suggestions to be rendered
11
+ const [suggestions, setSuggestions] = solidJs.createSignal([]);
12
+ const numSuggestions = solidJs.createMemo(() => suggestions().length);
10
13
  // Basic signals for component state
11
14
  const [query, setQuery] = solidJs.createSignal('');
12
15
  const [staged, setStaged] = solidJs.createSignal(null);
@@ -14,8 +17,15 @@ function Suggest(props) {
14
17
  const [debouncedQuery, setDebouncedQuery] = solidJs.createSignal('');
15
18
  // Just a variable to store debounce timeout, if applicable
16
19
  let debounceTimeout = null;
17
- const suggestions = solidJs.createMemo(() => props.onQuery(debouncedQuery()));
18
- const numSuggestions = solidJs.createMemo(() => suggestions().length);
20
+ // Effect to update suggestions when debouncedQuery changes
21
+ solidJs.createEffect(() => {
22
+ const result = props.onQuery(debouncedQuery());
23
+ if (result instanceof Promise) {
24
+ result.then(setSuggestions);
25
+ } else {
26
+ setSuggestions(result);
27
+ }
28
+ });
19
29
  function handleInput(e) {
20
30
  const value = e.currentTarget.value;
21
31
  setQuery(value);
@@ -99,10 +109,10 @@ function Suggest(props) {
99
109
  web.addEventListener(_el$4, "mouseenter", () => stageSuggestion(i));
100
110
  web.insert(_el$4, () => props.renderSuggestion(s));
101
111
  web.effect(_p$ => {
102
- var _v$ = staged() === i,
103
- _v$2 = staged() === i ? 'true' : 'false';
104
- _v$ !== _p$.e && web.setAttribute(_el$4, "data-staged", _p$.e = _v$);
105
- _v$2 !== _p$.t && web.setAttribute(_el$4, "aria-selected", _p$.t = _v$2);
112
+ var _v$3 = staged() === i,
113
+ _v$4 = staged() === i ? 'true' : 'false';
114
+ _v$3 !== _p$.e && web.setAttribute(_el$4, "data-staged", _p$.e = _v$3);
115
+ _v$4 !== _p$.t && web.setAttribute(_el$4, "aria-selected", _p$.t = _v$4);
106
116
  return _p$;
107
117
  }, {
108
118
  e: undefined,
@@ -113,7 +123,16 @@ function Suggest(props) {
113
123
  return _el$3;
114
124
  })();
115
125
  })(), null);
116
- web.effect(() => web.setAttribute(_el$, "aria-expanded", numSuggestions() > 0));
126
+ web.effect(_p$ => {
127
+ var _v$ = numSuggestions() > 0,
128
+ _v$2 = props.placeholder ?? '';
129
+ _v$ !== _p$.e && web.setAttribute(_el$, "aria-expanded", _p$.e = _v$);
130
+ _v$2 !== _p$.t && web.setAttribute(_el$2, "placeholder", _p$.t = _v$2);
131
+ return _p$;
132
+ }, {
133
+ e: undefined,
134
+ t: undefined
135
+ });
117
136
  web.effect(() => _el$2.value = query());
118
137
  return _el$;
119
138
  })();
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/index.tsx"],"sourcesContent":["import { createMemo, createSignal } from 'solid-js'\n\nexport interface SuggestProps<T = string> {\n onQuery: (query: string) => T[], // Suggestions assumed ordered by client\n onSelect: (suggestion: T) => void,\n renderSuggestion: (suggestion: T) => HTMLElement,\n reverseKeyInput?: boolean,\n debounceMs?: number, // Debounce period in milliseconds\n}\n\nexport default function Suggest(props: SuggestProps) {\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 const suggestions = createMemo(() => props.onQuery(debouncedQuery()));\n const numSuggestions = createMemo(() => suggestions().length);\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 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","query","setQuery","createSignal","staged","setStaged","debouncedQuery","setDebouncedQuery","debounceTimeout","suggestions","createMemo","onQuery","numSuggestions","length","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$","_v$2","_$setAttribute","t","undefined"],"mappings":"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"}
1
+ {"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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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- export interface SuggestProps<T = string> {
2
- onQuery: (query: string) => T[];
1
+ import { JSX } from 'solid-js';
2
+ export interface SuggestProps<T> {
3
+ onQuery: (query: string) => T[] | Promise<T[]>;
3
4
  onSelect: (suggestion: T) => void;
4
- renderSuggestion: (suggestion: T) => HTMLElement;
5
+ renderSuggestion: (suggestion: T) => HTMLElement | JSX.Element;
6
+ placeholder?: string;
5
7
  reverseKeyInput?: boolean;
6
8
  debounceMs?: number;
7
9
  }
8
- export default function Suggest(props: SuggestProps): import("solid-js").JSX.Element;
10
+ export default function Suggest<T = string>(props: SuggestProps<T>): JSX.Element;
package/dist/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import { template, addEventListener, insert, memo, effect, setAttribute } from 'solid-js/web';
2
- import { createSignal, createMemo } from 'solid-js';
2
+ import { createSignal, createMemo, createEffect } from 'solid-js';
3
3
 
4
4
  var _tmpl$ = /*#__PURE__*/template(`<div class=s-sug-container role=combobox aria-haspopup=listbox><input type=search class=s-sug-search aria-autocomplete=list>`),
5
5
  _tmpl$2 = /*#__PURE__*/template(`<ul class=s-sug-suggestions role=listbox>`),
6
6
  _tmpl$3 = /*#__PURE__*/template(`<li class=s-sug-suggestion role=option>`);
7
7
  function Suggest(props) {
8
+ // Suggestions to be rendered
9
+ const [suggestions, setSuggestions] = createSignal([]);
10
+ const numSuggestions = createMemo(() => suggestions().length);
8
11
  // Basic signals for component state
9
12
  const [query, setQuery] = createSignal('');
10
13
  const [staged, setStaged] = createSignal(null);
@@ -12,8 +15,15 @@ function Suggest(props) {
12
15
  const [debouncedQuery, setDebouncedQuery] = createSignal('');
13
16
  // Just a variable to store debounce timeout, if applicable
14
17
  let debounceTimeout = null;
15
- const suggestions = createMemo(() => props.onQuery(debouncedQuery()));
16
- const numSuggestions = createMemo(() => suggestions().length);
18
+ // Effect to update suggestions when debouncedQuery changes
19
+ createEffect(() => {
20
+ const result = props.onQuery(debouncedQuery());
21
+ if (result instanceof Promise) {
22
+ result.then(setSuggestions);
23
+ } else {
24
+ setSuggestions(result);
25
+ }
26
+ });
17
27
  function handleInput(e) {
18
28
  const value = e.currentTarget.value;
19
29
  setQuery(value);
@@ -97,10 +107,10 @@ function Suggest(props) {
97
107
  addEventListener(_el$4, "mouseenter", () => stageSuggestion(i));
98
108
  insert(_el$4, () => props.renderSuggestion(s));
99
109
  effect(_p$ => {
100
- var _v$ = staged() === i,
101
- _v$2 = staged() === i ? 'true' : 'false';
102
- _v$ !== _p$.e && setAttribute(_el$4, "data-staged", _p$.e = _v$);
103
- _v$2 !== _p$.t && setAttribute(_el$4, "aria-selected", _p$.t = _v$2);
110
+ var _v$3 = staged() === i,
111
+ _v$4 = staged() === i ? 'true' : 'false';
112
+ _v$3 !== _p$.e && setAttribute(_el$4, "data-staged", _p$.e = _v$3);
113
+ _v$4 !== _p$.t && setAttribute(_el$4, "aria-selected", _p$.t = _v$4);
104
114
  return _p$;
105
115
  }, {
106
116
  e: undefined,
@@ -111,7 +121,16 @@ function Suggest(props) {
111
121
  return _el$3;
112
122
  })();
113
123
  })(), null);
114
- effect(() => setAttribute(_el$, "aria-expanded", numSuggestions() > 0));
124
+ effect(_p$ => {
125
+ var _v$ = numSuggestions() > 0,
126
+ _v$2 = props.placeholder ?? '';
127
+ _v$ !== _p$.e && setAttribute(_el$, "aria-expanded", _p$.e = _v$);
128
+ _v$2 !== _p$.t && setAttribute(_el$2, "placeholder", _p$.t = _v$2);
129
+ return _p$;
130
+ }, {
131
+ e: undefined,
132
+ t: undefined
133
+ });
115
134
  effect(() => _el$2.value = query());
116
135
  return _el$;
117
136
  })();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import { createMemo, createSignal } from 'solid-js'\n\nexport interface SuggestProps<T = string> {\n onQuery: (query: string) => T[], // Suggestions assumed ordered by client\n onSelect: (suggestion: T) => void,\n renderSuggestion: (suggestion: T) => HTMLElement,\n reverseKeyInput?: boolean,\n debounceMs?: number, // Debounce period in milliseconds\n}\n\nexport default function Suggest(props: SuggestProps) {\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 const suggestions = createMemo(() => props.onQuery(debouncedQuery()));\n const numSuggestions = createMemo(() => suggestions().length);\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 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","query","setQuery","createSignal","staged","setStaged","debouncedQuery","setDebouncedQuery","debounceTimeout","suggestions","createMemo","onQuery","numSuggestions","length","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$","_v$2","_$setAttribute","t","undefined"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solid-suggest",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Headless search suggestion dropdown UI library for SolidJS",
5
5
  "homepage": "https://antrikshy.com/solid-suggest",
6
6
  "repository": {