Skip to content

Commit 595186b

Browse files
authored
Merge pull request #254 from psychlone77/dropdown-css
Improve Language Selector dropdowns
2 parents 9924f4d + 26c6091 commit 595186b

File tree

3 files changed

+101
-63
lines changed

3 files changed

+101
-63
lines changed

src/components/LanguageSelector.tsx

+42-40
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,13 @@ const LanguageSelector = () => {
152152

153153
useEffect(() => {
154154
if (isOpen && focusedIndex >= 0) {
155-
const element = document.querySelector(
156-
`.selector__item:nth-child(${focusedIndex + 1})`
157-
) as HTMLElement;
155+
const elements = Array.from(
156+
document.querySelectorAll(".selector__item")
157+
) as HTMLElement[];
158+
const focusableElements = elements.filter(
159+
(el) => el.getAttribute("tabIndex") !== "-1"
160+
);
161+
const element = focusableElements[focusedIndex];
158162
element?.focus();
159163
}
160164
}, [isOpen, focusedIndex]);
@@ -186,43 +190,41 @@ const LanguageSelector = () => {
186190
</div>
187191
<span className="selector__arrow" />
188192
</button>
189-
{isOpen && (
190-
<ul
191-
className="selector__dropdown"
192-
role="listbox"
193-
onKeyDown={handleKeyDown}
194-
tabIndex={-1}
195-
>
196-
{fetchedLanguages.map((lang, index) =>
197-
lang.subLanguages.length > 0 ? (
198-
<SubLanguageSelector
199-
key={lang.name}
200-
opened={openedLanguages.includes(lang)}
201-
parentLanguage={lang}
202-
onDropdownToggle={handleToggleSubLanguage}
203-
handleParentSelect={handleSelect}
204-
afterSelect={afterSelect}
205-
/>
206-
) : (
207-
<li
208-
key={lang.name}
209-
role="option"
210-
tabIndex={-1}
211-
onClick={() => handleSelect(lang)}
212-
className={`selector__item ${
213-
language.name === lang.name ? "selected" : ""
214-
} ${focusedIndex === index ? "focused" : ""}`}
215-
aria-selected={language.name === lang.name}
216-
>
217-
<label>
218-
<img src={lang.icon} alt="" />
219-
<span>{lang.name}</span>
220-
</label>
221-
</li>
222-
)
223-
)}
224-
</ul>
225-
)}
193+
<ul
194+
className={`selector__dropdown ${isOpen ? "" : " hidden"}`}
195+
role="listbox"
196+
onKeyDown={handleKeyDown}
197+
tabIndex={0}
198+
>
199+
{fetchedLanguages.map((lang, index) =>
200+
lang.subLanguages.length > 0 ? (
201+
<SubLanguageSelector
202+
key={lang.name}
203+
opened={openedLanguages.includes(lang)}
204+
parentLanguage={lang}
205+
onDropdownToggle={handleToggleSubLanguage}
206+
handleParentSelect={handleSelect}
207+
afterSelect={afterSelect}
208+
/>
209+
) : (
210+
<li
211+
key={lang.name}
212+
role="option"
213+
tabIndex={0}
214+
onClick={() => handleSelect(lang)}
215+
className={`selector__item ${
216+
language.name === lang.name ? "selected" : ""
217+
} ${focusedIndex === index ? "focused" : ""}`}
218+
aria-selected={language.name === lang.name}
219+
>
220+
<label>
221+
<img src={lang.icon} alt="" />
222+
<span>{lang.name}</span>
223+
</label>
224+
</li>
225+
)
226+
)}
227+
</ul>
226228
</div>
227229
);
228230
};

src/components/SubLanguageSelector.tsx

