Skip to content

Commit

Permalink
Improve SelectNext props API
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya committed Oct 4, 2023
1 parent 386df2a commit 839f9ee
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 22 deletions.
24 changes: 18 additions & 6 deletions src/components/input/SelectNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,26 +110,37 @@ function useShouldDropUp(
export type SelectProps<T> = PresentationalProps & {
value: T;
onChange: (newValue: T) => void;
label: ComponentChildren;
buttonContent?: ComponentChildren;
disabled?: boolean;

/**
* Propagated as `id` attributed for the toggle button.
* A random one is generated by default
*/
buttonId?: string;

/** @deprecated Use buttonContent instead */
label?: ComponentChildren;
};

function SelectMain<T>({
buttonContent,
label,
value,
onChange,
children,
disabled,
classes,
elementRef,
classes,
buttonId,
}: SelectProps<T>) {
const [listboxOpen, setListboxOpen] = useState(false);
const closeListbox = useCallback(() => setListboxOpen(false), []);
const wrapperRef = useRef<HTMLDivElement | null>(null);
const listboxRef = useRef<HTMLDivElement | null>(null);
const listboxId = useId();
const buttonRef = useSyncedRef(elementRef);
const buttonId = useId();
const defaultButtonId = useId();
const shouldListboxDropUp = useShouldDropUp(
buttonRef,
listboxRef,
Expand Down Expand Up @@ -168,7 +179,7 @@ function SelectMain<T>({
return (
<div className="relative" ref={wrapperRef}>
<Button
id={buttonId}
id={buttonId ?? defaultButtonId}
variant="custom"
classes={classnames(
'w-full flex border rounded',
Expand All @@ -183,12 +194,13 @@ function SelectMain<T>({
onClick={() => setListboxOpen(prev => !prev)}
onKeyDown={e => {
if (e.key === 'ArrowDown' && !listboxOpen) {
e.preventDefault();
setListboxOpen(true);
}
}}
data-testid="select-toggle-button"
>
{label}
{buttonContent ?? label}
<div className="grow" />
<div className="text-grey-6">
{listboxOpen ? <MenuCollapseIcon /> : <MenuExpandIcon />}
Expand All @@ -212,7 +224,7 @@ function SelectMain<T>({
role="listbox"
ref={listboxRef}
id={listboxId}
aria-labelledby={buttonId}
aria-labelledby={buttonId ?? defaultButtonId}
aria-orientation="vertical"
data-testid="select-listbox"
>
Expand Down
6 changes: 3 additions & 3 deletions src/components/input/test/SelectNext-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('SelectNext', () => {
document.body.append(container);

const wrapper = mount(
<SelectNext value={undefined} onChange={sinon.stub()} label="" {...props}>
<SelectNext value={undefined} onChange={sinon.stub()} {...props}>
{items.map(item => (
<SelectNext.Option
value={item}
Expand Down Expand Up @@ -225,12 +225,12 @@ describe('SelectNext', () => {
checkAccessibility([
{
name: 'Closed Select listbox',
content: () => createComponent({ label: 'Select' }),
content: () => createComponent({ buttonContent: 'Select' }),
},
{
name: 'Open Select listbox',
content: () => {
const wrapper = createComponent({ label: 'Select' });
const wrapper = createComponent({ buttonContent: 'Select' });
toggleListbox(wrapper);

return wrapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCallback, useMemo, useState } from 'preact/hooks';

import { ArrowLeftIcon, ArrowRightIcon } from '../../../../components/icons';
import { IconButton, InputGroup } from '../../../../components/input';
import Select from '../../../../components/input/SelectNext';
import SelectNext from '../../../../components/input/SelectNext';
import Library from '../../Library';

const defaultItems = [
Expand All @@ -26,10 +26,10 @@ function SelectExample({
const [value, setValue] = useState<(typeof items)[number]>();

return (
<Select
<SelectNext
value={value}
onChange={setValue}
label={
buttonContent={
value ? (
<>
{value.name}
Expand All @@ -48,7 +48,7 @@ function SelectExample({
disabled={disabled}
>
{items.map(item => (
<Select.Option value={item} key={item.id}>
<SelectNext.Option value={item} key={item.id}>
{() =>
textOnly ? (
<>{item.name}</>
Expand All @@ -62,9 +62,9 @@ function SelectExample({
</>
)
}
</Select.Option>
</SelectNext.Option>
))}
</Select>
</SelectNext>
);
}

Expand Down Expand Up @@ -93,10 +93,10 @@ function InputGroupSelectExample() {
disabled={selectedIndex <= 0}
/>
<div className="w-full">
<Select
<SelectNext
value={selected}
onChange={setSelected}
label={
buttonContent={
selected ? (
<>
{selected.name}
Expand All @@ -110,7 +110,7 @@ function InputGroupSelectExample() {
}
>
{defaultItems.map(item => (
<Select.Option value={item} key={item.id}>
<SelectNext.Option value={item} key={item.id}>
{() => (
<>
{item.name}
Expand All @@ -122,9 +122,9 @@ function InputGroupSelectExample() {
</div>
</>
)}
</Select.Option>
</SelectNext.Option>
))}
</Select>
</SelectNext>
</div>
<IconButton
icon={ArrowRightIcon}
Expand Down Expand Up @@ -230,7 +230,7 @@ export default function SelectNextPage() {
<Library.Link href="/using-components#presentational-components-api">
presentational component props
</Library.Link>
<Library.Example title="label">
<Library.Example title="buttonContent">
<Library.Info>
<Library.InfoItem label="description">
The content to be displayed in the toggle button.
Expand Down Expand Up @@ -273,6 +273,19 @@ export default function SelectNextPage() {
</Library.InfoItem>
</Library.Info>
</Library.Example>
<Library.Example title="buttonId">
<Library.Info>
<Library.InfoItem label="description">
The toggle button{"'"}s <code>id</code>.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>string</code>
</Library.InfoItem>
<Library.InfoItem label="default">
<code>undefined</code>
</Library.InfoItem>
</Library.Info>
</Library.Example>
</Library.Pattern>

<Library.Pattern title="How to use it">
Expand All @@ -288,7 +301,7 @@ export default function SelectNextPage() {
<SelectNext
value={value}
onChange={setSelected}
label={
buttonContent={
value ? (
<>
{value.name}
Expand Down

0 comments on commit 839f9ee

Please sign in to comment.