Skip to content

Commit df6f4e9

Browse files
Merge pull request #548 from TheMcnafaha/remove-useVisibleTask-listbox
refactor(select-listbox): removed useVisibleTask
2 parents 16eb340 + 909454b commit df6f4e9

File tree

2 files changed

+291
-296
lines changed

2 files changed

+291
-296
lines changed

packages/kit-headless/src/components/select/select-listbox.tsx

Lines changed: 94 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
Slot,
55
useContext,
66
useSignal,
7-
useVisibleTask$,
87
} from '@builder.io/qwik';
98
import SelectContextId from './select-context-id';
109

@@ -17,120 +16,116 @@ export const SelectListBox = component$((props: SelectListBoxProps) => {
1716
const fullStrgSearchFailedSignal = useSignal(false);
1817
const context = useContext(SelectContextId);
1918

20-
useVisibleTask$(function setKeyHandler({ cleanup }) {
21-
function keyHandler(e: KeyboardEvent) {
22-
const availableOptions = context.optionsStore.filter(
23-
(option) => !(option?.getAttribute('aria-disabled') === 'true'),
24-
);
25-
const target = e.target as HTMLElement;
26-
const currentIndex = availableOptions.indexOf(target);
19+
return (
20+
<ul
21+
ref={context.listboxRef}
22+
role="listbox"
23+
tabIndex={0}
24+
hidden={!context.isListboxHiddenSig.value}
25+
style={`
26+
display: ${context.isOpenSig.value ? 'block' : 'none'};
27+
position: absolute;
28+
z-index: 1;
29+
${props.style}
30+
`}
31+
class={props.class}
32+
onKeyDown$={(e) => {
33+
console.log(e.key);
34+
console.log('do i run on server???');
2735

28-
if (
29-
e.key === 'ArrowDown' ||
30-
e.key === 'ArrowUp' ||
31-
e.key === 'Home' ||
32-
e.key === 'End' ||
33-
e.key === ' '
34-
) {
35-
e.preventDefault();
36-
}
36+
const availableOptions = context.optionsStore.filter(
37+
(option) => !(option?.getAttribute('aria-disabled') === 'true'),
38+
);
39+
const target = e.target as HTMLElement;
40+
const currentIndex = availableOptions.indexOf(target);
3741

38-
if (e.key === 'ArrowDown') {
39-
if (currentIndex === availableOptions.length - 1) {
40-
availableOptions[0]?.focus();
41-
} else {
42-
availableOptions[currentIndex + 1]?.focus();
42+
if (
43+
e.key === 'ArrowDown' ||
44+
e.key === 'ArrowUp' ||
45+
e.key === 'Home' ||
46+
e.key === 'End' ||
47+
e.key === ' '
48+
) {
49+
e.preventDefault();
4350
}
44-
}
4551

46-
if (e.key === 'ArrowUp') {
47-
if (currentIndex <= 0) {
48-
availableOptions[availableOptions.length - 1]?.focus();
49-
} else {
50-
availableOptions[currentIndex - 1]?.focus();
52+
if (e.key === 'ArrowDown') {
53+
if (currentIndex === availableOptions.length - 1) {
54+
availableOptions[0]?.focus();
55+
} else {
56+
availableOptions[currentIndex + 1]?.focus();
57+
}
58+
}
59+
60+
if (e.key === 'ArrowUp') {
61+
if (currentIndex <= 0) {
62+
availableOptions[availableOptions.length - 1]?.focus();
63+
} else {
64+
availableOptions[currentIndex - 1]?.focus();
65+
}
5166
}
52-
}
5367

54-
clearTimeout(prevTimeoutSignal.value);
68+
clearTimeout(prevTimeoutSignal.value);
5569

56-
prevTimeoutSignal.value = setTimeout(() => {
57-
inputStrgSignal.value = '';
58-
}, 500);
70+
prevTimeoutSignal.value = setTimeout(() => {
71+
inputStrgSignal.value = '';
72+
}, 500);
5973

60-
const searchFirstCharOnly =
61-
inputStrgSignal.value.length < 1 || fullStrgSearchFailedSignal.value;
62-
if (searchFirstCharOnly) {
63-
const charOptions: Readonly<string[]> = availableOptions.map((e) => {
64-
return e.textContent!.slice(0, 1).toLowerCase();
65-
});
66-
const currentChar = e.key.toLowerCase();
67-
if (!fullStrgSearchFailedSignal.value) {
68-
inputStrgSignal.value += currentChar;
69-
}
70-
const charIndex = charOptions.indexOf(currentChar);
71-
if (charIndex !== -1) {
72-
if (indexDiffSignal.value === undefined) {
73-
availableOptions[charIndex].focus();
74-
indexDiffSignal.value = charIndex + 1;
75-
} else {
76-
const isRepeat = charOptions[indexDiffSignal.value - 1] === currentChar;
77-
if (isRepeat) {
78-
const nextChars = charOptions.slice(indexDiffSignal.value);
79-
const repeatIndex = nextChars.indexOf(currentChar);
80-
if (repeatIndex !== -1) {
81-
const nextIndex = repeatIndex + indexDiffSignal.value;
82-
availableOptions[nextIndex].focus();
83-
indexDiffSignal.value = nextIndex + 1;
74+
const searchFirstCharOnly =
75+
inputStrgSignal.value.length < 1 || fullStrgSearchFailedSignal.value;
76+
if (searchFirstCharOnly) {
77+
const charOptions: Readonly<string[]> = availableOptions.map((e) => {
78+
return e.textContent!.slice(0, 1).toLowerCase();
79+
});
80+
const currentChar = e.key.toLowerCase();
81+
if (!fullStrgSearchFailedSignal.value) {
82+
inputStrgSignal.value += currentChar;
83+
}
84+
const charIndex = charOptions.indexOf(currentChar);
85+
if (charIndex !== -1) {
86+
if (indexDiffSignal.value === undefined) {
87+
availableOptions[charIndex].focus();
88+
indexDiffSignal.value = charIndex + 1;
89+
} else {
90+
const isRepeat = charOptions[indexDiffSignal.value - 1] === currentChar;
91+
if (isRepeat) {
92+
const nextChars = charOptions.slice(indexDiffSignal.value);
93+
const repeatIndex = nextChars.indexOf(currentChar);
94+
if (repeatIndex !== -1) {
95+
const nextIndex = repeatIndex + indexDiffSignal.value;
96+
availableOptions[nextIndex].focus();
97+
indexDiffSignal.value = nextIndex + 1;
98+
} else {
99+
availableOptions[charIndex].focus();
100+
indexDiffSignal.value = charIndex + 1;
101+
}
84102
} else {
85103
availableOptions[charIndex].focus();
104+
// bc char has changed, user is typing a new strg
105+
fullStrgSearchFailedSignal.value = false;
86106
indexDiffSignal.value = charIndex + 1;
87107
}
88-
} else {
89-
availableOptions[charIndex].focus();
90-
// bc char has changed, user is typing a new strg
91-
fullStrgSearchFailedSignal.value = false;
92-
indexDiffSignal.value = charIndex + 1;
93108
}
94109
}
95-
}
96-
} else {
97-
const strgOptions: Readonly<string[]> = availableOptions.map((e) => {
98-
return e.textContent!.toLowerCase();
99-
});
100-
const searchStrg = inputStrgSignal.value + e.key.toLowerCase();
101-
const firstPossibleOptIndex = strgOptions.findIndex((e) => {
102-
const size = searchStrg.length;
103-
return e.substring(0, size) === searchStrg;
104-
});
105-
if (firstPossibleOptIndex !== -1) {
106-
availableOptions[firstPossibleOptIndex].focus();
107-
inputStrgSignal.value = searchStrg;
108-
indexDiffSignal.value = firstPossibleOptIndex + 1;
109110
} else {
110-
clearTimeout(prevTimeoutSignal.value);
111-
fullStrgSearchFailedSignal.value = true;
111+
const strgOptions: Readonly<string[]> = availableOptions.map((e) => {
112+
return e.textContent!.toLowerCase();
113+
});
114+
const searchStrg = inputStrgSignal.value + e.key.toLowerCase();
115+
const firstPossibleOptIndex = strgOptions.findIndex((e) => {
116+
const size = searchStrg.length;
117+
return e.substring(0, size) === searchStrg;
118+
});
119+
if (firstPossibleOptIndex !== -1) {
120+
availableOptions[firstPossibleOptIndex].focus();
121+
inputStrgSignal.value = searchStrg;
122+
indexDiffSignal.value = firstPossibleOptIndex + 1;
123+
} else {
124+
clearTimeout(prevTimeoutSignal.value);
125+
fullStrgSearchFailedSignal.value = true;
126+
}
112127
}
113-
}
114-
}
115-
context.listboxRef.value?.addEventListener('keydown', keyHandler);
116-
cleanup(() => {
117-
context.listboxRef.value?.removeEventListener('keydown', keyHandler);
118-
});
119-
});
120-
121-
return (
122-
<ul
123-
ref={context.listboxRef}
124-
role="listbox"
125-
tabIndex={0}
126-
hidden={!context.isListboxHiddenSig.value}
127-
style={`
128-
display: ${context.isOpenSig.value ? 'block' : 'none'};
129-
position: absolute;
130-
z-index: 1;
131-
${props.style}
132-
`}
133-
class={props.class}
128+
}}
134129
>
135130
<Slot />
136131
</ul>

0 commit comments

Comments
 (0)