+19-19
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const SubLanguageSelector = ({
4747
<>
4848
<li
4949
role="option"
50-
tabIndex={-1}
50+
tabIndex={0}
5151
className={`selector__item ${
5252
subLanguage === defaultSlugifiedSubLanguageName &&
5353
language.name === parentLanguage.name
@@ -78,24 +78,24 @@ const SubLanguageSelector = ({
7878
</label>
7979
</li>
8080

81-
{opened &&
82-
parentLanguage.subLanguages.map((sl) => (
83-
<li
84-
key={sl.name}
85-
role="option"
86-
tabIndex={-1}
87-
className={`selector__item sublanguage__item ${
88-
slugify(subLanguage) === slugify(sl.name) ? "selected" : ""
89-
}`}
90-
aria-selected={slugify(subLanguage) === slugify(sl.name)}
91-
onClick={handleSubLanguageSelect(sl)}
92-
>
93-
<label>
94-
<img src={sl.icon} alt={sl.name} />
95-
<span>{sl.name}</span>
96-
</label>
97-
</li>
98-
))}
81+
{parentLanguage.subLanguages.map((sl) => (
82+
<li
83+
key={sl.name}
84+
role="option"
85+
tabIndex={opened ? 0 : -1}
86+
aria-disabled={!opened}
87+
className={`selector__item sublanguage__item ${opened ? "" : "hidden"} ${
88+
slugify(subLanguage) === slugify(sl.name) ? "selected" : ""
89+
}`}
90+
aria-selected={slugify(subLanguage) === slugify(sl.name)}
91+
onClick={handleSubLanguageSelect(sl)}
92+
>
93+
<label>
94+
<img src={sl.icon} alt={sl.name} />
95+
<span>{sl.name}</span>
96+
</label>
97+
</li>
98+
))}
9999
</>
100100
);
101101
};

src/styles/main.css

+40-4
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ abbr {
401401
border-left: 7px solid transparent;
402402
border-right: 7px solid transparent;
403403
border-top: 7px solid var(--clr-text-primary); /* [1] */
404-
transition: transform 100ms ease;
404+
transition: transform 300ms ease;
405405
}
406406

407407
.selector--open .selector__arrow {
@@ -414,7 +414,7 @@ abbr {
414414

415415
position: absolute;
416416
width: 100%;
417-
max-height: 20rem;
417+
height: 50vh;
418418
overflow-y: auto;
419419

420420
background-color: var(--clr-bg-secondary);
@@ -427,10 +427,28 @@ abbr {
427427

428428
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
429429
z-index: 1;
430+
transition: all 300ms ease;
430431
}
431432

432-
.selector__dropdown:focus-within {
433-
border-color: var(--clr-accent);
433+
.selector__dropdown.hidden {
434+
border: none;
435+
padding: 0;
436+
height: 0;
437+
opacity: 0;
438+
overflow: hidden;
439+
}
440+
441+
.selector__dropdown::-webkit-scrollbar {
442+
width: 8px;
443+
}
444+
445+
.selector__dropdown::-webkit-scrollbar-thumb {
446+
background: var(--scrollbar-thumb);
447+
border-radius: 4px;
448+
}
449+
450+
.selector__dropdown::-webkit-scrollbar-thumb:hover {
451+
background: var(--scrollbar-thumb);
434452
}
435453

436454
.selector__item {
@@ -440,10 +458,19 @@ abbr {
440458
gap: 1rem;
441459
align-items: center;
442460
border-radius: var(--br-md);
461+
transition: all 300ms ease;
443462
}
444463

445464
.sublanguage__item {
465+
height: 3rem;
446466
margin-left: 1.5rem;
467+
transition: all 300ms ease;
468+
}
469+
470+
.sublanguage__item.hidden {
471+
height: 0;
472+
opacity: 0;
473+
overflow: hidden;
447474
}
448475

449476
.sublanguage__button {
@@ -463,6 +490,11 @@ abbr {
463490
transform: rotate(-90deg);
464491
transition: transform 100ms ease;
465492
cursor: pointer;
493+
transition: all 200ms ease;
494+
}
495+
496+
.sublanguage__arrow:hover {
497+
border-top-color: var(--clr-accent);
466498
}
467499

468500
[aria-expanded="true"] .sublanguage__arrow {
@@ -473,6 +505,10 @@ abbr {
473505
border-top-color: var(--clr-text-tertiary);
474506
}
475507

508+
.selector__item.selected .sublanguage__arrow:hover {
509+
border-top-color: var(--clr-text-primary);
510+
}
511+
476512
.selector__item label {
477513
width: 100%;
478514
padding: 0.25em 0.75em;

0 commit comments

Comments
 (0)