this repo has no description
1import './TextInput.css';
2
3import { createSignal, For, Show } from "solid-js"
4
5export interface TextInputProps{
6 placeholder: string,
7 value?: string,
8 requestSuggestions?: ( text: string ) => Promise<string[]>,
9 change?: ( text: string ) => void
10}
11
12export let TextInput = ( props: TextInputProps ) => {
13 let [ suggestionsOpen, setSuggestionsOpen ] = createSignal(false);
14 let [ suggestions, setSuggestions ] = createSignal<string[]>([])
15
16 let input!: HTMLInputElement;
17
18 let suggestionsContainer!: HTMLDivElement;
19 let suggestionsIndex = 0;
20
21 let onInput = async () => {
22 let s = null;
23
24 if(props.requestSuggestions){
25 s = await props.requestSuggestions(input.value);
26
27 if(s != suggestions()){
28 setSuggestions(s);
29
30 let open = s !== null && s.length > 0 && input.value.length > 0;
31
32 setSuggestionsOpen(open);
33 if(open)changeSelection(() => { suggestionsIndex = 0; });
34 }
35 }
36 }
37
38 let onKeyDown = ( ev: KeyboardEvent ) => {
39 switch(ev.key){
40 case 'ArrowDown':
41 changeSelection(() => {
42 suggestionsIndex++;
43 if(suggestionsIndex >= suggestionsContainer.children.length)suggestionsIndex = suggestionsContainer.children.length - 1;
44 });
45 break;
46 case 'ArrowUp':
47 changeSelection(() => {
48 suggestionsIndex--;
49 if(suggestionsIndex < 0)suggestionsIndex = 0;
50 });
51 break;
52 case 'Enter':
53 let currentDiv = suggestionsContainer.children[suggestionsIndex];
54 if(currentDiv)input.value = currentDiv.innerHTML;
55
56 props.change ? props.change(input.value) : null
57 setSuggestionsOpen(false);
58 break;
59 }
60 }
61
62 let changeSelection = ( cb: () => void ) => {
63 for(let child of suggestionsContainer.children)
64 child.classList.remove('suggestion-selected');
65
66 cb();
67
68 let height = suggestionsIndex * 19;
69 suggestionsContainer.scrollTo(0, height - 150);
70
71 let currentDiv = suggestionsContainer.children[suggestionsIndex];
72 if(currentDiv)currentDiv.classList.add('suggestion-selected');
73 }
74
75 return (
76 <>
77 <div style={{ width: '100%' }}>
78 <input
79 style={{ width: '100%' }}
80 type="text"
81 placeholder={ props.placeholder }
82 value={ props.value || "" }
83 onChange={() => props.change ? props.change(input.value) : null}
84 onInput={onInput}
85 onKeyDown={onKeyDown}
86 onFocusOut={() => setTimeout(() => {
87 setSuggestionsOpen(false);
88 suggestionsIndex = -1;
89 }, 100)}
90 ref={input} />
91
92 <Show when={suggestionsOpen()}>
93 <div input-dropdown ref={suggestionsContainer}>
94 <For each={suggestions()}>
95 { item => <div onClick={( el ) => {
96 let thisEl = el.target;
97
98 input.value = thisEl.innerHTML;
99 setSuggestionsOpen(false);
100
101 props.change ? props.change(input.value) : null
102 suggestionsIndex = -1;
103 }}>{ item }</div> }
104 </For>
105 </div>
106 </Show>
107 </div>
108 </>
109 )
110}