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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import PencilOffIcon from '../../icons/ic-pencil-off.svg';
|
||||
import PlainTextIcon from '../../icons/ic-text-paragraph.svg';
|
||||
import RichTextIcon from '../../icons/ic-text-rich.svg';
|
||||
import TrashIcon from '../../icons/ic-trash.svg';
|
||||
import PinIcon from '../../icons/ic-pin.svg';
|
||||
@@ -13,6 +14,12 @@ import PasswordIcon from '../../icons/ic-textbox-password.svg';
|
||||
import TrashSweepIcon from '../../icons/ic-trash-sweep.svg';
|
||||
import MoreIcon from '../../icons/ic-more.svg';
|
||||
import TuneIcon from '../../icons/ic-tune.svg';
|
||||
import MenuArrowDownIcon from '../../icons/ic-menu-arrow-down.svg';
|
||||
import AuthenticatorIcon from '../../icons/ic-authenticator.svg';
|
||||
import SpreadsheetsIcon from '../../icons/ic-spreadsheets.svg';
|
||||
import TasksIcon from '../../icons/ic-tasks.svg';
|
||||
import MarkdownIcon from '../../icons/ic-markdown.svg';
|
||||
import CodeIcon from '../../icons/ic-code.svg';
|
||||
|
||||
import AccessibilityIcon from '../../icons/ic-accessibility.svg';
|
||||
import HelpIcon from '../../icons/ic-help.svg';
|
||||
@@ -35,7 +42,13 @@ import { FunctionalComponent } from 'preact';
|
||||
|
||||
const ICONS = {
|
||||
'pencil-off': PencilOffIcon,
|
||||
'plain-text': PlainTextIcon,
|
||||
'rich-text': RichTextIcon,
|
||||
code: CodeIcon,
|
||||
markdown: MarkdownIcon,
|
||||
authenticator: AuthenticatorIcon,
|
||||
spreadsheets: SpreadsheetsIcon,
|
||||
tasks: TasksIcon,
|
||||
trash: TrashIcon,
|
||||
pin: PinIcon,
|
||||
unpin: UnpinIcon,
|
||||
@@ -64,6 +77,7 @@ const ICONS = {
|
||||
check: CheckIcon,
|
||||
'check-bold': CheckBoldIcon,
|
||||
'account-circle': AccountCircleIcon,
|
||||
'menu-arrow-down': MenuArrowDownIcon,
|
||||
};
|
||||
|
||||
export type IconType = keyof typeof ICONS;
|
||||
|
||||
Reference in New Issue
Block a user