feat: Dropdown component
feat: Add editor icons feat: Implement default editor selection
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
import { Listbox, ListboxOption } from '@reach/listbox';
|
||||
import {
|
||||
ListboxArrow,
|
||||
ListboxButton,
|
||||
ListboxInput,
|
||||
ListboxList,
|
||||
ListboxOption,
|
||||
ListboxPopover,
|
||||
} from '@reach/listbox';
|
||||
import VisuallyHidden from '@reach/visually-hidden';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { IconType } from './Icon';
|
||||
import { IconType, Icon } from './Icon';
|
||||
import '@reach/listbox/styles.css';
|
||||
import { useState } from 'preact/hooks';
|
||||
|
||||
@@ -11,35 +18,85 @@ export type DropdownItem = {
|
||||
value: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
type DropdownProps = {
|
||||
id: string;
|
||||
srLabel: string;
|
||||
items: DropdownItem[];
|
||||
defaultValue: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export const Dropdown: FunctionComponent<Props> = ({
|
||||
type ListboxButtonProps = {
|
||||
value: string | null;
|
||||
label: string;
|
||||
isExpanded: boolean;
|
||||
};
|
||||
|
||||
const customDropdownButton: FunctionComponent<ListboxButtonProps> = ({
|
||||
label,
|
||||
isExpanded,
|
||||
}) => (
|
||||
<>
|
||||
<div className="dropdown-selected-label">{label}</div>
|
||||
<ListboxArrow
|
||||
className={`sn-dropdown-arrow ${
|
||||
isExpanded ? 'dropdown-arrow-rotated' : ''
|
||||
}`}
|
||||
>
|
||||
<Icon type="menu-arrow-down" className="sn-icon--small color-grey-1" />
|
||||
</ListboxArrow>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Dropdown: FunctionComponent<DropdownProps> = ({
|
||||
id,
|
||||
srLabel,
|
||||
items,
|
||||
defaultValue,
|
||||
onChange,
|
||||
}) => {
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
|
||||
const labelId = `${id}-label`;
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
setValue(value);
|
||||
onChange(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<VisuallyHidden id={labelId}>{srLabel}</VisuallyHidden>
|
||||
<Listbox
|
||||
<ListboxInput
|
||||
value={value}
|
||||
onChange={(value) => setValue(value)}
|
||||
onChange={handleChange}
|
||||
aria-labelledby={labelId}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<ListboxOption value={item.value}>{item.label}</ListboxOption>
|
||||
))}
|
||||
</Listbox>
|
||||
<ListboxButton
|
||||
className="sn-dropdown-button"
|
||||
children={customDropdownButton}
|
||||
/>
|
||||
<ListboxPopover className="sn-dropdown sn-dropdown-popover">
|
||||
<div className="sn-component">
|
||||
<ListboxList>
|
||||
{items.map((item) => (
|
||||
<ListboxOption
|
||||
className="sn-dropdown-item"
|
||||
value={item.value}
|
||||
label={item.label}
|
||||
>
|
||||
{item.icon ? (
|
||||
<div className="flex mr-3">
|
||||
<Icon type={item.icon} className="sn-icon--small" />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="text-input">{item.label}</div>
|
||||
</ListboxOption>
|
||||
))}
|
||||
</ListboxList>
|
||||
</div>
|
||||
</ListboxPopover>
|
||||
</ListboxInput>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user