Improve dropdown component

This commit is contained in:
Arnaud 2024-08-28 10:03:09 +02:00
parent 3c314b455d
commit b325e249a3
No known key found for this signature in database
GPG Key ID: 69D6CE281FCAE663
2 changed files with 73 additions and 37 deletions

View File

@ -1,4 +1,10 @@
import { ChangeEvent, ComponentType, useState } from "react"; import {
ChangeEvent,
ComponentType,
useState,
KeyboardEvent,
useRef,
} from "react";
import "./dropdown.css"; import "./dropdown.css";
import { attributes } from "../utils/attributes"; import { attributes } from "../utils/attributes";
import { Backdrop } from "../Backdrop/Backdrop"; import { Backdrop } from "../Backdrop/Backdrop";
@ -67,12 +73,20 @@ type Props = {
* --codex-dropdown-option-background-hover * --codex-dropdown-option-background-hover
*/ */
style?: CustomStyleCSS; style?: CustomStyleCSS;
label: string;
id: string;
Component?: ComponentType<DropdownOption>;
}; };
export function Dropdown({ export function Dropdown({
placeholder, placeholder,
style, style,
options, options,
label,
id,
onMouseEnter, onMouseEnter,
onMouseLeave, onMouseLeave,
onFocus, onFocus,
@ -82,6 +96,7 @@ export function Dropdown({
value = "", value = "",
className = "", className = "",
}: Props) { }: Props) {
const inputRef = useRef<HTMLInputElement>(null);
const lower = value.toLocaleLowerCase(); const lower = value.toLocaleLowerCase();
const filtered = options.filter( const filtered = options.filter(
(o) => (o) =>
@ -105,48 +120,63 @@ export function Dropdown({
setFocused(false); setFocused(false);
}; };
const onKeyUp = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Escape") {
onClose();
inputRef.current?.blur();
}
};
const onClose = () => setFocused(false); const onClose = () => setFocused(false);
const attr = attributes({ "aria-expanded": focused }); const attr = attributes({ "aria-expanded": focused });
return ( return (
<div className={`dropdown ${className}`} style={style}> <>
<Backdrop onClose={onClose} open={focused} /> <label className="dropdown-label" htmlFor={id}>
{label}
</label>
<Input <div className={`dropdown ${className}`} style={style}>
className="dropdown-input" <Backdrop onClose={onClose} open={focused} />
onChange={onChange}
onFocus={onInternalFocus}
onBlur={onInternalBlur}
placeholder={placeholder}
value={value}
label={""}
id={""}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
/>
<div className="dropdown-panel" {...attr}> <Input
{filtered.length ? ( ref={inputRef}
filtered.map((o) => ( className="dropdown-input"
<div onChange={onChange}
className="dropdown-option" onFocus={onInternalFocus}
onClick={() => onSelect(o)} onBlur={onInternalBlur}
key={o.title} onKeyUp={onKeyUp}
> onMouseEnter={onMouseEnter}
{o.Icon && <o.Icon />} onMouseLeave={onMouseLeave}
<div> placeholder={placeholder}
<span className="dropdown-title">{o.title}</span> value={value}
{o.subtitle && ( label={""}
<span className="dropdown-subtitle">{o.subtitle}</span> id={id}
)} />
<div className="dropdown-panel" {...attr}>
{filtered.length ? (
filtered.map((o) => (
<div
className="dropdown-option"
onClick={() => onSelect(o)}
key={o.title}
>
{o.Icon && <o.Icon />}
<div>
<span className="dropdown-title">{o.title}</span>
{o.subtitle && (
<span className="dropdown-subtitle">{o.subtitle}</span>
)}
</div>
</div> </div>
</div> ))
)) ) : (
) : ( <p className="dropdown-noResults">No results found</p>
<p className="dropdown-noResults">No results found</p> )}
)} </div>
</div> </div>
</div> </>
); );
} }

View File

@ -24,11 +24,17 @@
z-index: -1; z-index: -1;
} }
.dropdown-label {
margin-bottom: 0.5rem;
font-weight: 500;
display: block;
color: var(--codex-color);
}
.dropdown-panel[aria-expanded] { .dropdown-panel[aria-expanded] {
z-index: 2;
transform: translateY(0.5rem); transform: translateY(0.5rem);
opacity: 1; opacity: 1;
z-index: 2; z-index: 10;
} }
.dropdown-input { .dropdown-input {